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;
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;

View File

@ -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;

View File

@ -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<dust3d::Uuid>& partIds) const

View File

@ -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<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);
connect(thread, &QThread::started, m_componentPreviewImagesGenerator, &MeshPreviewImagesGenerator::process);

View File

@ -40,6 +40,19 @@ void MeshGenerator::process()
auto it = m_generatedComponentPreviews.find(componentId);
if (it == m_generatedComponentPreviews.end())
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);
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)

View File

@ -73,12 +73,17 @@ ModelMesh::ModelMesh(const std::vector<dust3d::Vector3>& vertices,
const dust3d::Color& color,
float metalness,
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_triangleVertices = new ModelOpenGLVertex[m_triangleVertexCount];
int destIndex = 0;
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++) {
int vertexIndex = (int)triangles[i][j];
const dust3d::Vector3* srcVert = &vertices[vertexIndex];
@ -87,8 +92,8 @@ ModelMesh::ModelMesh(const std::vector<dust3d::Vector3>& 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();

View File

@ -5,9 +5,14 @@
#include <QImage>
#include <QObject>
#include <QTextStream>
#include <array>
#include <dust3d/base/color.h>
#include <dust3d/base/object.h>
#include <dust3d/base/position_key.h>
#include <dust3d/base/vector2.h>
#include <dust3d/base/vector3.h>
#include <map>
#include <tuple>
#include <vector>
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<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(ModelOpenGLVertex* triangleVertices, int vertexNum);
ModelMesh(const ModelMesh& mesh);

View File

@ -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<QImage>(nullptr != m_mesh ? m_mesh->takeTextureImage() : nullptr);
auto object = std::make_unique<ModelOpenGLObject>();
object->update(std::unique_ptr<ModelMesh>(m_mesh));
m_mesh = nullptr;
auto program = std::make_unique<ModelOpenGLProgram>();
program->load(m_context->format().profile() == QSurfaceFormat::CoreProfile);
if (nullptr != colorTextureImage)
program->updateTextureImage(std::move(colorTextureImage));
program->bind();
program->bindMaps();

View File

@ -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)

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()
{
m_previewImage = std::make_unique<QImage>(m_uvImageSize, m_uvImageSize, QImage::Format_ARGB32);
m_previewImage->fill(Qt::white);
// TODO:
}

View File

@ -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 <QImage>
#include <QObject>
@ -11,6 +11,7 @@ class UvPreviewImageGenerator : public QObject {
Q_OBJECT
public:
UvPreviewImageGenerator(std::vector<std::vector<dust3d::Vector2>>&& faceUvs);
std::unique_ptr<QImage> takePreviewImage();
void generate();
signals:
void finished();

View File

@ -683,7 +683,26 @@ std::unique_ptr<MeshCombiner::Mesh> 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<MeshCombiner::Mesh> 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> sectionPreviewMeshBuilder;

View File

@ -44,10 +44,10 @@ public:
struct GeneratedPart {
std::vector<Vector3> vertices;
std::vector<std::vector<size_t>> faces;
std::map<std::array<PositionKey, 3>, std::array<Vector2, 3>> triangleUvs;
std::vector<ObjectNode> objectNodes;
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::vector<Vector2>> 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<Vector3> vertices;
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);
float metalness = 0.0;
float roughness = 1.0;

View File

@ -21,6 +21,7 @@
*/
#include <algorithm>
#include <dust3d/base/debug.h>
#include <dust3d/mesh/base_normal.h>
#include <dust3d/mesh/tube_mesh_builder.h>
@ -204,7 +205,8 @@ void TubeMeshBuilder::build()
// Build all vertex Uvs
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);
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<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
@ -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());
}
}