Scale UV by area ration

master
Jeremy Hu 2019-08-09 22:03:42 +09:30
parent f5a70dfd9e
commit a6b9ac7bf1
5 changed files with 55 additions and 6 deletions

View File

@ -57,6 +57,7 @@ void uvUnwrap(const Outcome &outcome,
simpleuv::UvUnwrapper uvUnwrapper; simpleuv::UvUnwrapper uvUnwrapper;
uvUnwrapper.setMesh(inputMesh); uvUnwrapper.setMesh(inputMesh);
uvUnwrapper.unwrap(); uvUnwrapper.unwrap();
qDebug() << "Texture size:" << uvUnwrapper.textureSize();
const std::vector<simpleuv::FaceTextureCoords> &resultFaceUvs = uvUnwrapper.getFaceUvs(); const std::vector<simpleuv::FaceTextureCoords> &resultFaceUvs = uvUnwrapper.getFaceUvs();
const std::vector<QRectF> &resultChartRects = uvUnwrapper.getChartRects(); const std::vector<QRectF> &resultChartRects = uvUnwrapper.getChartRects();
const std::vector<int> &resultChartSourcePartitions = uvUnwrapper.getChartSourcePartitions(); const std::vector<int> &resultChartSourcePartitions = uvUnwrapper.getChartSourcePartitions();

View File

@ -82,11 +82,12 @@ bool ChartPacker::tryPack(float textureSize)
return true; return true;
} }
void ChartPacker::pack() float ChartPacker::pack()
{ {
float textureSize = 0;
float initialGuessSize = std::sqrt(calculateTotalArea() * m_initialAreaGuessFactor); float initialGuessSize = std::sqrt(calculateTotalArea() * m_initialAreaGuessFactor);
while (true) { while (true) {
float textureSize = initialGuessSize * m_textureSizeFactor; textureSize = initialGuessSize * m_textureSizeFactor;
++m_tryNum; ++m_tryNum;
if (tryPack(textureSize)) if (tryPack(textureSize))
break; break;
@ -96,6 +97,7 @@ void ChartPacker::pack()
break; break;
} }
} }
return textureSize;
} }
} }

View File

@ -11,7 +11,7 @@ class ChartPacker
public: public:
void setCharts(const std::vector<std::pair<float, float>> &chartSizes); void setCharts(const std::vector<std::pair<float, float>> &chartSizes);
const std::vector<std::tuple<float, float, float, float, bool>> &getResult(); const std::vector<std::tuple<float, float, float, float, bool>> &getResult();
void pack(); float pack();
bool tryPack(float textureSize); bool tryPack(float textureSize);
private: private:
@ -25,7 +25,6 @@ private:
size_t m_tryNum = 0; size_t m_tryNum = 0;
float m_textureSizeFactor = 1.0; float m_textureSizeFactor = 1.0;
size_t m_maxTryNum = 100; size_t m_maxTryNum = 100;
float m_texelSizePerUnit = 1.0f;
}; };
} }

View File

@ -316,6 +316,20 @@ void UvUnwrapper::makeSeamAndCut(const std::vector<Vertex> &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() void UvUnwrapper::calculateSizeAndRemoveInvalidCharts()
{ {
auto charts = m_charts; auto charts = m_charts;
@ -333,15 +347,35 @@ void UvUnwrapper::calculateSizeAndRemoveInvalidCharts()
qDebug() << "Found invalid chart size:" << size.first << "x" << size.second; qDebug() << "Found invalid chart size:" << size.first << "x" << size.second;
continue; 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 (auto &item: chart.second) {
for (int i = 0; i < 3; ++i) { for (int i = 0; i < 3; ++i) {
item.coords[i].uv[0] -= left; item.coords[i].uv[0] -= left;
item.coords[i].uv[1] -= top; 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() << "left:" << left << "top:" << top << "right:" << right << "bottom:" << bottom;
//qDebug() << "width:" << size.first << "height:" << size.second; //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_chartSizes.push_back(size);
m_scaledChartSizes.push_back(std::make_pair(size.first * scale, size.second * scale));
m_charts.push_back(chart); m_charts.push_back(chart);
m_chartSourcePartitions.push_back(chartSourcePartitions[chartIndex]); m_chartSourcePartitions.push_back(chartSourcePartitions[chartIndex]);
} }
@ -350,8 +384,8 @@ void UvUnwrapper::calculateSizeAndRemoveInvalidCharts()
void UvUnwrapper::packCharts() void UvUnwrapper::packCharts()
{ {
ChartPacker chartPacker; ChartPacker chartPacker;
chartPacker.setCharts(m_chartSizes); chartPacker.setCharts(m_scaledChartSizes);
chartPacker.pack(); m_resultTextureSize = chartPacker.pack();
m_chartRects.resize(m_chartSizes.size()); m_chartRects.resize(m_chartSizes.size());
const std::vector<std::tuple<float, float, float, float, bool>> &packedResult = chartPacker.getResult(); const std::vector<std::tuple<float, float, float, float, bool>> &packedResult = chartPacker.getResult();
for (decltype(m_charts.size()) i = 0; i < m_charts.size(); ++i) { for (decltype(m_charts.size()) i = 0; i < m_charts.size(); ++i) {
@ -505,6 +539,11 @@ void UvUnwrapper::parametrizeSingleGroup(const std::vector<Vertex> &verticies,
m_chartSourcePartitions.push_back(sourcePartition); m_chartSourcePartitions.push_back(sourcePartition);
} }
float UvUnwrapper::textureSize() const
{
return m_resultTextureSize;
}
void UvUnwrapper::unwrap() void UvUnwrapper::unwrap()
{ {
partition(); partition();

View File

@ -4,6 +4,8 @@
#include <map> #include <map>
#include <QRectF> #include <QRectF>
#include <simpleuv/meshdatatype.h> #include <simpleuv/meshdatatype.h>
#include <QVector3D>
#include <QVector2D>
namespace simpleuv namespace simpleuv
{ {
@ -16,6 +18,7 @@ public:
const std::vector<FaceTextureCoords> &getFaceUvs() const; const std::vector<FaceTextureCoords> &getFaceUvs() const;
const std::vector<QRectF> &getChartRects() const; const std::vector<QRectF> &getChartRects() const;
const std::vector<int> &getChartSourcePartitions() const; const std::vector<int> &getChartSourcePartitions() const;
float textureSize() const;
private: private:
void partition(); void partition();
@ -38,6 +41,8 @@ private:
void buildEdgeToFaceMap(const std::vector<Face> &faces, std::map<std::pair<size_t, size_t>, size_t> &edgeToFaceMap); void buildEdgeToFaceMap(const std::vector<Face> &faces, std::map<std::pair<size_t, size_t>, size_t> &edgeToFaceMap);
double distanceBetweenVertices(const Vertex &first, const Vertex &second); double distanceBetweenVertices(const Vertex &first, const Vertex &second);
double dotProduct(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<Vertex> &verticies, void triangulateRing(const std::vector<Vertex> &verticies,
std::vector<Face> &faces, const std::vector<size_t> &ring); std::vector<Face> &faces, const std::vector<size_t> &ring);
void calculateFaceTextureBoundingBox(const std::vector<FaceTextureCoords> &faceTextureCoords, void calculateFaceTextureBoundingBox(const std::vector<FaceTextureCoords> &faceTextureCoords,
@ -48,10 +53,13 @@ private:
std::map<int, std::vector<size_t>> m_partitions; std::map<int, std::vector<size_t>> m_partitions;
std::vector<std::pair<std::vector<size_t>, std::vector<FaceTextureCoords>>> m_charts; std::vector<std::pair<std::vector<size_t>, std::vector<FaceTextureCoords>>> m_charts;
std::vector<std::pair<float, float>> m_chartSizes; std::vector<std::pair<float, float>> m_chartSizes;
std::vector<std::pair<float, float>> m_scaledChartSizes;
std::vector<QRectF> m_chartRects; std::vector<QRectF> m_chartRects;
std::vector<int> m_chartSourcePartitions; std::vector<int> m_chartSourcePartitions;
bool m_segmentByNormal = true; bool m_segmentByNormal = true;
float m_segmentDotProductThreshold = 0.00; float m_segmentDotProductThreshold = 0.00;
float m_texelSizePerUnit = 1.0;
float m_resultTextureSize = 0;
}; };
} }