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;
uvUnwrapper.setMesh(inputMesh);
uvUnwrapper.unwrap();
qDebug() << "Texture size:" << uvUnwrapper.textureSize();
const std::vector<simpleuv::FaceTextureCoords> &resultFaceUvs = uvUnwrapper.getFaceUvs();
const std::vector<QRectF> &resultChartRects = uvUnwrapper.getChartRects();
const std::vector<int> &resultChartSourcePartitions = uvUnwrapper.getChartSourcePartitions();

View File

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

View File

@ -11,7 +11,7 @@ class ChartPacker
public:
void setCharts(const std::vector<std::pair<float, float>> &chartSizes);
const std::vector<std::tuple<float, float, float, float, bool>> &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;
};
}

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()
{
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<std::tuple<float, float, float, float, bool>> &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<Vertex> &verticies,
m_chartSourcePartitions.push_back(sourcePartition);
}
float UvUnwrapper::textureSize() const
{
return m_resultTextureSize;
}
void UvUnwrapper::unwrap()
{
partition();

View File

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