Scale UV by area ration
parent
f5a70dfd9e
commit
a6b9ac7bf1
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue