dust3d/src/uvunwrap.cpp

94 lines
3.9 KiB
C++

#include <simpleuv/uvunwrapper.h>
#include <QDebug>
#include <QRectF>
#include "uvunwrap.h"
void uvUnwrap(const Outcome &outcome,
std::vector<std::vector<QVector2D>> &triangleVertexUvs,
std::set<int> &seamVertices,
std::map<QUuid, std::vector<QRectF>> &uvRects)
{
const auto &choosenVertices = outcome.vertices;
const auto &choosenTriangles = outcome.triangles;
const auto &choosenTriangleNormals = outcome.triangleNormals;
triangleVertexUvs.resize(choosenTriangles.size(), {
QVector2D(), QVector2D(), QVector2D()
});
if (nullptr == outcome.triangleSourceNodes())
return;
const std::vector<std::pair<QUuid, QUuid>> &triangleSourceNodes = *outcome.triangleSourceNodes();
simpleuv::Mesh inputMesh;
for (const auto &vertex: choosenVertices) {
simpleuv::Vertex v;
v.xyz[0] = vertex.x();
v.xyz[1] = vertex.y();
v.xyz[2] = vertex.z();
inputMesh.vertices.push_back(v);
}
std::map<QUuid, int> partIdToPartitionMap;
std::vector<QUuid> partitionPartUuids;
for (decltype(choosenTriangles.size()) i = 0; i < choosenTriangles.size(); ++i) {
const auto &triangle = choosenTriangles[i];
const auto &sourceNode = triangleSourceNodes[i];
const auto &normal = choosenTriangleNormals[i];
simpleuv::Face f;
f.indices[0] = triangle[0];
f.indices[1] = triangle[1];
f.indices[2] = triangle[2];
inputMesh.faces.push_back(f);
simpleuv::Vector3 n;
n.xyz[0] = normal.x();
n.xyz[1] = normal.y();
n.xyz[2] = normal.z();
inputMesh.faceNormals.push_back(n);
auto findPartitionResult = partIdToPartitionMap.find(sourceNode.first);
if (findPartitionResult == partIdToPartitionMap.end()) {
partitionPartUuids.push_back(sourceNode.first);
partIdToPartitionMap.insert({sourceNode.first, (int)partitionPartUuids.size()});
inputMesh.facePartitions.push_back((int)partitionPartUuids.size());
} else {
inputMesh.facePartitions.push_back(findPartitionResult->second);
}
}
simpleuv::UvUnwrapper uvUnwrapper;
uvUnwrapper.setMesh(inputMesh);
uvUnwrapper.unwrap();
qDebug() << "Texture size:" << uvUnwrapper.getTextureSize();
const std::vector<simpleuv::FaceTextureCoords> &resultFaceUvs = uvUnwrapper.getFaceUvs();
const std::vector<simpleuv::Rect> &resultChartRects = uvUnwrapper.getChartRects();
const std::vector<int> &resultChartSourcePartitions = uvUnwrapper.getChartSourcePartitions();
std::map<int, QVector2D> vertexUvMap;
for (decltype(choosenTriangles.size()) i = 0; i < choosenTriangles.size(); ++i) {
const auto &triangle = choosenTriangles[i];
const auto &src = resultFaceUvs[i];
auto &dest = triangleVertexUvs[i];
for (size_t j = 0; j < 3; ++j) {
QVector2D uvCoord = QVector2D(src.coords[j].uv[0], src.coords[j].uv[1]);
dest[j][0] = uvCoord.x();
dest[j][1] = uvCoord.y();
int vertexIndex = triangle[j];
auto findVertexUvResult = vertexUvMap.find(vertexIndex);
if (findVertexUvResult == vertexUvMap.end()) {
vertexUvMap.insert({vertexIndex, uvCoord});
} else {
if (!qFuzzyCompare(findVertexUvResult->second, uvCoord)) {
seamVertices.insert(vertexIndex);
}
}
}
}
for (size_t i = 0; i < resultChartRects.size(); ++i) {
const auto &rect = resultChartRects[i];
const auto &source = resultChartSourcePartitions[i];
if (0 == source || source > (int)partitionPartUuids.size()) {
qDebug() << "Invalid UV chart source partition:" << source;
continue;
}
uvRects[partitionPartUuids[source - 1]].push_back({rect.left, rect.top, rect.width, rect.height});
}
}