From a6b9ac7bf1052622235a9961a663f4cead7e7e4e Mon Sep 17 00:00:00 2001 From: Jeremy Hu Date: Fri, 9 Aug 2019 22:03:42 +0930 Subject: [PATCH] Scale UV by area ration --- src/uvunwrap.cpp | 1 + thirdparty/simpleuv/simpleuv/chartpacker.cpp | 6 ++- thirdparty/simpleuv/simpleuv/chartpacker.h | 3 +- thirdparty/simpleuv/simpleuv/uvunwrapper.cpp | 43 +++++++++++++++++++- thirdparty/simpleuv/simpleuv/uvunwrapper.h | 8 ++++ 5 files changed, 55 insertions(+), 6 deletions(-) diff --git a/src/uvunwrap.cpp b/src/uvunwrap.cpp index 59544d8e..249edb3b 100644 --- a/src/uvunwrap.cpp +++ b/src/uvunwrap.cpp @@ -57,6 +57,7 @@ void uvUnwrap(const Outcome &outcome, simpleuv::UvUnwrapper uvUnwrapper; uvUnwrapper.setMesh(inputMesh); uvUnwrapper.unwrap(); + qDebug() << "Texture size:" << uvUnwrapper.textureSize(); const std::vector &resultFaceUvs = uvUnwrapper.getFaceUvs(); const std::vector &resultChartRects = uvUnwrapper.getChartRects(); const std::vector &resultChartSourcePartitions = uvUnwrapper.getChartSourcePartitions(); diff --git a/thirdparty/simpleuv/simpleuv/chartpacker.cpp b/thirdparty/simpleuv/simpleuv/chartpacker.cpp index 8b9c3fa0..c096a468 100644 --- a/thirdparty/simpleuv/simpleuv/chartpacker.cpp +++ b/thirdparty/simpleuv/simpleuv/chartpacker.cpp @@ -82,11 +82,12 @@ bool ChartPacker::tryPack(float textureSize) return true; } -void ChartPacker::pack() +float ChartPacker::pack() { + float textureSize = 0; float initialGuessSize = std::sqrt(calculateTotalArea() * m_initialAreaGuessFactor); while (true) { - float textureSize = initialGuessSize * m_textureSizeFactor; + textureSize = initialGuessSize * m_textureSizeFactor; ++m_tryNum; if (tryPack(textureSize)) break; @@ -96,6 +97,7 @@ void ChartPacker::pack() break; } } + return textureSize; } } diff --git a/thirdparty/simpleuv/simpleuv/chartpacker.h b/thirdparty/simpleuv/simpleuv/chartpacker.h index fd28edce..a8a5a11d 100644 --- a/thirdparty/simpleuv/simpleuv/chartpacker.h +++ b/thirdparty/simpleuv/simpleuv/chartpacker.h @@ -11,7 +11,7 @@ class ChartPacker public: void setCharts(const std::vector> &chartSizes); const std::vector> &getResult(); - void pack(); + float pack(); bool tryPack(float textureSize); private: @@ -25,7 +25,6 @@ private: size_t m_tryNum = 0; float m_textureSizeFactor = 1.0; size_t m_maxTryNum = 100; - float m_texelSizePerUnit = 1.0f; }; } diff --git a/thirdparty/simpleuv/simpleuv/uvunwrapper.cpp b/thirdparty/simpleuv/simpleuv/uvunwrapper.cpp index d14d50af..48759258 100644 --- a/thirdparty/simpleuv/simpleuv/uvunwrapper.cpp +++ b/thirdparty/simpleuv/simpleuv/uvunwrapper.cpp @@ -316,6 +316,20 @@ void UvUnwrapper::makeSeamAndCut(const std::vector &verticies, } } +float UvUnwrapper::areaOf3dTriangle(const QVector3D &a, const QVector3D &b, const QVector3D &c) +{ + auto ab = b - a; + auto ac = c - a; + return 0.5 * QVector3D::crossProduct(ab, ac).length(); +} + +float UvUnwrapper::areaOf2dTriangle(const QVector2D &a, const QVector2D &b, const QVector2D &c) +{ + return areaOf3dTriangle(QVector3D(a.x(), a.y(), 0), + QVector3D(b.x(), b.y(), 0), + QVector3D(c.x(), c.y(), 0)); +} + void UvUnwrapper::calculateSizeAndRemoveInvalidCharts() { auto charts = m_charts; @@ -333,15 +347,35 @@ void UvUnwrapper::calculateSizeAndRemoveInvalidCharts() qDebug() << "Found invalid chart size:" << size.first << "x" << size.second; continue; } + float surfaceArea = 0; + for (const auto &item: chart.first) { + const auto &face = m_mesh.faces[item]; + surfaceArea += areaOf3dTriangle(QVector3D(m_mesh.vertices[face.indices[0]].xyz[0], + m_mesh.vertices[face.indices[0]].xyz[1], + m_mesh.vertices[face.indices[0]].xyz[2]), + QVector3D(m_mesh.vertices[face.indices[1]].xyz[0], + m_mesh.vertices[face.indices[1]].xyz[1], + m_mesh.vertices[face.indices[1]].xyz[2]), + QVector3D(m_mesh.vertices[face.indices[2]].xyz[0], + m_mesh.vertices[face.indices[2]].xyz[1], + m_mesh.vertices[face.indices[2]].xyz[2])); + } + float uvArea = 0; for (auto &item: chart.second) { for (int i = 0; i < 3; ++i) { item.coords[i].uv[0] -= left; item.coords[i].uv[1] -= top; } + uvArea += areaOf2dTriangle(QVector2D(item.coords[0].uv[0], item.coords[0].uv[1]), + QVector2D(item.coords[1].uv[0], item.coords[1].uv[1]), + QVector2D(item.coords[2].uv[0], item.coords[2].uv[1])); } //qDebug() << "left:" << left << "top:" << top << "right:" << right << "bottom:" << bottom; //qDebug() << "width:" << size.first << "height:" << size.second; + float ratioOfSurfaceAreaAndUvArea = uvArea > 0 ? surfaceArea / uvArea : 1.0; + float scale = ratioOfSurfaceAreaAndUvArea * m_texelSizePerUnit; m_chartSizes.push_back(size); + m_scaledChartSizes.push_back(std::make_pair(size.first * scale, size.second * scale)); m_charts.push_back(chart); m_chartSourcePartitions.push_back(chartSourcePartitions[chartIndex]); } @@ -350,8 +384,8 @@ void UvUnwrapper::calculateSizeAndRemoveInvalidCharts() void UvUnwrapper::packCharts() { ChartPacker chartPacker; - chartPacker.setCharts(m_chartSizes); - chartPacker.pack(); + chartPacker.setCharts(m_scaledChartSizes); + m_resultTextureSize = chartPacker.pack(); m_chartRects.resize(m_chartSizes.size()); const std::vector> &packedResult = chartPacker.getResult(); for (decltype(m_charts.size()) i = 0; i < m_charts.size(); ++i) { @@ -505,6 +539,11 @@ void UvUnwrapper::parametrizeSingleGroup(const std::vector &verticies, m_chartSourcePartitions.push_back(sourcePartition); } +float UvUnwrapper::textureSize() const +{ + return m_resultTextureSize; +} + void UvUnwrapper::unwrap() { partition(); diff --git a/thirdparty/simpleuv/simpleuv/uvunwrapper.h b/thirdparty/simpleuv/simpleuv/uvunwrapper.h index ab01b222..c6d37abb 100644 --- a/thirdparty/simpleuv/simpleuv/uvunwrapper.h +++ b/thirdparty/simpleuv/simpleuv/uvunwrapper.h @@ -4,6 +4,8 @@ #include #include #include +#include +#include namespace simpleuv { @@ -16,6 +18,7 @@ public: const std::vector &getFaceUvs() const; const std::vector &getChartRects() const; const std::vector &getChartSourcePartitions() const; + float textureSize() const; private: void partition(); @@ -38,6 +41,8 @@ private: void buildEdgeToFaceMap(const std::vector &faces, std::map, size_t> &edgeToFaceMap); double distanceBetweenVertices(const Vertex &first, const Vertex &second); double dotProduct(const Vertex &first, const Vertex &second); + float areaOf3dTriangle(const QVector3D &a, const QVector3D &b, const QVector3D &c); + float areaOf2dTriangle(const QVector2D &a, const QVector2D &b, const QVector2D &c); void triangulateRing(const std::vector &verticies, std::vector &faces, const std::vector &ring); void calculateFaceTextureBoundingBox(const std::vector &faceTextureCoords, @@ -48,10 +53,13 @@ private: std::map> m_partitions; std::vector, std::vector>> m_charts; std::vector> m_chartSizes; + std::vector> m_scaledChartSizes; std::vector m_chartRects; std::vector m_chartSourcePartitions; bool m_segmentByNormal = true; float m_segmentDotProductThreshold = 0.00; + float m_texelSizePerUnit = 1.0; + float m_resultTextureSize = 0; }; }