From 0f44d5cf7b6bef0af7fdd0873438568550f9f615 Mon Sep 17 00:00:00 2001 From: Jeremy HU Date: Sun, 23 Oct 2022 14:14:30 +1100 Subject: [PATCH] Implement part uv preview --- application/shaders/model.frag | 4 ++-- application/shaders/model_core.frag | 4 ++-- application/sources/document.cc | 5 ++++- application/sources/document_window.cc | 19 ++++++++++++---- application/sources/mesh_generator.cc | 16 +++++++++++++- application/sources/model_mesh.cc | 11 +++++++--- application/sources/model_mesh.h | 8 ++++++- application/sources/model_offscreen_render.cc | 4 ++++ .../sources/monochrome_opengl_vertex.h | 6 ++--- .../sources/uv_preview_image_generator.cc | 6 +++++ .../sources/uv_preview_image_generator.h | 5 +++-- dust3d/mesh/mesh_generator.cc | 22 ++++++++++++++++++- dust3d/mesh/mesh_generator.h | 3 ++- dust3d/mesh/tube_mesh_builder.cc | 17 +++++++++++--- 14 files changed, 106 insertions(+), 24 deletions(-) diff --git a/application/shaders/model.frag b/application/shaders/model.frag index f2cfdb0a..830af7df 100644 --- a/application/shaders/model.frag +++ b/application/shaders/model.frag @@ -122,9 +122,9 @@ void main() float NoV = abs(dot(n, v)) + 1e-5; vec3 irradiance = texturesAsCube(environmentIrradianceMapId, r).rgb; - vec3 diffuse = irradiance * (1.0 - metalness) * pointColor; + vec3 diffuse = irradiance * (1.0 - metalness) * color; - vec3 f0 = mix(vec3(0.04), pointColor, metalness); + vec3 f0 = mix(vec3(0.04), color, metalness); vec3 fresnelFactor = fresnelSchlickRoughness(NoV, f0, roughness); vec3 specular = fresnelFactor * texturesAsCube(environmentSpecularMapId, r).rgb; diff --git a/application/shaders/model_core.frag b/application/shaders/model_core.frag index be037e22..762b718e 100644 --- a/application/shaders/model_core.frag +++ b/application/shaders/model_core.frag @@ -61,9 +61,9 @@ void main() float NoV = abs(dot(n, v)) + 1e-5; vec3 irradiance = texture(environmentIrradianceMapId, r).rgb; - vec3 diffuse = irradiance * (1.0 - metalness) * pointColor; + vec3 diffuse = irradiance * (1.0 - metalness) * color; - vec3 f0 = mix(vec3(0.04), pointColor, metalness); + vec3 f0 = mix(vec3(0.04), color, metalness); vec3 fresnelFactor = fresnelSchlickRoughness(NoV, f0, roughness); vec3 specular = fresnelFactor * texture(environmentSpecularMapId, r, 0.0).rgb; diff --git a/application/sources/document.cc b/application/sources/document.cc index d46f9089..656ed07e 100644 --- a/application/sources/document.cc +++ b/application/sources/document.cc @@ -923,8 +923,11 @@ void Document::setPartColorImage(const dust3d::Uuid& partId, const dust3d::Uuid& return; part->second.colorImageId = imageId; part->second.dirty = true; + auto component = componentMap.find(part->second.componentId); + if (component != componentMap.end()) + component->second.isPreviewMeshObsolete = true; emit partColorImageChanged(partId); - emit optionsChanged(); + emit textureChanged(); } void Document::collectComponentDescendantParts(dust3d::Uuid componentId, std::vector& partIds) const diff --git a/application/sources/document_window.cc b/application/sources/document_window.cc index 78dec2e1..96613b4b 100644 --- a/application/sources/document_window.cc +++ b/application/sources/document_window.cc @@ -202,9 +202,8 @@ DocumentWindow::DocumentWindow() m_isLastMeshGenerationSucceed = m_document->isMeshGenerationSucceed(); updateInprogressIndicator(); }); - connect(m_document, &Document::resultComponentPreviewMeshesChanged, this, [=]() { - generateComponentPreviewImages(); - }); + connect(m_document, &Document::resultComponentPreviewMeshesChanged, this, &DocumentWindow::generateComponentPreviewImages); + connect(m_document, &Document::textureChanged, this, &DocumentWindow::generateComponentPreviewImages); connect(m_document, &Document::postProcessing, this, &DocumentWindow::updateInprogressIndicator); connect(m_document, &Document::textureGenerating, this, &DocumentWindow::updateInprogressIndicator); connect(m_document, &Document::resultTextureChanged, this, &DocumentWindow::updateInprogressIndicator); @@ -1187,7 +1186,19 @@ void DocumentWindow::generateComponentPreviewImages() if (!component.second.isPreviewMeshObsolete) continue; component.second.isPreviewMeshObsolete = false; - m_componentPreviewImagesGenerator->addInput(component.first, std::unique_ptr(component.second.takePreviewMesh())); + auto previewMesh = std::unique_ptr(component.second.takePreviewMesh()); + if (!component.second.linkToPartId.isNull()) { + const auto& part = m_document->findPart(component.second.linkToPartId); + if (nullptr != part) { + if (!part->colorImageId.isNull()) { + const auto& colorImage = ImageForever::get(part->colorImageId); + if (nullptr != colorImage) { + previewMesh->setTextureImage(new QImage(*colorImage)); + } + } + } + } + m_componentPreviewImagesGenerator->addInput(component.first, std::move(previewMesh)); } m_componentPreviewImagesGenerator->moveToThread(thread); connect(thread, &QThread::started, m_componentPreviewImagesGenerator, &MeshPreviewImagesGenerator::process); diff --git a/application/sources/mesh_generator.cc b/application/sources/mesh_generator.cc index e3dbd0df..46c5cd79 100644 --- a/application/sources/mesh_generator.cc +++ b/application/sources/mesh_generator.cc @@ -40,6 +40,19 @@ void MeshGenerator::process() auto it = m_generatedComponentPreviews.find(componentId); if (it == m_generatedComponentPreviews.end()) continue; + std::vector> triangleUvs; + if (!it->second.triangleUvs.empty()) { + triangleUvs.resize(it->second.triangles.size()); + for (size_t i = 0; i < it->second.triangles.size(); ++i) { + const auto& triangle = it->second.triangles[i]; + auto findUv = it->second.triangleUvs.find({ dust3d::PositionKey(it->second.vertices[triangle[0]]), + dust3d::PositionKey(it->second.vertices[triangle[1]]), + dust3d::PositionKey(it->second.vertices[triangle[2]]) }); + if (findUv != it->second.triangleUvs.end()) { + triangleUvs[i] = findUv->second; + } + } + } dust3d::trimVertices(&it->second.vertices, true); for (auto& it : it->second.vertices) { it *= 2.0; @@ -64,7 +77,8 @@ void MeshGenerator::process() it->second.color, it->second.metalness, it->second.roughness, - it->second.vertexProperties.empty() ? nullptr : &it->second.vertexProperties); + it->second.vertexProperties.empty() ? nullptr : &it->second.vertexProperties, + triangleUvs.empty() ? nullptr : &triangleUvs); } if (nullptr != m_object) diff --git a/application/sources/model_mesh.cc b/application/sources/model_mesh.cc index a286fc22..b931e0ea 100644 --- a/application/sources/model_mesh.cc +++ b/application/sources/model_mesh.cc @@ -73,12 +73,17 @@ ModelMesh::ModelMesh(const std::vector& vertices, const dust3d::Color& color, float metalness, float roughness, - const std::vector>* vertexProperties) + const std::vector>* vertexProperties, + const std::vector>* triangleUvs) { m_triangleVertexCount = (int)triangles.size() * 3; m_triangleVertices = new ModelOpenGLVertex[m_triangleVertexCount]; int destIndex = 0; for (size_t i = 0; i < triangles.size(); ++i) { + std::array uvs = {}; + if (nullptr != triangleUvs) { + uvs = triangleUvs->at(i); + } for (auto j = 0; j < 3; j++) { int vertexIndex = (int)triangles[i][j]; const dust3d::Vector3* srcVert = &vertices[vertexIndex]; @@ -87,8 +92,8 @@ ModelMesh::ModelMesh(const std::vector& vertices, dest->posX = srcVert->x(); dest->posY = srcVert->y(); dest->posZ = srcVert->z(); - dest->texU = 0; - dest->texV = 0; + dest->texU = uvs[j][0]; + dest->texV = uvs[j][1]; dest->normX = srcNormal->x(); dest->normY = srcNormal->y(); dest->normZ = srcNormal->z(); diff --git a/application/sources/model_mesh.h b/application/sources/model_mesh.h index 97e84e0d..3160ffbf 100644 --- a/application/sources/model_mesh.h +++ b/application/sources/model_mesh.h @@ -5,9 +5,14 @@ #include #include #include +#include #include #include +#include +#include #include +#include +#include #include class ModelMesh { @@ -18,7 +23,8 @@ public: const dust3d::Color& color = dust3d::Color::createWhite(), float metalness = 0.0, float roughness = 1.0, - const std::vector>* vertexProperties = nullptr); + const std::vector>* vertexProperties = nullptr, + const std::vector>* triangleUvs = nullptr); ModelMesh(dust3d::Object& object); ModelMesh(ModelOpenGLVertex* triangleVertices, int vertexNum); ModelMesh(const ModelMesh& mesh); diff --git a/application/sources/model_offscreen_render.cc b/application/sources/model_offscreen_render.cc index 50dd27f2..9d78aa9f 100644 --- a/application/sources/model_offscreen_render.cc +++ b/application/sources/model_offscreen_render.cc @@ -113,12 +113,16 @@ QImage ModelOffscreenRender::toImage(const QSize& size) f->glEnable(GL_CULL_FACE); f->glViewport(0, 0, size.width(), size.height()); + auto colorTextureImage = std::unique_ptr(nullptr != m_mesh ? m_mesh->takeTextureImage() : nullptr); + auto object = std::make_unique(); object->update(std::unique_ptr(m_mesh)); m_mesh = nullptr; auto program = std::make_unique(); program->load(m_context->format().profile() == QSurfaceFormat::CoreProfile); + if (nullptr != colorTextureImage) + program->updateTextureImage(std::move(colorTextureImage)); program->bind(); program->bindMaps(); diff --git a/application/sources/monochrome_opengl_vertex.h b/application/sources/monochrome_opengl_vertex.h index 14cb8e6e..3bd04367 100644 --- a/application/sources/monochrome_opengl_vertex.h +++ b/application/sources/monochrome_opengl_vertex.h @@ -10,9 +10,9 @@ typedef struct GLfloat posX; GLfloat posY; GLfloat posZ; - GLfloat colorR = 24.0 / 255.0; - GLfloat colorG = 29.0 / 255.0; - GLfloat colorB = 49.0 / 255.0; + GLfloat colorR = 0.0; + GLfloat colorG = 0.0; + GLfloat colorB = 0.0; GLfloat alpha = 1.0; } MonochromeOpenGLVertex; #pragma pack(pop) diff --git a/application/sources/uv_preview_image_generator.cc b/application/sources/uv_preview_image_generator.cc index ef43c334..3160c583 100644 --- a/application/sources/uv_preview_image_generator.cc +++ b/application/sources/uv_preview_image_generator.cc @@ -7,9 +7,15 @@ UvPreviewImageGenerator::UvPreviewImageGenerator(std::vector UvPreviewImageGenerator::takePreviewImage() +{ + return std::move(m_previewImage); +} + void UvPreviewImageGenerator::generate() { m_previewImage = std::make_unique(m_uvImageSize, m_uvImageSize, QImage::Format_ARGB32); + m_previewImage->fill(Qt::white); // TODO: } diff --git a/application/sources/uv_preview_image_generator.h b/application/sources/uv_preview_image_generator.h index cef44526..5c36fd0c 100644 --- a/application/sources/uv_preview_image_generator.h +++ b/application/sources/uv_preview_image_generator.h @@ -1,5 +1,5 @@ -#ifndef DUST3D_APPLICATION_TUBE_PREVIEW_IMAGE_GENERATOR_H_ -#define DUST3D_APPLICATION_TUBE_PREVIEW_IMAGE_GENERATOR_H_ +#ifndef DUST3D_APPLICATION_UV_PREVIEW_IMAGE_GENERATOR_H_ +#define DUST3D_APPLICATION_UV_PREVIEW_IMAGE_GENERATOR_H_ #include #include @@ -11,6 +11,7 @@ class UvPreviewImageGenerator : public QObject { Q_OBJECT public: UvPreviewImageGenerator(std::vector>&& faceUvs); + std::unique_ptr takePreviewImage(); void generate(); signals: void finished(); diff --git a/dust3d/mesh/mesh_generator.cc b/dust3d/mesh/mesh_generator.cc index 2eb1b5a5..136a2aa7 100644 --- a/dust3d/mesh/mesh_generator.cc +++ b/dust3d/mesh/mesh_generator.cc @@ -683,7 +683,26 @@ std::unique_ptr MeshGenerator::combinePartMesh(const std::st for (auto& it : partCache.faces) std::reverse(it.begin(), it.end()); } - partCache.faceUvs = tubeMeshBuilder->generatedFaceUvs(); + const auto& faceUvs = tubeMeshBuilder->generatedFaceUvs(); + for (size_t i = 0; i < faceUvs.size(); ++i) { + const auto& uv = faceUvs[i]; + const auto& face = partCache.faces[i]; + if (3 == face.size()) { + partCache.triangleUvs.insert({ { PositionKey(partCache.vertices[face[0]]), + PositionKey(partCache.vertices[face[1]]), + PositionKey(partCache.vertices[face[2]]) }, + { uv[0], uv[1], uv[2] } }); + } else if (4 == face.size()) { + partCache.triangleUvs.insert({ { PositionKey(partCache.vertices[face[0]]), + PositionKey(partCache.vertices[face[1]]), + PositionKey(partCache.vertices[face[2]]) }, + { uv[0], uv[1], uv[2] } }); + partCache.triangleUvs.insert({ { PositionKey(partCache.vertices[face[2]]), + PositionKey(partCache.vertices[face[3]]), + PositionKey(partCache.vertices[face[0]]) }, + { uv[2], uv[3], uv[0] } }); + } + } } } @@ -702,6 +721,7 @@ std::unique_ptr MeshGenerator::combinePartMesh(const std::st preview.color = partCache.color; preview.metalness = partCache.metalness; preview.roughness = partCache.roughness; + preview.triangleUvs = partCache.triangleUvs; addComponentPreview(componentIdString, std::move(preview)); } else if (PartTarget::CutFace == target) { std::unique_ptr sectionPreviewMeshBuilder; diff --git a/dust3d/mesh/mesh_generator.h b/dust3d/mesh/mesh_generator.h index 9f86c6b9..ae645bd9 100644 --- a/dust3d/mesh/mesh_generator.h +++ b/dust3d/mesh/mesh_generator.h @@ -44,10 +44,10 @@ public: struct GeneratedPart { std::vector vertices; std::vector> faces; + std::map, std::array> triangleUvs; std::vector objectNodes; std::vector, std::pair>> objectEdges; std::vector>> objectNodeVertices; - std::vector> faceUvs; Color color = Color(1.0, 1.0, 1.0); float metalness = 0.0; float roughness = 1.0; @@ -74,6 +74,7 @@ public: struct ComponentPreview { std::vector vertices; std::vector> triangles; + std::map, std::array> triangleUvs; Color color = Color(1.0, 1.0, 1.0); float metalness = 0.0; float roughness = 1.0; diff --git a/dust3d/mesh/tube_mesh_builder.cc b/dust3d/mesh/tube_mesh_builder.cc index 8ae85540..6e4ed3bb 100644 --- a/dust3d/mesh/tube_mesh_builder.cc +++ b/dust3d/mesh/tube_mesh_builder.cc @@ -21,6 +21,7 @@ */ #include +#include #include #include @@ -204,7 +205,8 @@ void TubeMeshBuilder::build() // Build all vertex Uvs std::vector> cutFaceVertexUvs(cutFaceVertexPositions.size()); - double maxOffsetU = 0.0; + std::vector maxUs(cutFaceVertexPositions.size(), 0.0); + std::vector maxVs(cutFaceVertexPositions.front().size(), 0.0); std::vector offsetVs(cutFaceVertexPositions.front().size(), 0.0); for (size_t n = 0; n < cutFaceVertexPositions.size(); ++n) { const auto& cutFaceVertices = cutFaceVertexPositions[n]; @@ -222,7 +224,17 @@ void TubeMeshBuilder::build() offsetU += (cutFaceVertices[j] - cutFaceVertices[i]).length(); } cutFaceVertexUvs[n] = uvCoords; - maxOffsetU = std::max(maxOffsetU, offsetU); + maxUs[n] = offsetU; + for (size_t i = 0; i < cutFaceVertices.size(); ++i) { + maxVs[i] += offsetVs[i]; + } + } + for (size_t n = 0; n < cutFaceVertexUvs.size(); ++n) { + for (size_t k = 0; k < cutFaceVertexUvs[n].size(); ++k) { + cutFaceVertexUvs[n][k][0] /= std::max(maxUs[n], std::numeric_limits::epsilon()); + cutFaceVertexUvs[n][k][1] /= std::max(maxVs[k], std::numeric_limits::epsilon()); + //dust3dDebug << "uv[" << n << "][" << k << "]:" << cutFaceVertexUvs[n][k][0] << cutFaceVertexUvs[n][k][1]; + } } // Generate vertex indices @@ -277,7 +289,6 @@ void TubeMeshBuilder::build() m_generatedFaces.emplace_back(cutFaceIndices.front()); std::reverse(m_generatedFaces.back().begin(), m_generatedFaces.back().end()); // TODO: Add UV for end cap - m_generatedFaceUvs.resize(m_generatedFaces.size()); } }