Implement part uv preview

master
Jeremy HU 2022-10-23 14:14:30 +11:00
parent b0000e7a34
commit 0f44d5cf7b
14 changed files with 106 additions and 24 deletions

View File

@ -122,9 +122,9 @@ void main()
float NoV = abs(dot(n, v)) + 1e-5; float NoV = abs(dot(n, v)) + 1e-5;
vec3 irradiance = texturesAsCube(environmentIrradianceMapId, r).rgb; 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 fresnelFactor = fresnelSchlickRoughness(NoV, f0, roughness);
vec3 specular = fresnelFactor * texturesAsCube(environmentSpecularMapId, r).rgb; vec3 specular = fresnelFactor * texturesAsCube(environmentSpecularMapId, r).rgb;

View File

@ -61,9 +61,9 @@ void main()
float NoV = abs(dot(n, v)) + 1e-5; float NoV = abs(dot(n, v)) + 1e-5;
vec3 irradiance = texture(environmentIrradianceMapId, r).rgb; 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 fresnelFactor = fresnelSchlickRoughness(NoV, f0, roughness);
vec3 specular = fresnelFactor * texture(environmentSpecularMapId, r, 0.0).rgb; vec3 specular = fresnelFactor * texture(environmentSpecularMapId, r, 0.0).rgb;

View File

@ -923,8 +923,11 @@ void Document::setPartColorImage(const dust3d::Uuid& partId, const dust3d::Uuid&
return; return;
part->second.colorImageId = imageId; part->second.colorImageId = imageId;
part->second.dirty = true; part->second.dirty = true;
auto component = componentMap.find(part->second.componentId);
if (component != componentMap.end())
component->second.isPreviewMeshObsolete = true;
emit partColorImageChanged(partId); emit partColorImageChanged(partId);
emit optionsChanged(); emit textureChanged();
} }
void Document::collectComponentDescendantParts(dust3d::Uuid componentId, std::vector<dust3d::Uuid>& partIds) const void Document::collectComponentDescendantParts(dust3d::Uuid componentId, std::vector<dust3d::Uuid>& partIds) const

View File

@ -202,9 +202,8 @@ DocumentWindow::DocumentWindow()
m_isLastMeshGenerationSucceed = m_document->isMeshGenerationSucceed(); m_isLastMeshGenerationSucceed = m_document->isMeshGenerationSucceed();
updateInprogressIndicator(); updateInprogressIndicator();
}); });
connect(m_document, &Document::resultComponentPreviewMeshesChanged, this, [=]() { connect(m_document, &Document::resultComponentPreviewMeshesChanged, this, &DocumentWindow::generateComponentPreviewImages);
generateComponentPreviewImages(); connect(m_document, &Document::textureChanged, this, &DocumentWindow::generateComponentPreviewImages);
});
connect(m_document, &Document::postProcessing, this, &DocumentWindow::updateInprogressIndicator); connect(m_document, &Document::postProcessing, this, &DocumentWindow::updateInprogressIndicator);
connect(m_document, &Document::textureGenerating, this, &DocumentWindow::updateInprogressIndicator); connect(m_document, &Document::textureGenerating, this, &DocumentWindow::updateInprogressIndicator);
connect(m_document, &Document::resultTextureChanged, this, &DocumentWindow::updateInprogressIndicator); connect(m_document, &Document::resultTextureChanged, this, &DocumentWindow::updateInprogressIndicator);
@ -1187,7 +1186,19 @@ void DocumentWindow::generateComponentPreviewImages()
if (!component.second.isPreviewMeshObsolete) if (!component.second.isPreviewMeshObsolete)
continue; continue;
component.second.isPreviewMeshObsolete = false; component.second.isPreviewMeshObsolete = false;
m_componentPreviewImagesGenerator->addInput(component.first, std::unique_ptr<ModelMesh>(component.second.takePreviewMesh())); auto previewMesh = std::unique_ptr<ModelMesh>(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); m_componentPreviewImagesGenerator->moveToThread(thread);
connect(thread, &QThread::started, m_componentPreviewImagesGenerator, &MeshPreviewImagesGenerator::process); connect(thread, &QThread::started, m_componentPreviewImagesGenerator, &MeshPreviewImagesGenerator::process);

View File

@ -40,6 +40,19 @@ void MeshGenerator::process()
auto it = m_generatedComponentPreviews.find(componentId); auto it = m_generatedComponentPreviews.find(componentId);
if (it == m_generatedComponentPreviews.end()) if (it == m_generatedComponentPreviews.end())
continue; continue;
std::vector<std::array<dust3d::Vector2, 3>> 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); dust3d::trimVertices(&it->second.vertices, true);
for (auto& it : it->second.vertices) { for (auto& it : it->second.vertices) {
it *= 2.0; it *= 2.0;
@ -64,7 +77,8 @@ void MeshGenerator::process()
it->second.color, it->second.color,
it->second.metalness, it->second.metalness,
it->second.roughness, 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) if (nullptr != m_object)

View File

@ -73,12 +73,17 @@ ModelMesh::ModelMesh(const std::vector<dust3d::Vector3>& vertices,
const dust3d::Color& color, const dust3d::Color& color,
float metalness, float metalness,
float roughness, float roughness,
const std::vector<std::tuple<dust3d::Color, float /*metalness*/, float /*roughness*/>>* vertexProperties) const std::vector<std::tuple<dust3d::Color, float /*metalness*/, float /*roughness*/>>* vertexProperties,
const std::vector<std::array<dust3d::Vector2, 3>>* triangleUvs)
{ {
m_triangleVertexCount = (int)triangles.size() * 3; m_triangleVertexCount = (int)triangles.size() * 3;
m_triangleVertices = new ModelOpenGLVertex[m_triangleVertexCount]; m_triangleVertices = new ModelOpenGLVertex[m_triangleVertexCount];
int destIndex = 0; int destIndex = 0;
for (size_t i = 0; i < triangles.size(); ++i) { for (size_t i = 0; i < triangles.size(); ++i) {
std::array<dust3d::Vector2, 3> uvs = {};
if (nullptr != triangleUvs) {
uvs = triangleUvs->at(i);
}
for (auto j = 0; j < 3; j++) { for (auto j = 0; j < 3; j++) {
int vertexIndex = (int)triangles[i][j]; int vertexIndex = (int)triangles[i][j];
const dust3d::Vector3* srcVert = &vertices[vertexIndex]; const dust3d::Vector3* srcVert = &vertices[vertexIndex];
@ -87,8 +92,8 @@ ModelMesh::ModelMesh(const std::vector<dust3d::Vector3>& vertices,
dest->posX = srcVert->x(); dest->posX = srcVert->x();
dest->posY = srcVert->y(); dest->posY = srcVert->y();
dest->posZ = srcVert->z(); dest->posZ = srcVert->z();
dest->texU = 0; dest->texU = uvs[j][0];
dest->texV = 0; dest->texV = uvs[j][1];
dest->normX = srcNormal->x(); dest->normX = srcNormal->x();
dest->normY = srcNormal->y(); dest->normY = srcNormal->y();
dest->normZ = srcNormal->z(); dest->normZ = srcNormal->z();

View File

@ -5,9 +5,14 @@
#include <QImage> #include <QImage>
#include <QObject> #include <QObject>
#include <QTextStream> #include <QTextStream>
#include <array>
#include <dust3d/base/color.h> #include <dust3d/base/color.h>
#include <dust3d/base/object.h> #include <dust3d/base/object.h>
#include <dust3d/base/position_key.h>
#include <dust3d/base/vector2.h>
#include <dust3d/base/vector3.h> #include <dust3d/base/vector3.h>
#include <map>
#include <tuple>
#include <vector> #include <vector>
class ModelMesh { class ModelMesh {
@ -18,7 +23,8 @@ public:
const dust3d::Color& color = dust3d::Color::createWhite(), const dust3d::Color& color = dust3d::Color::createWhite(),
float metalness = 0.0, float metalness = 0.0,
float roughness = 1.0, float roughness = 1.0,
const std::vector<std::tuple<dust3d::Color, float /*metalness*/, float /*roughness*/>>* vertexProperties = nullptr); const std::vector<std::tuple<dust3d::Color, float /*metalness*/, float /*roughness*/>>* vertexProperties = nullptr,
const std::vector<std::array<dust3d::Vector2, 3>>* triangleUvs = nullptr);
ModelMesh(dust3d::Object& object); ModelMesh(dust3d::Object& object);
ModelMesh(ModelOpenGLVertex* triangleVertices, int vertexNum); ModelMesh(ModelOpenGLVertex* triangleVertices, int vertexNum);
ModelMesh(const ModelMesh& mesh); ModelMesh(const ModelMesh& mesh);

View File

@ -113,12 +113,16 @@ QImage ModelOffscreenRender::toImage(const QSize& size)
f->glEnable(GL_CULL_FACE); f->glEnable(GL_CULL_FACE);
f->glViewport(0, 0, size.width(), size.height()); f->glViewport(0, 0, size.width(), size.height());
auto colorTextureImage = std::unique_ptr<QImage>(nullptr != m_mesh ? m_mesh->takeTextureImage() : nullptr);
auto object = std::make_unique<ModelOpenGLObject>(); auto object = std::make_unique<ModelOpenGLObject>();
object->update(std::unique_ptr<ModelMesh>(m_mesh)); object->update(std::unique_ptr<ModelMesh>(m_mesh));
m_mesh = nullptr; m_mesh = nullptr;
auto program = std::make_unique<ModelOpenGLProgram>(); auto program = std::make_unique<ModelOpenGLProgram>();
program->load(m_context->format().profile() == QSurfaceFormat::CoreProfile); program->load(m_context->format().profile() == QSurfaceFormat::CoreProfile);
if (nullptr != colorTextureImage)
program->updateTextureImage(std::move(colorTextureImage));
program->bind(); program->bind();
program->bindMaps(); program->bindMaps();

View File

@ -10,9 +10,9 @@ typedef struct
GLfloat posX; GLfloat posX;
GLfloat posY; GLfloat posY;
GLfloat posZ; GLfloat posZ;
GLfloat colorR = 24.0 / 255.0; GLfloat colorR = 0.0;
GLfloat colorG = 29.0 / 255.0; GLfloat colorG = 0.0;
GLfloat colorB = 49.0 / 255.0; GLfloat colorB = 0.0;
GLfloat alpha = 1.0; GLfloat alpha = 1.0;
} MonochromeOpenGLVertex; } MonochromeOpenGLVertex;
#pragma pack(pop) #pragma pack(pop)

View File

@ -7,9 +7,15 @@ UvPreviewImageGenerator::UvPreviewImageGenerator(std::vector<std::vector<dust3d:
{ {
} }
std::unique_ptr<QImage> UvPreviewImageGenerator::takePreviewImage()
{
return std::move(m_previewImage);
}
void UvPreviewImageGenerator::generate() void UvPreviewImageGenerator::generate()
{ {
m_previewImage = std::make_unique<QImage>(m_uvImageSize, m_uvImageSize, QImage::Format_ARGB32); m_previewImage = std::make_unique<QImage>(m_uvImageSize, m_uvImageSize, QImage::Format_ARGB32);
m_previewImage->fill(Qt::white);
// TODO: // TODO:
} }

View File

@ -1,5 +1,5 @@
#ifndef DUST3D_APPLICATION_TUBE_PREVIEW_IMAGE_GENERATOR_H_ #ifndef DUST3D_APPLICATION_UV_PREVIEW_IMAGE_GENERATOR_H_
#define DUST3D_APPLICATION_TUBE_PREVIEW_IMAGE_GENERATOR_H_ #define DUST3D_APPLICATION_UV_PREVIEW_IMAGE_GENERATOR_H_
#include <QImage> #include <QImage>
#include <QObject> #include <QObject>
@ -11,6 +11,7 @@ class UvPreviewImageGenerator : public QObject {
Q_OBJECT Q_OBJECT
public: public:
UvPreviewImageGenerator(std::vector<std::vector<dust3d::Vector2>>&& faceUvs); UvPreviewImageGenerator(std::vector<std::vector<dust3d::Vector2>>&& faceUvs);
std::unique_ptr<QImage> takePreviewImage();
void generate(); void generate();
signals: signals:
void finished(); void finished();

View File

@ -683,7 +683,26 @@ std::unique_ptr<MeshCombiner::Mesh> MeshGenerator::combinePartMesh(const std::st
for (auto& it : partCache.faces) for (auto& it : partCache.faces)
std::reverse(it.begin(), it.end()); 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<MeshCombiner::Mesh> MeshGenerator::combinePartMesh(const std::st
preview.color = partCache.color; preview.color = partCache.color;
preview.metalness = partCache.metalness; preview.metalness = partCache.metalness;
preview.roughness = partCache.roughness; preview.roughness = partCache.roughness;
preview.triangleUvs = partCache.triangleUvs;
addComponentPreview(componentIdString, std::move(preview)); addComponentPreview(componentIdString, std::move(preview));
} else if (PartTarget::CutFace == target) { } else if (PartTarget::CutFace == target) {
std::unique_ptr<SectionPreviewMeshBuilder> sectionPreviewMeshBuilder; std::unique_ptr<SectionPreviewMeshBuilder> sectionPreviewMeshBuilder;

View File

@ -44,10 +44,10 @@ public:
struct GeneratedPart { struct GeneratedPart {
std::vector<Vector3> vertices; std::vector<Vector3> vertices;
std::vector<std::vector<size_t>> faces; std::vector<std::vector<size_t>> faces;
std::map<std::array<PositionKey, 3>, std::array<Vector2, 3>> triangleUvs;
std::vector<ObjectNode> objectNodes; std::vector<ObjectNode> objectNodes;
std::vector<std::pair<std::pair<Uuid, Uuid>, std::pair<Uuid, Uuid>>> objectEdges; std::vector<std::pair<std::pair<Uuid, Uuid>, std::pair<Uuid, Uuid>>> objectEdges;
std::vector<std::pair<Vector3, std::pair<Uuid, Uuid>>> objectNodeVertices; std::vector<std::pair<Vector3, std::pair<Uuid, Uuid>>> objectNodeVertices;
std::vector<std::vector<Vector2>> faceUvs;
Color color = Color(1.0, 1.0, 1.0); Color color = Color(1.0, 1.0, 1.0);
float metalness = 0.0; float metalness = 0.0;
float roughness = 1.0; float roughness = 1.0;
@ -74,6 +74,7 @@ public:
struct ComponentPreview { struct ComponentPreview {
std::vector<Vector3> vertices; std::vector<Vector3> vertices;
std::vector<std::vector<size_t>> triangles; std::vector<std::vector<size_t>> triangles;
std::map<std::array<PositionKey, 3>, std::array<Vector2, 3>> triangleUvs;
Color color = Color(1.0, 1.0, 1.0); Color color = Color(1.0, 1.0, 1.0);
float metalness = 0.0; float metalness = 0.0;
float roughness = 1.0; float roughness = 1.0;

View File

@ -21,6 +21,7 @@
*/ */
#include <algorithm> #include <algorithm>
#include <dust3d/base/debug.h>
#include <dust3d/mesh/base_normal.h> #include <dust3d/mesh/base_normal.h>
#include <dust3d/mesh/tube_mesh_builder.h> #include <dust3d/mesh/tube_mesh_builder.h>
@ -204,7 +205,8 @@ void TubeMeshBuilder::build()
// Build all vertex Uvs // Build all vertex Uvs
std::vector<std::vector<Vector2>> cutFaceVertexUvs(cutFaceVertexPositions.size()); std::vector<std::vector<Vector2>> cutFaceVertexUvs(cutFaceVertexPositions.size());
double maxOffsetU = 0.0; std::vector<double> maxUs(cutFaceVertexPositions.size(), 0.0);
std::vector<double> maxVs(cutFaceVertexPositions.front().size(), 0.0);
std::vector<double> offsetVs(cutFaceVertexPositions.front().size(), 0.0); std::vector<double> offsetVs(cutFaceVertexPositions.front().size(), 0.0);
for (size_t n = 0; n < cutFaceVertexPositions.size(); ++n) { for (size_t n = 0; n < cutFaceVertexPositions.size(); ++n) {
const auto& cutFaceVertices = cutFaceVertexPositions[n]; const auto& cutFaceVertices = cutFaceVertexPositions[n];
@ -222,7 +224,17 @@ void TubeMeshBuilder::build()
offsetU += (cutFaceVertices[j] - cutFaceVertices[i]).length(); offsetU += (cutFaceVertices[j] - cutFaceVertices[i]).length();
} }
cutFaceVertexUvs[n] = uvCoords; 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<double>::epsilon());
cutFaceVertexUvs[n][k][1] /= std::max(maxVs[k], std::numeric_limits<double>::epsilon());
//dust3dDebug << "uv[" << n << "][" << k << "]:" << cutFaceVertexUvs[n][k][0] << cutFaceVertexUvs[n][k][1];
}
} }
// Generate vertex indices // Generate vertex indices
@ -277,7 +289,6 @@ void TubeMeshBuilder::build()
m_generatedFaces.emplace_back(cutFaceIndices.front()); m_generatedFaces.emplace_back(cutFaceIndices.front());
std::reverse(m_generatedFaces.back().begin(), m_generatedFaces.back().end()); std::reverse(m_generatedFaces.back().begin(), m_generatedFaces.back().end());
// TODO: Add UV for end cap // TODO: Add UV for end cap
m_generatedFaceUvs.resize(m_generatedFaces.size());
} }
} }