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