Remove poly count
parent
62418b9340
commit
1e7057bd90
|
@ -341,9 +341,6 @@ HEADERS += src/skeletondocument.h
|
||||||
SOURCES += src/combinemode.cpp
|
SOURCES += src/combinemode.cpp
|
||||||
HEADERS += src/combinemode.h
|
HEADERS += src/combinemode.h
|
||||||
|
|
||||||
SOURCES += src/polycount.cpp
|
|
||||||
HEADERS += src/polycount.h
|
|
||||||
|
|
||||||
SOURCES += src/cutface.cpp
|
SOURCES += src/cutface.cpp
|
||||||
HEADERS += src/cutface.h
|
HEADERS += src/cutface.h
|
||||||
|
|
||||||
|
@ -430,15 +427,9 @@ HEADERS += src/triangulatefaces.h
|
||||||
SOURCES += src/booleanmesh.cpp
|
SOURCES += src/booleanmesh.cpp
|
||||||
HEADERS += src/booleanmesh.h
|
HEADERS += src/booleanmesh.h
|
||||||
|
|
||||||
SOURCES += src/remesher.cpp
|
|
||||||
HEADERS += src/remesher.h
|
|
||||||
|
|
||||||
SOURCES += src/isotropicremesh.cpp
|
SOURCES += src/isotropicremesh.cpp
|
||||||
HEADERS += src/isotropicremesh.h
|
HEADERS += src/isotropicremesh.h
|
||||||
|
|
||||||
SOURCES += src/projectfacestonodes.cpp
|
|
||||||
HEADERS += src/projectfacestonodes.h
|
|
||||||
|
|
||||||
SOURCES += src/ddsfile.cpp
|
SOURCES += src/ddsfile.cpp
|
||||||
HEADERS += src/ddsfile.h
|
HEADERS += src/ddsfile.h
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,6 @@ Document::Document() :
|
||||||
textureAmbientOcclusionImageByteArray(nullptr),
|
textureAmbientOcclusionImageByteArray(nullptr),
|
||||||
rigType(RigType::None),
|
rigType(RigType::None),
|
||||||
weldEnabled(true),
|
weldEnabled(true),
|
||||||
polyCount(PolyCount::Original),
|
|
||||||
brushColor(Qt::white),
|
brushColor(Qt::white),
|
||||||
objectLocked(false),
|
objectLocked(false),
|
||||||
// private
|
// private
|
||||||
|
@ -1226,8 +1225,6 @@ void Document::toSnapshot(Snapshot *snapshot, const std::set<QUuid> &limitNodeId
|
||||||
component["smoothAll"] = QString::number(componentIt.second.smoothAll);
|
component["smoothAll"] = QString::number(componentIt.second.smoothAll);
|
||||||
if (componentIt.second.smoothSeamAdjusted())
|
if (componentIt.second.smoothSeamAdjusted())
|
||||||
component["smoothSeam"] = QString::number(componentIt.second.smoothSeam);
|
component["smoothSeam"] = QString::number(componentIt.second.smoothSeam);
|
||||||
if (componentIt.second.polyCount != PolyCount::Original)
|
|
||||||
component["polyCount"] = PolyCountToString(componentIt.second.polyCount);
|
|
||||||
QStringList childIdList;
|
QStringList childIdList;
|
||||||
for (const auto &childId: componentIt.second.childrenIds) {
|
for (const auto &childId: componentIt.second.childrenIds) {
|
||||||
childIdList.append(childId.toString());
|
childIdList.append(childId.toString());
|
||||||
|
@ -1306,8 +1303,6 @@ void Document::toSnapshot(Snapshot *snapshot, const std::set<QUuid> &limitNodeId
|
||||||
canvas["originY"] = QString::number(getOriginY());
|
canvas["originY"] = QString::number(getOriginY());
|
||||||
canvas["originZ"] = QString::number(getOriginZ());
|
canvas["originZ"] = QString::number(getOriginZ());
|
||||||
canvas["rigType"] = RigTypeToString(rigType);
|
canvas["rigType"] = RigTypeToString(rigType);
|
||||||
if (this->polyCount != PolyCount::Original)
|
|
||||||
canvas["polyCount"] = PolyCountToString(this->polyCount);
|
|
||||||
if (this->objectLocked)
|
if (this->objectLocked)
|
||||||
canvas["objectLocked"] = "true";
|
canvas["objectLocked"] = "true";
|
||||||
snapshot->canvas = canvas;
|
snapshot->canvas = canvas;
|
||||||
|
@ -1412,7 +1407,6 @@ void Document::addFromSnapshot(const Snapshot &snapshot, enum SnapshotSource sou
|
||||||
bool isMeshLockedChanged = false;
|
bool isMeshLockedChanged = false;
|
||||||
if (SnapshotSource::Paste != source &&
|
if (SnapshotSource::Paste != source &&
|
||||||
SnapshotSource::Import != source) {
|
SnapshotSource::Import != source) {
|
||||||
this->polyCount = PolyCountFromString(valueOfKeyInMapOrEmpty(snapshot.canvas, "polyCount").toUtf8().constData());
|
|
||||||
const auto &originXit = snapshot.canvas.find("originX");
|
const auto &originXit = snapshot.canvas.find("originX");
|
||||||
const auto &originYit = snapshot.canvas.find("originY");
|
const auto &originYit = snapshot.canvas.find("originY");
|
||||||
const auto &originZit = snapshot.canvas.find("originZ");
|
const auto &originZit = snapshot.canvas.find("originZ");
|
||||||
|
@ -1669,7 +1663,6 @@ void Document::addFromSnapshot(const Snapshot &snapshot, enum SnapshotSource sou
|
||||||
const auto &smoothSeamIt = componentKv.second.find("smoothSeam");
|
const auto &smoothSeamIt = componentKv.second.find("smoothSeam");
|
||||||
if (smoothSeamIt != componentKv.second.end())
|
if (smoothSeamIt != componentKv.second.end())
|
||||||
component.setSmoothSeam(smoothSeamIt->second.toFloat());
|
component.setSmoothSeam(smoothSeamIt->second.toFloat());
|
||||||
component.polyCount = PolyCountFromString(valueOfKeyInMapOrEmpty(componentKv.second, "polyCount").toUtf8().constData());
|
|
||||||
//qDebug() << "Add component:" << component.id << " old:" << componentKv.first << "name:" << component.name;
|
//qDebug() << "Add component:" << component.id << " old:" << componentKv.first << "name:" << component.name;
|
||||||
if ("partId" == linkDataType) {
|
if ("partId" == linkDataType) {
|
||||||
QUuid partId = oldNewIdMap[QUuid(linkData)];
|
QUuid partId = oldNewIdMap[QUuid(linkData)];
|
||||||
|
@ -2460,29 +2453,6 @@ void Document::setComponentExpandState(QUuid componentId, bool expanded)
|
||||||
emit optionsChanged();
|
emit optionsChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Document::setComponentPolyCount(QUuid componentId, PolyCount count)
|
|
||||||
{
|
|
||||||
if (componentId.isNull()) {
|
|
||||||
if (polyCount == count)
|
|
||||||
return;
|
|
||||||
polyCount = count;
|
|
||||||
emit componentPolyCountChanged(componentId);
|
|
||||||
emit skeletonChanged();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Component *component = (Component *)findComponent(componentId);
|
|
||||||
if (nullptr == component)
|
|
||||||
return;
|
|
||||||
if (component->polyCount == count)
|
|
||||||
return;
|
|
||||||
|
|
||||||
component->polyCount = count;
|
|
||||||
component->dirty = true;
|
|
||||||
emit componentPolyCountChanged(componentId);
|
|
||||||
emit skeletonChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Document::createNewComponentAndMoveThisIn(QUuid componentId)
|
void Document::createNewComponentAndMoveThisIn(QUuid componentId)
|
||||||
{
|
{
|
||||||
auto component = componentMap.find(componentId);
|
auto component = componentMap.find(componentId);
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
#include "jointnodetree.h"
|
#include "jointnodetree.h"
|
||||||
#include "skeletondocument.h"
|
#include "skeletondocument.h"
|
||||||
#include "combinemode.h"
|
#include "combinemode.h"
|
||||||
#include "polycount.h"
|
|
||||||
#include "preferences.h"
|
#include "preferences.h"
|
||||||
#include "paintmode.h"
|
#include "paintmode.h"
|
||||||
#include "proceduralanimation.h"
|
#include "proceduralanimation.h"
|
||||||
|
@ -64,7 +63,6 @@ public:
|
||||||
bool dirty = true;
|
bool dirty = true;
|
||||||
float smoothAll = 0.0;
|
float smoothAll = 0.0;
|
||||||
float smoothSeam = 0.0;
|
float smoothSeam = 0.0;
|
||||||
PolyCount polyCount = PolyCount::Original;
|
|
||||||
std::vector<QUuid> childrenIds;
|
std::vector<QUuid> childrenIds;
|
||||||
QString linkData() const
|
QString linkData() const
|
||||||
{
|
{
|
||||||
|
@ -287,7 +285,6 @@ signals:
|
||||||
void componentExpandStateChanged(QUuid componentId);
|
void componentExpandStateChanged(QUuid componentId);
|
||||||
void componentSmoothAllChanged(QUuid componentId);
|
void componentSmoothAllChanged(QUuid componentId);
|
||||||
void componentSmoothSeamChanged(QUuid componentId);
|
void componentSmoothSeamChanged(QUuid componentId);
|
||||||
void componentPolyCountChanged(QUuid componentId);
|
|
||||||
void componentLayerChanged(QUuid componentId);
|
void componentLayerChanged(QUuid componentId);
|
||||||
void nodeRemoved(QUuid nodeId);
|
void nodeRemoved(QUuid nodeId);
|
||||||
void edgeRemoved(QUuid edgeId);
|
void edgeRemoved(QUuid edgeId);
|
||||||
|
@ -398,7 +395,6 @@ public: // need initialize
|
||||||
QByteArray *textureAmbientOcclusionImageByteArray;
|
QByteArray *textureAmbientOcclusionImageByteArray;
|
||||||
RigType rigType;
|
RigType rigType;
|
||||||
bool weldEnabled;
|
bool weldEnabled;
|
||||||
PolyCount polyCount;
|
|
||||||
QColor brushColor;
|
QColor brushColor;
|
||||||
bool objectLocked;
|
bool objectLocked;
|
||||||
float brushMetalness = Model::m_defaultMetalness;
|
float brushMetalness = Model::m_defaultMetalness;
|
||||||
|
@ -555,7 +551,6 @@ public slots:
|
||||||
void setComponentExpandState(QUuid componentId, bool expanded);
|
void setComponentExpandState(QUuid componentId, bool expanded);
|
||||||
void setComponentSmoothAll(QUuid componentId, float toSmoothAll);
|
void setComponentSmoothAll(QUuid componentId, float toSmoothAll);
|
||||||
void setComponentSmoothSeam(QUuid componentId, float toSmoothSeam);
|
void setComponentSmoothSeam(QUuid componentId, float toSmoothSeam);
|
||||||
void setComponentPolyCount(QUuid componentId, PolyCount count);
|
|
||||||
void hideOtherComponents(QUuid componentId);
|
void hideOtherComponents(QUuid componentId);
|
||||||
void lockOtherComponents(QUuid componentId);
|
void lockOtherComponents(QUuid componentId);
|
||||||
void hideAllComponents();
|
void hideAllComponents();
|
||||||
|
|
|
@ -986,7 +986,6 @@ DocumentWindow::DocumentWindow() :
|
||||||
connect(m_partTreeWidget, &PartTreeWidget::setComponentExpandState, m_document, &Document::setComponentExpandState);
|
connect(m_partTreeWidget, &PartTreeWidget::setComponentExpandState, m_document, &Document::setComponentExpandState);
|
||||||
connect(m_partTreeWidget, &PartTreeWidget::setComponentSmoothAll, m_document, &Document::setComponentSmoothAll);
|
connect(m_partTreeWidget, &PartTreeWidget::setComponentSmoothAll, m_document, &Document::setComponentSmoothAll);
|
||||||
connect(m_partTreeWidget, &PartTreeWidget::setComponentSmoothSeam, m_document, &Document::setComponentSmoothSeam);
|
connect(m_partTreeWidget, &PartTreeWidget::setComponentSmoothSeam, m_document, &Document::setComponentSmoothSeam);
|
||||||
connect(m_partTreeWidget, &PartTreeWidget::setComponentPolyCount, m_document, &Document::setComponentPolyCount);
|
|
||||||
connect(m_partTreeWidget, &PartTreeWidget::moveComponent, m_document, &Document::moveComponent);
|
connect(m_partTreeWidget, &PartTreeWidget::moveComponent, m_document, &Document::moveComponent);
|
||||||
connect(m_partTreeWidget, &PartTreeWidget::removeComponent, m_document, &Document::removeComponent);
|
connect(m_partTreeWidget, &PartTreeWidget::removeComponent, m_document, &Document::removeComponent);
|
||||||
connect(m_partTreeWidget, &PartTreeWidget::hideOtherComponents, m_document, &Document::hideOtherComponents);
|
connect(m_partTreeWidget, &PartTreeWidget::hideOtherComponents, m_document, &Document::hideOtherComponents);
|
||||||
|
|
|
@ -15,10 +15,7 @@
|
||||||
#include "partbase.h"
|
#include "partbase.h"
|
||||||
#include "imageforever.h"
|
#include "imageforever.h"
|
||||||
#include "triangulatefaces.h"
|
#include "triangulatefaces.h"
|
||||||
#include "remesher.h"
|
|
||||||
#include "polycount.h"
|
|
||||||
#include "isotropicremesh.h"
|
#include "isotropicremesh.h"
|
||||||
#include "projectfacestonodes.h"
|
|
||||||
#include "document.h"
|
#include "document.h"
|
||||||
#include "meshstroketifier.h"
|
#include "meshstroketifier.h"
|
||||||
#include "fileforever.h"
|
#include "fileforever.h"
|
||||||
|
@ -911,22 +908,10 @@ CombineMode MeshGenerator::componentCombineMode(const std::map<QString, QString>
|
||||||
if (combineMode == CombineMode::Normal) {
|
if (combineMode == CombineMode::Normal) {
|
||||||
if (isTrueValueString(valueOfKeyInMapOrEmpty(*component, "inverse")))
|
if (isTrueValueString(valueOfKeyInMapOrEmpty(*component, "inverse")))
|
||||||
combineMode = CombineMode::Inversion;
|
combineMode = CombineMode::Inversion;
|
||||||
if (componentRemeshed(component))
|
|
||||||
combineMode = CombineMode::Uncombined;
|
|
||||||
}
|
}
|
||||||
return combineMode;
|
return combineMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MeshGenerator::componentRemeshed(const std::map<QString, QString> *component, float *polyCountValue)
|
|
||||||
{
|
|
||||||
if (nullptr == component)
|
|
||||||
return false;
|
|
||||||
auto polyCount = PolyCountFromString(valueOfKeyInMapOrEmpty(*component, "polyCount").toUtf8().constData());
|
|
||||||
if (nullptr != polyCountValue)
|
|
||||||
*polyCountValue = PolyCountToValue(polyCount);
|
|
||||||
return polyCount != PolyCount::Original;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString MeshGenerator::componentColorName(const std::map<QString, QString> *component)
|
QString MeshGenerator::componentColorName(const std::map<QString, QString> *component)
|
||||||
{
|
{
|
||||||
if (nullptr == component)
|
if (nullptr == component)
|
||||||
|
@ -1125,73 +1110,6 @@ MeshCombiner::Mesh *MeshGenerator::combineComponentMesh(const QString &component
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nullptr != mesh) {
|
|
||||||
float polyCountValue = 1.0f;
|
|
||||||
bool remeshed = componentId.isNull() ? componentRemeshed(&m_snapshot->canvas, &polyCountValue) : componentRemeshed(component, &polyCountValue);
|
|
||||||
if (remeshed) {
|
|
||||||
std::vector<QVector3D> combinedVertices;
|
|
||||||
std::vector<std::vector<size_t>> combinedFaces;
|
|
||||||
mesh->fetch(combinedVertices, combinedFaces);
|
|
||||||
std::vector<QVector3D> newVertices;
|
|
||||||
std::vector<std::vector<size_t>> newQuads;
|
|
||||||
std::vector<std::vector<size_t>> newTriangles;
|
|
||||||
std::vector<std::tuple<QVector3D, float, size_t>> interpolatedNodes;
|
|
||||||
Object::buildInterpolatedNodes(componentCache.objectNodes,
|
|
||||||
componentCache.objectEdges,
|
|
||||||
&interpolatedNodes);
|
|
||||||
remesh(componentCache.objectNodes,
|
|
||||||
interpolatedNodes,
|
|
||||||
combinedVertices,
|
|
||||||
combinedFaces,
|
|
||||||
polyCountValue,
|
|
||||||
&newVertices,
|
|
||||||
&newQuads,
|
|
||||||
&newTriangles,
|
|
||||||
&componentCache.objectNodeVertices);
|
|
||||||
componentCache.sharedQuadEdges.clear();
|
|
||||||
for (const auto &face: newQuads) {
|
|
||||||
if (face.size() != 4)
|
|
||||||
continue;
|
|
||||||
componentCache.sharedQuadEdges.insert({
|
|
||||||
PositionKey(newVertices[face[0]]),
|
|
||||||
PositionKey(newVertices[face[2]])
|
|
||||||
});
|
|
||||||
componentCache.sharedQuadEdges.insert({
|
|
||||||
PositionKey(newVertices[face[1]]),
|
|
||||||
PositionKey(newVertices[face[3]])
|
|
||||||
});
|
|
||||||
}
|
|
||||||
delete mesh;
|
|
||||||
mesh = nullptr;
|
|
||||||
bool disableSelfIntersectionTest = componentId.isNull() ||
|
|
||||||
CombineMode::Uncombined == componentCombineMode(component);
|
|
||||||
if (!disableSelfIntersectionTest) {
|
|
||||||
if (isManifold(newTriangles)) {
|
|
||||||
mesh = new MeshCombiner::Mesh(newVertices, newTriangles, disableSelfIntersectionTest);
|
|
||||||
} else {
|
|
||||||
fixHoles(newVertices, newTriangles);
|
|
||||||
disableSelfIntersectionTest = true;
|
|
||||||
mesh = new MeshCombiner::Mesh(newVertices, newTriangles, disableSelfIntersectionTest);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fixHoles(newVertices, newTriangles);
|
|
||||||
mesh = new MeshCombiner::Mesh(newVertices, newTriangles, disableSelfIntersectionTest);
|
|
||||||
}
|
|
||||||
if (nullptr != mesh) {
|
|
||||||
if (!disableSelfIntersectionTest) {
|
|
||||||
if (mesh->isNull()) {
|
|
||||||
delete mesh;
|
|
||||||
mesh = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
delete componentCache.mesh;
|
|
||||||
componentCache.mesh = nullptr;
|
|
||||||
if (nullptr != mesh)
|
|
||||||
componentCache.mesh = new MeshCombiner::Mesh(*mesh);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return mesh;
|
return mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1463,55 +1381,6 @@ void MeshGenerator::postprocessObject(Object *object)
|
||||||
object->setTriangleVertexNormals(triangleVertexNormals);
|
object->setTriangleVertexNormals(triangleVertexNormals);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshGenerator::remesh(const std::vector<ObjectNode> &inputNodes,
|
|
||||||
const std::vector<std::tuple<QVector3D, float, size_t>> &interpolatedNodes,
|
|
||||||
const std::vector<QVector3D> &inputVertices,
|
|
||||||
const std::vector<std::vector<size_t>> &inputFaces,
|
|
||||||
float targetVertexMultiplyFactor,
|
|
||||||
std::vector<QVector3D> *outputVertices,
|
|
||||||
std::vector<std::vector<size_t>> *outputQuads,
|
|
||||||
std::vector<std::vector<size_t>> *outputTriangles,
|
|
||||||
std::vector<std::pair<QVector3D, std::pair<QUuid, QUuid>>> *outputNodeVertices)
|
|
||||||
{
|
|
||||||
std::vector<std::pair<QVector3D, float>> nodes;
|
|
||||||
std::vector<std::pair<QUuid, QUuid>> sourceIds;
|
|
||||||
nodes.reserve(interpolatedNodes.size());
|
|
||||||
sourceIds.reserve(interpolatedNodes.size());
|
|
||||||
for (const auto &it: interpolatedNodes) {
|
|
||||||
nodes.push_back(std::make_pair(std::get<0>(it), std::get<1>(it)));
|
|
||||||
const auto &sourceNode = inputNodes[std::get<2>(it)];
|
|
||||||
sourceIds.push_back(std::make_pair(sourceNode.partId, sourceNode.nodeId));
|
|
||||||
}
|
|
||||||
Remesher remesher;
|
|
||||||
remesher.setMesh(inputVertices, inputFaces);
|
|
||||||
remesher.setNodes(nodes, sourceIds);
|
|
||||||
remesher.remesh(targetVertexMultiplyFactor);
|
|
||||||
*outputVertices = remesher.getRemeshedVertices();
|
|
||||||
const auto &remeshedFaces = remesher.getRemeshedFaces();
|
|
||||||
*outputQuads = remeshedFaces;
|
|
||||||
outputTriangles->clear();
|
|
||||||
outputTriangles->reserve(remeshedFaces.size() * 2);
|
|
||||||
for (const auto &it: remeshedFaces) {
|
|
||||||
outputTriangles->push_back(std::vector<size_t> {
|
|
||||||
it[0], it[1], it[2]
|
|
||||||
});
|
|
||||||
if (4 == it.size()) {
|
|
||||||
outputTriangles->push_back(std::vector<size_t> {
|
|
||||||
it[2], it[3], it[0]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const auto &remeshedVertexSources = remesher.getRemeshedVertexSources();
|
|
||||||
outputNodeVertices->clear();
|
|
||||||
outputNodeVertices->reserve(outputVertices->size());
|
|
||||||
for (size_t i = 0; i < outputVertices->size(); ++i) {
|
|
||||||
const auto &vertexSource = remeshedVertexSources[i];
|
|
||||||
if (vertexSource.first.isNull())
|
|
||||||
continue;
|
|
||||||
outputNodeVertices->push_back(std::make_pair((*outputVertices)[i], vertexSource));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MeshGenerator::collectIncombinableComponentMeshes(const QString &componentIdString)
|
void MeshGenerator::collectIncombinableComponentMeshes(const QString &componentIdString)
|
||||||
{
|
{
|
||||||
const auto &component = findComponent(componentIdString);
|
const auto &component = findComponent(componentIdString);
|
||||||
|
@ -1786,8 +1655,6 @@ void MeshGenerator::generate()
|
||||||
|
|
||||||
m_dirtyComponentIds.insert(QUuid().toString());
|
m_dirtyComponentIds.insert(QUuid().toString());
|
||||||
|
|
||||||
bool remeshed = componentRemeshed(&m_snapshot->canvas);
|
|
||||||
|
|
||||||
CombineMode combineMode;
|
CombineMode combineMode;
|
||||||
auto combinedMesh = combineComponentMesh(QUuid().toString(), &combineMode);
|
auto combinedMesh = combineComponentMesh(QUuid().toString(), &combineMode);
|
||||||
|
|
||||||
|
@ -1802,7 +1669,6 @@ void MeshGenerator::generate()
|
||||||
if (nullptr != combinedMesh) {
|
if (nullptr != combinedMesh) {
|
||||||
combinedMesh->fetch(combinedVertices, combinedFaces);
|
combinedMesh->fetch(combinedVertices, combinedFaces);
|
||||||
if (m_weldEnabled) {
|
if (m_weldEnabled) {
|
||||||
if (!remeshed) {
|
|
||||||
size_t totalAffectedNum = 0;
|
size_t totalAffectedNum = 0;
|
||||||
size_t affectedNum = 0;
|
size_t affectedNum = 0;
|
||||||
do {
|
do {
|
||||||
|
@ -1816,7 +1682,6 @@ void MeshGenerator::generate()
|
||||||
totalAffectedNum += affectedNum;
|
totalAffectedNum += affectedNum;
|
||||||
} while (affectedNum > 0);
|
} while (affectedNum > 0);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
recoverQuads(combinedVertices, combinedFaces, componentCache.sharedQuadEdges, m_object->triangleAndQuads);
|
recoverQuads(combinedVertices, combinedFaces, componentCache.sharedQuadEdges, m_object->triangleAndQuads);
|
||||||
m_object->vertices = combinedVertices;
|
m_object->vertices = combinedVertices;
|
||||||
m_object->triangles = combinedFaces;
|
m_object->triangles = combinedFaces;
|
||||||
|
|
|
@ -163,22 +163,12 @@ private:
|
||||||
std::vector<std::vector<QVector3D>> *triangleVertexNormals);
|
std::vector<std::vector<QVector3D>> *triangleVertexNormals);
|
||||||
const std::map<QString, QString> *findComponent(const QString &componentIdString);
|
const std::map<QString, QString> *findComponent(const QString &componentIdString);
|
||||||
CombineMode componentCombineMode(const std::map<QString, QString> *component);
|
CombineMode componentCombineMode(const std::map<QString, QString> *component);
|
||||||
bool componentRemeshed(const std::map<QString, QString> *component, float *polyCountValue=nullptr);
|
|
||||||
MeshCombiner::Mesh *combineComponentChildGroupMesh(const std::vector<QString> &componentIdStrings,
|
MeshCombiner::Mesh *combineComponentChildGroupMesh(const std::vector<QString> &componentIdStrings,
|
||||||
GeneratedComponent &componentCache);
|
GeneratedComponent &componentCache);
|
||||||
MeshCombiner::Mesh *combineMultipleMeshes(const std::vector<std::tuple<MeshCombiner::Mesh *, CombineMode, QString>> &multipleMeshes, bool recombine=true);
|
MeshCombiner::Mesh *combineMultipleMeshes(const std::vector<std::tuple<MeshCombiner::Mesh *, CombineMode, QString>> &multipleMeshes, bool recombine=true);
|
||||||
QString componentColorName(const std::map<QString, QString> *component);
|
QString componentColorName(const std::map<QString, QString> *component);
|
||||||
void collectUncombinedComponent(const QString &componentIdString);
|
void collectUncombinedComponent(const QString &componentIdString);
|
||||||
void cutFaceStringToCutTemplate(const QString &cutFaceString, std::vector<QVector2D> &cutTemplate);
|
void cutFaceStringToCutTemplate(const QString &cutFaceString, std::vector<QVector2D> &cutTemplate);
|
||||||
void remesh(const std::vector<ObjectNode> &inputNodes,
|
|
||||||
const std::vector<std::tuple<QVector3D, float, size_t>> &interpolatedNodes,
|
|
||||||
const std::vector<QVector3D> &inputVertices,
|
|
||||||
const std::vector<std::vector<size_t>> &inputFaces,
|
|
||||||
float targetVertexMultiplyFactor,
|
|
||||||
std::vector<QVector3D> *outputVertices,
|
|
||||||
std::vector<std::vector<size_t>> *outputQuads,
|
|
||||||
std::vector<std::vector<size_t>> *outputTriangles,
|
|
||||||
std::vector<std::pair<QVector3D, std::pair<QUuid, QUuid>>> *outputNodeVertices);
|
|
||||||
void postprocessObject(Object *object);
|
void postprocessObject(Object *object);
|
||||||
void collectErroredParts();
|
void collectErroredParts();
|
||||||
void preprocessMirror();
|
void preprocessMirror();
|
||||||
|
|
|
@ -342,37 +342,10 @@ void PartTreeWidget::showContextMenu(const QPoint &pos, bool shorted)
|
||||||
layout->addWidget(previewLabel);
|
layout->addWidget(previewLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
QComboBox *polyCountSelectBox = nullptr;
|
|
||||||
QComboBox *combineModeSelectBox = nullptr;
|
QComboBox *combineModeSelectBox = nullptr;
|
||||||
QComboBox *partTargetSelectBox = nullptr;
|
QComboBox *partTargetSelectBox = nullptr;
|
||||||
QComboBox *partBaseSelectBox = nullptr;
|
QComboBox *partBaseSelectBox = nullptr;
|
||||||
|
|
||||||
if (componentIds.size() <= 1) {
|
|
||||||
if (nullptr == component) {
|
|
||||||
polyCountSelectBox = new QComboBox;
|
|
||||||
for (size_t i = 0; i < (size_t)PolyCount::Count; ++i) {
|
|
||||||
PolyCount count = (PolyCount)i;
|
|
||||||
polyCountSelectBox->addItem(PolyCountToDispName(count));
|
|
||||||
}
|
|
||||||
polyCountSelectBox->setCurrentIndex((int)m_document->polyCount);
|
|
||||||
connect(polyCountSelectBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, [=](int index) {
|
|
||||||
emit setComponentPolyCount(QUuid(), (PolyCount)index);
|
|
||||||
emit groupOperationAdded();
|
|
||||||
});
|
|
||||||
} else if (nullptr == part || part->hasPolyFunction()) {
|
|
||||||
polyCountSelectBox = new QComboBox;
|
|
||||||
for (size_t i = 0; i < (size_t)PolyCount::Count; ++i) {
|
|
||||||
PolyCount count = (PolyCount)i;
|
|
||||||
polyCountSelectBox->addItem(PolyCountToDispName(count));
|
|
||||||
}
|
|
||||||
polyCountSelectBox->setCurrentIndex((int)component->polyCount);
|
|
||||||
connect(polyCountSelectBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, [=](int index) {
|
|
||||||
emit setComponentPolyCount(component->id, (PolyCount)index);
|
|
||||||
emit groupOperationAdded();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nullptr != component) {
|
if (nullptr != component) {
|
||||||
|
|
||||||
if (nullptr == part || part->hasCombineModeFunction()) {
|
if (nullptr == part || part->hasCombineModeFunction()) {
|
||||||
|
@ -416,37 +389,6 @@ void PartTreeWidget::showContextMenu(const QPoint &pos, bool shorted)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (componentIds.size() > 1) {
|
if (componentIds.size() > 1) {
|
||||||
if (nullptr == polyCountSelectBox) {
|
|
||||||
std::set<PolyCount> polyCounts;
|
|
||||||
for (const auto &componentId: componentIds) {
|
|
||||||
const Component *oneComponent = m_document->findComponent(componentId);
|
|
||||||
if (nullptr == oneComponent)
|
|
||||||
continue;
|
|
||||||
polyCounts.insert(oneComponent->polyCount);
|
|
||||||
}
|
|
||||||
if (!polyCounts.empty()) {
|
|
||||||
int startIndex = (1 == polyCounts.size()) ? 0 : 1;
|
|
||||||
polyCountSelectBox = new QComboBox;
|
|
||||||
if (0 != startIndex)
|
|
||||||
polyCountSelectBox->addItem(tr("Not Change"));
|
|
||||||
for (size_t i = 0; i < (size_t)PolyCount::Count; ++i) {
|
|
||||||
PolyCount count = (PolyCount)i;
|
|
||||||
polyCountSelectBox->addItem(PolyCountToDispName(count));
|
|
||||||
}
|
|
||||||
if (0 != startIndex)
|
|
||||||
polyCountSelectBox->setCurrentIndex(0);
|
|
||||||
else
|
|
||||||
polyCountSelectBox->setCurrentIndex((int)*polyCounts.begin());
|
|
||||||
connect(polyCountSelectBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, [=](int index) {
|
|
||||||
if (index < startIndex)
|
|
||||||
return;
|
|
||||||
for (const auto &componentId: componentIds) {
|
|
||||||
emit setComponentPolyCount(componentId, (PolyCount)(index - startIndex));
|
|
||||||
}
|
|
||||||
emit groupOperationAdded();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nullptr == partBaseSelectBox) {
|
if (nullptr == partBaseSelectBox) {
|
||||||
std::set<PartBase> partBases;
|
std::set<PartBase> partBases;
|
||||||
|
@ -522,8 +464,6 @@ void PartTreeWidget::showContextMenu(const QPoint &pos, bool shorted)
|
||||||
QWidget *widget = new QWidget;
|
QWidget *widget = new QWidget;
|
||||||
QFormLayout *componentSettingsLayout = new QFormLayout;
|
QFormLayout *componentSettingsLayout = new QFormLayout;
|
||||||
|
|
||||||
if (nullptr != polyCountSelectBox)
|
|
||||||
componentSettingsLayout->addRow(tr("Poly"), polyCountSelectBox);
|
|
||||||
if (nullptr != partBaseSelectBox)
|
if (nullptr != partBaseSelectBox)
|
||||||
componentSettingsLayout->addRow(tr("Base"), partBaseSelectBox);
|
componentSettingsLayout->addRow(tr("Base"), partBaseSelectBox);
|
||||||
if (nullptr != partTargetSelectBox)
|
if (nullptr != partTargetSelectBox)
|
||||||
|
|
|
@ -23,7 +23,6 @@ signals:
|
||||||
void setComponentExpandState(QUuid componentId, bool expanded);
|
void setComponentExpandState(QUuid componentId, bool expanded);
|
||||||
void setComponentSmoothAll(QUuid componentId, float toSmoothAll);
|
void setComponentSmoothAll(QUuid componentId, float toSmoothAll);
|
||||||
void setComponentSmoothSeam(QUuid componentId, float toSmoothSeam);
|
void setComponentSmoothSeam(QUuid componentId, float toSmoothSeam);
|
||||||
void setComponentPolyCount(QUuid componentId, PolyCount count);
|
|
||||||
void setPartTarget(QUuid partId, PartTarget target);
|
void setPartTarget(QUuid partId, PartTarget target);
|
||||||
void setPartBase(QUuid partId, PartBase base);
|
void setPartBase(QUuid partId, PartBase base);
|
||||||
void moveComponent(QUuid componentId, QUuid toParentId);
|
void moveComponent(QUuid componentId, QUuid toParentId);
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
#include <QObject>
|
|
||||||
#include "polycount.h"
|
|
||||||
|
|
||||||
IMPL_PolyCountToString
|
|
||||||
IMPL_PolyCountFromString
|
|
||||||
IMPL_PolyCountToDispName
|
|
||||||
IMPL_PolyCountToValue
|
|
116
src/polycount.h
116
src/polycount.h
|
@ -1,116 +0,0 @@
|
||||||
#ifndef DUST3D_POLY_COUNT_H
|
|
||||||
#define DUST3D_POLY_COUNT_H
|
|
||||||
#include <QString>
|
|
||||||
|
|
||||||
enum class PolyCount
|
|
||||||
{
|
|
||||||
LowPoly,
|
|
||||||
Original,
|
|
||||||
MediumPoly,
|
|
||||||
HighPoly,
|
|
||||||
VeryHighPoly,
|
|
||||||
UltraHighPoly,
|
|
||||||
ExtremelyHighPoly,
|
|
||||||
TremendouslyHighPoly,
|
|
||||||
Count
|
|
||||||
};
|
|
||||||
PolyCount PolyCountFromString(const char *countString);
|
|
||||||
#define IMPL_PolyCountFromString \
|
|
||||||
PolyCount PolyCountFromString(const char *countString) \
|
|
||||||
{ \
|
|
||||||
QString count = countString; \
|
|
||||||
if (count == "LowPoly") \
|
|
||||||
return PolyCount::LowPoly; \
|
|
||||||
if (count == "Original") \
|
|
||||||
return PolyCount::Original; \
|
|
||||||
if (count == "MediumPoly") \
|
|
||||||
return PolyCount::MediumPoly; \
|
|
||||||
if (count == "HighPoly") \
|
|
||||||
return PolyCount::HighPoly; \
|
|
||||||
if (count == "VeryHighPoly") \
|
|
||||||
return PolyCount::VeryHighPoly; \
|
|
||||||
if (count == "UltraHighPoly") \
|
|
||||||
return PolyCount::UltraHighPoly; \
|
|
||||||
if (count == "ExtremelyHighPoly") \
|
|
||||||
return PolyCount::ExtremelyHighPoly; \
|
|
||||||
if (count == "TremendouslyHighPoly") \
|
|
||||||
return PolyCount::TremendouslyHighPoly; \
|
|
||||||
return PolyCount::Original; \
|
|
||||||
}
|
|
||||||
const char *PolyCountToString(PolyCount count);
|
|
||||||
#define IMPL_PolyCountToString \
|
|
||||||
const char *PolyCountToString(PolyCount count) \
|
|
||||||
{ \
|
|
||||||
switch (count) { \
|
|
||||||
case PolyCount::LowPoly: \
|
|
||||||
return "LowPoly"; \
|
|
||||||
case PolyCount::Original: \
|
|
||||||
return "Original"; \
|
|
||||||
case PolyCount::MediumPoly: \
|
|
||||||
return "MediumPoly"; \
|
|
||||||
case PolyCount::HighPoly: \
|
|
||||||
return "HighPoly"; \
|
|
||||||
case PolyCount::VeryHighPoly: \
|
|
||||||
return "VeryHighPoly"; \
|
|
||||||
case PolyCount::UltraHighPoly: \
|
|
||||||
return "UltraHighPoly"; \
|
|
||||||
case PolyCount::ExtremelyHighPoly: \
|
|
||||||
return "ExtremelyHighPoly"; \
|
|
||||||
case PolyCount::TremendouslyHighPoly: \
|
|
||||||
return "TremendouslyHighPoly"; \
|
|
||||||
default: \
|
|
||||||
return "Original"; \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
QString PolyCountToDispName(PolyCount count);
|
|
||||||
#define IMPL_PolyCountToDispName \
|
|
||||||
QString PolyCountToDispName(PolyCount count) \
|
|
||||||
{ \
|
|
||||||
switch (count) { \
|
|
||||||
case PolyCount::LowPoly: \
|
|
||||||
return QObject::tr("Low Poly"); \
|
|
||||||
case PolyCount::Original: \
|
|
||||||
return QObject::tr("Original"); \
|
|
||||||
case PolyCount::MediumPoly: \
|
|
||||||
return QObject::tr("Medium Poly"); \
|
|
||||||
case PolyCount::HighPoly: \
|
|
||||||
return QObject::tr("High Poly"); \
|
|
||||||
case PolyCount::VeryHighPoly: \
|
|
||||||
return QObject::tr("Very High Poly"); \
|
|
||||||
case PolyCount::UltraHighPoly: \
|
|
||||||
return QObject::tr("Ultra High Poly"); \
|
|
||||||
case PolyCount::ExtremelyHighPoly: \
|
|
||||||
return QObject::tr("Extremely High Poly"); \
|
|
||||||
case PolyCount::TremendouslyHighPoly: \
|
|
||||||
return QObject::tr("Tremendously High Poly"); \
|
|
||||||
default: \
|
|
||||||
return QObject::tr("Original"); \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
float PolyCountToValue(PolyCount count);
|
|
||||||
#define IMPL_PolyCountToValue \
|
|
||||||
float PolyCountToValue(PolyCount count) \
|
|
||||||
{ \
|
|
||||||
switch (count) { \
|
|
||||||
case PolyCount::LowPoly: \
|
|
||||||
return 0.6f; \
|
|
||||||
case PolyCount::Original: \
|
|
||||||
return 1.0f; \
|
|
||||||
case PolyCount::MediumPoly: \
|
|
||||||
return 1.2f; \
|
|
||||||
case PolyCount::HighPoly: \
|
|
||||||
return 2.4f; \
|
|
||||||
case PolyCount::VeryHighPoly: \
|
|
||||||
return 4.8f; \
|
|
||||||
case PolyCount::UltraHighPoly: \
|
|
||||||
return 9.6f; \
|
|
||||||
case PolyCount::ExtremelyHighPoly: \
|
|
||||||
return 19.2f; \
|
|
||||||
case PolyCount::TremendouslyHighPoly: \
|
|
||||||
return 38.4f; \
|
|
||||||
default: \
|
|
||||||
return 1.0f; \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,76 +0,0 @@
|
||||||
#include <tbb/parallel_for.h>
|
|
||||||
#include <tbb/blocked_range.h>
|
|
||||||
#include <cmath>
|
|
||||||
#include "projectfacestonodes.h"
|
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
class FacesToNearestNodesProjector
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
FacesToNearestNodesProjector(const std::vector<QVector3D> *vertices,
|
|
||||||
const std::vector<std::vector<size_t>> *faces,
|
|
||||||
const std::vector<std::pair<QVector3D, float>> *sourceNodes,
|
|
||||||
std::vector<size_t> *faceSources) :
|
|
||||||
m_vertices(vertices),
|
|
||||||
m_faces(faces),
|
|
||||||
m_sourceNodes(sourceNodes),
|
|
||||||
m_faceSources(faceSources)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
bool test(const std::vector<size_t> &face,
|
|
||||||
const QVector3D &nodePosition,
|
|
||||||
float nodeRadius,
|
|
||||||
float *distance) const
|
|
||||||
{
|
|
||||||
QVector3D faceCenter;
|
|
||||||
for (const auto &it: face) {
|
|
||||||
faceCenter += (*m_vertices)[it];
|
|
||||||
}
|
|
||||||
if (face.size() > 0)
|
|
||||||
faceCenter /= face.size();
|
|
||||||
auto ray = (nodePosition - faceCenter).normalized();
|
|
||||||
auto inversedFaceNormal = -polygonNormal(*m_vertices, face);
|
|
||||||
*distance = (faceCenter - nodePosition).length();
|
|
||||||
if (*distance > nodeRadius * 1.5f)
|
|
||||||
return false;
|
|
||||||
if (QVector3D::dotProduct(ray, inversedFaceNormal) < 0.707) { // 45 degrees
|
|
||||||
if (*distance > nodeRadius * 1.01f)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
void operator()(const tbb::blocked_range<size_t> &range) const
|
|
||||||
{
|
|
||||||
for (size_t i = range.begin(); i != range.end(); ++i) {
|
|
||||||
std::vector<std::pair<size_t, float>> distanceWithNodes;
|
|
||||||
for (size_t j = 0; j < m_sourceNodes->size(); ++j) {
|
|
||||||
const auto &node = (*m_sourceNodes)[j];
|
|
||||||
float distance = 0.0f;
|
|
||||||
if (!test((*m_faces)[i], node.first, node.second, &distance))
|
|
||||||
continue;
|
|
||||||
distanceWithNodes.push_back(std::make_pair(j, distance));
|
|
||||||
}
|
|
||||||
if (distanceWithNodes.empty())
|
|
||||||
continue;
|
|
||||||
(*m_faceSources)[i] = std::min_element(distanceWithNodes.begin(), distanceWithNodes.end(), [](const std::pair<size_t, float> &first, const std::pair<size_t, float> &second) {
|
|
||||||
return first.second < second.second;
|
|
||||||
})->first;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
const std::vector<QVector3D> *m_vertices = nullptr;
|
|
||||||
const std::vector<std::vector<size_t>> *m_faces = nullptr;
|
|
||||||
const std::vector<std::pair<QVector3D, float>> *m_sourceNodes = nullptr;
|
|
||||||
std::vector<size_t> *m_faceSources = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
void projectFacesToNodes(const std::vector<QVector3D> &vertices,
|
|
||||||
const std::vector<std::vector<size_t>> &faces,
|
|
||||||
const std::vector<std::pair<QVector3D, float>> &sourceNodes,
|
|
||||||
std::vector<size_t> *faceSources)
|
|
||||||
{
|
|
||||||
// Resolve the faces's source nodes
|
|
||||||
faceSources->resize(faces.size(), std::numeric_limits<size_t>::max());
|
|
||||||
tbb::parallel_for(tbb::blocked_range<size_t>(0, faces.size()),
|
|
||||||
FacesToNearestNodesProjector(&vertices, &faces, &sourceNodes, faceSources));
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
#ifndef DUST3D_PROJECT_TRIANGLES_TO_NODES_H
|
|
||||||
#define DUST3D_PROJECT_TRIANGLES_TO_NODES_H
|
|
||||||
#include <QVector3D>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
void projectFacesToNodes(const std::vector<QVector3D> &vertices,
|
|
||||||
const std::vector<std::vector<size_t>> &faces,
|
|
||||||
const std::vector<std::pair<QVector3D, float>> &sourceNodes,
|
|
||||||
std::vector<size_t> *faceSources);
|
|
||||||
|
|
||||||
#endif
|
|
131
src/remesher.cpp
131
src/remesher.cpp
|
@ -1,131 +0,0 @@
|
||||||
#include <instant-meshes-api.h>
|
|
||||||
#include <cmath>
|
|
||||||
#include <QElapsedTimer>
|
|
||||||
#include "remesher.h"
|
|
||||||
#include "util.h"
|
|
||||||
#include "projectfacestonodes.h"
|
|
||||||
|
|
||||||
Remesher::Remesher()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Remesher::~Remesher()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Remesher::setMesh(const std::vector<QVector3D> &vertices,
|
|
||||||
const std::vector<std::vector<size_t>> &triangles)
|
|
||||||
{
|
|
||||||
m_vertices = vertices;
|
|
||||||
m_triangles = triangles;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<QVector3D> &Remesher::getRemeshedVertices() const
|
|
||||||
{
|
|
||||||
return m_remeshedVertices;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<std::vector<size_t>> &Remesher::getRemeshedFaces() const
|
|
||||||
{
|
|
||||||
return m_remeshedFaces;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<std::pair<QUuid, QUuid>> &Remesher::getRemeshedVertexSources() const
|
|
||||||
{
|
|
||||||
return m_remeshedVertexSources;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Remesher::remesh(float targetVertexMultiplyFactor)
|
|
||||||
{
|
|
||||||
std::vector<Dust3D_InstantMeshesVertex> inputVertices(m_vertices.size());
|
|
||||||
for (size_t i = 0; i < m_vertices.size(); ++i) {
|
|
||||||
const auto &vertex = m_vertices[i];
|
|
||||||
inputVertices[i] = Dust3D_InstantMeshesVertex {
|
|
||||||
vertex.x(), vertex.y(), vertex.z()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
std::vector<Dust3D_InstantMeshesTriangle> inputTriangles;
|
|
||||||
inputTriangles.reserve(m_triangles.size());
|
|
||||||
float totalArea = 0.0f;
|
|
||||||
for (size_t i = 0; i < m_triangles.size(); ++i) {
|
|
||||||
const auto &triangle = m_triangles[i];
|
|
||||||
if (triangle.size() != 3)
|
|
||||||
continue;
|
|
||||||
inputTriangles.push_back(Dust3D_InstantMeshesTriangle {{
|
|
||||||
triangle[0],
|
|
||||||
triangle[1],
|
|
||||||
triangle[2]
|
|
||||||
}});
|
|
||||||
totalArea += areaOfTriangle(m_vertices[triangle[0]], m_vertices[triangle[1]], m_vertices[triangle[2]]);
|
|
||||||
}
|
|
||||||
const Dust3D_InstantMeshesVertex *resultVertices = nullptr;
|
|
||||||
size_t nResultVertices = 0;
|
|
||||||
const Dust3D_InstantMeshesTriangle *resultTriangles = nullptr;
|
|
||||||
size_t nResultTriangles = 0;
|
|
||||||
const Dust3D_InstantMeshesQuad *resultQuads = nullptr;
|
|
||||||
size_t nResultQuads = 0;
|
|
||||||
Dust3D_instantMeshesRemesh(inputVertices.data(), inputVertices.size(),
|
|
||||||
inputTriangles.data(), inputTriangles.size(),
|
|
||||||
(size_t)(targetVertexMultiplyFactor * 30 * std::sqrt(totalArea) / 0.02f),
|
|
||||||
&resultVertices,
|
|
||||||
&nResultVertices,
|
|
||||||
&resultTriangles,
|
|
||||||
&nResultTriangles,
|
|
||||||
&resultQuads,
|
|
||||||
&nResultQuads);
|
|
||||||
m_remeshedVertices.resize(nResultVertices);
|
|
||||||
memcpy(m_remeshedVertices.data(), resultVertices, sizeof(Dust3D_InstantMeshesVertex) * nResultVertices);
|
|
||||||
m_remeshedFaces.reserve(nResultTriangles + nResultQuads);
|
|
||||||
for (size_t i = 0; i < nResultTriangles; ++i) {
|
|
||||||
const auto &source = resultTriangles[i];
|
|
||||||
m_remeshedFaces.push_back(std::vector<size_t> {
|
|
||||||
source.indices[0],
|
|
||||||
source.indices[1],
|
|
||||||
source.indices[2]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
for (size_t i = 0; i < nResultQuads; ++i) {
|
|
||||||
const auto &source = resultQuads[i];
|
|
||||||
m_remeshedFaces.push_back(std::vector<size_t> {
|
|
||||||
source.indices[0],
|
|
||||||
source.indices[1],
|
|
||||||
source.indices[2],
|
|
||||||
source.indices[3]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
resolveSources();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Remesher::setNodes(const std::vector<std::pair<QVector3D, float>> &nodes,
|
|
||||||
const std::vector<std::pair<QUuid, QUuid>> &sourceIds)
|
|
||||||
{
|
|
||||||
m_nodes = nodes;
|
|
||||||
m_sourceIds = sourceIds;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Remesher::resolveSources()
|
|
||||||
{
|
|
||||||
QElapsedTimer timer;
|
|
||||||
timer.start();
|
|
||||||
std::vector<size_t> faceSources;
|
|
||||||
auto projectFacesToNodesStartTime = timer.elapsed();
|
|
||||||
projectFacesToNodes(m_remeshedVertices, m_remeshedFaces, m_nodes, &faceSources);
|
|
||||||
auto projectFacesToNodesStopTime = timer.elapsed();
|
|
||||||
qDebug() << "Project faces to nodes took" << (projectFacesToNodesStopTime - projectFacesToNodesStartTime) << "milliseconds";
|
|
||||||
std::map<size_t, std::map<size_t, size_t>> vertexToNodeVotes;
|
|
||||||
for (size_t i = 0; i < m_remeshedFaces.size(); ++i) {
|
|
||||||
const auto &face = m_remeshedFaces[i];
|
|
||||||
const auto &source = faceSources[i];
|
|
||||||
if (source >= m_nodes.size())
|
|
||||||
continue;
|
|
||||||
for (const auto &vertexIndex: face)
|
|
||||||
vertexToNodeVotes[vertexIndex][source]++;
|
|
||||||
}
|
|
||||||
m_remeshedVertexSources.resize(m_remeshedVertices.size());
|
|
||||||
for (const auto &it: vertexToNodeVotes) {
|
|
||||||
auto sourceIndex = std::max_element(it.second.begin(), it.second.end(), [](const std::pair<size_t, size_t> &first, const std::pair<size_t, size_t> &second) {
|
|
||||||
return first.second < second.second;
|
|
||||||
})->first;
|
|
||||||
m_remeshedVertexSources[it.first] = m_sourceIds[sourceIndex];
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
#ifndef DUST3D_REMESHER_H
|
|
||||||
#define DUST3D_REMESHER_H
|
|
||||||
#include <QObject>
|
|
||||||
#include <vector>
|
|
||||||
#include <QVector3D>
|
|
||||||
#include <QUuid>
|
|
||||||
|
|
||||||
class Remesher : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
Remesher();
|
|
||||||
~Remesher();
|
|
||||||
void setMesh(const std::vector<QVector3D> &vertices,
|
|
||||||
const std::vector<std::vector<size_t>> &triangles);
|
|
||||||
void setNodes(const std::vector<std::pair<QVector3D, float>> &nodes,
|
|
||||||
const std::vector<std::pair<QUuid, QUuid>> &sourceIds);
|
|
||||||
void remesh(float targetVertexMultiplyFactor);
|
|
||||||
const std::vector<QVector3D> &getRemeshedVertices() const;
|
|
||||||
const std::vector<std::vector<size_t>> &getRemeshedFaces() const;
|
|
||||||
const std::vector<std::pair<QUuid, QUuid>> &getRemeshedVertexSources() const;
|
|
||||||
private:
|
|
||||||
std::vector<QVector3D> m_vertices;
|
|
||||||
std::vector<std::vector<size_t>> m_triangles;
|
|
||||||
std::vector<QVector3D> m_remeshedVertices;
|
|
||||||
std::vector<std::vector<size_t>> m_remeshedFaces;
|
|
||||||
std::vector<std::pair<QUuid, QUuid>> m_remeshedVertexSources;
|
|
||||||
std::vector<std::pair<QVector3D, float>> m_nodes;
|
|
||||||
std::vector<std::pair<QUuid, QUuid>> m_sourceIds;
|
|
||||||
void resolveSources();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
Loading…
Reference in New Issue