Remove poly count

master
huxingyi 2020-12-17 23:16:49 +09:30
parent 62418b9340
commit 1e7057bd90
14 changed files with 12 additions and 637 deletions

View File

@ -341,9 +341,6 @@ HEADERS += src/skeletondocument.h
SOURCES += src/combinemode.cpp
HEADERS += src/combinemode.h
SOURCES += src/polycount.cpp
HEADERS += src/polycount.h
SOURCES += src/cutface.cpp
HEADERS += src/cutface.h
@ -430,15 +427,9 @@ HEADERS += src/triangulatefaces.h
SOURCES += src/booleanmesh.cpp
HEADERS += src/booleanmesh.h
SOURCES += src/remesher.cpp
HEADERS += src/remesher.h
SOURCES += src/isotropicremesh.cpp
HEADERS += src/isotropicremesh.h
SOURCES += src/projectfacestonodes.cpp
HEADERS += src/projectfacestonodes.h
SOURCES += src/ddsfile.cpp
HEADERS += src/ddsfile.h

View File

@ -37,7 +37,6 @@ Document::Document() :
textureAmbientOcclusionImageByteArray(nullptr),
rigType(RigType::None),
weldEnabled(true),
polyCount(PolyCount::Original),
brushColor(Qt::white),
objectLocked(false),
// private
@ -1226,8 +1225,6 @@ void Document::toSnapshot(Snapshot *snapshot, const std::set<QUuid> &limitNodeId
component["smoothAll"] = QString::number(componentIt.second.smoothAll);
if (componentIt.second.smoothSeamAdjusted())
component["smoothSeam"] = QString::number(componentIt.second.smoothSeam);
if (componentIt.second.polyCount != PolyCount::Original)
component["polyCount"] = PolyCountToString(componentIt.second.polyCount);
QStringList childIdList;
for (const auto &childId: componentIt.second.childrenIds) {
childIdList.append(childId.toString());
@ -1306,8 +1303,6 @@ void Document::toSnapshot(Snapshot *snapshot, const std::set<QUuid> &limitNodeId
canvas["originY"] = QString::number(getOriginY());
canvas["originZ"] = QString::number(getOriginZ());
canvas["rigType"] = RigTypeToString(rigType);
if (this->polyCount != PolyCount::Original)
canvas["polyCount"] = PolyCountToString(this->polyCount);
if (this->objectLocked)
canvas["objectLocked"] = "true";
snapshot->canvas = canvas;
@ -1412,7 +1407,6 @@ void Document::addFromSnapshot(const Snapshot &snapshot, enum SnapshotSource sou
bool isMeshLockedChanged = false;
if (SnapshotSource::Paste != source &&
SnapshotSource::Import != source) {
this->polyCount = PolyCountFromString(valueOfKeyInMapOrEmpty(snapshot.canvas, "polyCount").toUtf8().constData());
const auto &originXit = snapshot.canvas.find("originX");
const auto &originYit = snapshot.canvas.find("originY");
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");
if (smoothSeamIt != componentKv.second.end())
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;
if ("partId" == linkDataType) {
QUuid partId = oldNewIdMap[QUuid(linkData)];
@ -2460,29 +2453,6 @@ void Document::setComponentExpandState(QUuid componentId, bool expanded)
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)
{
auto component = componentMap.find(componentId);

View File

@ -22,7 +22,6 @@
#include "jointnodetree.h"
#include "skeletondocument.h"
#include "combinemode.h"
#include "polycount.h"
#include "preferences.h"
#include "paintmode.h"
#include "proceduralanimation.h"
@ -64,7 +63,6 @@ public:
bool dirty = true;
float smoothAll = 0.0;
float smoothSeam = 0.0;
PolyCount polyCount = PolyCount::Original;
std::vector<QUuid> childrenIds;
QString linkData() const
{
@ -287,7 +285,6 @@ signals:
void componentExpandStateChanged(QUuid componentId);
void componentSmoothAllChanged(QUuid componentId);
void componentSmoothSeamChanged(QUuid componentId);
void componentPolyCountChanged(QUuid componentId);
void componentLayerChanged(QUuid componentId);
void nodeRemoved(QUuid nodeId);
void edgeRemoved(QUuid edgeId);
@ -398,7 +395,6 @@ public: // need initialize
QByteArray *textureAmbientOcclusionImageByteArray;
RigType rigType;
bool weldEnabled;
PolyCount polyCount;
QColor brushColor;
bool objectLocked;
float brushMetalness = Model::m_defaultMetalness;
@ -555,7 +551,6 @@ public slots:
void setComponentExpandState(QUuid componentId, bool expanded);
void setComponentSmoothAll(QUuid componentId, float toSmoothAll);
void setComponentSmoothSeam(QUuid componentId, float toSmoothSeam);
void setComponentPolyCount(QUuid componentId, PolyCount count);
void hideOtherComponents(QUuid componentId);
void lockOtherComponents(QUuid componentId);
void hideAllComponents();

View File

@ -986,7 +986,6 @@ DocumentWindow::DocumentWindow() :
connect(m_partTreeWidget, &PartTreeWidget::setComponentExpandState, m_document, &Document::setComponentExpandState);
connect(m_partTreeWidget, &PartTreeWidget::setComponentSmoothAll, m_document, &Document::setComponentSmoothAll);
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::removeComponent, m_document, &Document::removeComponent);
connect(m_partTreeWidget, &PartTreeWidget::hideOtherComponents, m_document, &Document::hideOtherComponents);

View File

@ -15,10 +15,7 @@
#include "partbase.h"
#include "imageforever.h"
#include "triangulatefaces.h"
#include "remesher.h"
#include "polycount.h"
#include "isotropicremesh.h"
#include "projectfacestonodes.h"
#include "document.h"
#include "meshstroketifier.h"
#include "fileforever.h"
@ -911,22 +908,10 @@ CombineMode MeshGenerator::componentCombineMode(const std::map<QString, QString>
if (combineMode == CombineMode::Normal) {
if (isTrueValueString(valueOfKeyInMapOrEmpty(*component, "inverse")))
combineMode = CombineMode::Inversion;
if (componentRemeshed(component))
combineMode = CombineMode::Uncombined;
}
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)
{
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;
}
@ -1463,55 +1381,6 @@ void MeshGenerator::postprocessObject(Object *object)
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)
{
const auto &component = findComponent(componentIdString);
@ -1786,8 +1655,6 @@ void MeshGenerator::generate()
m_dirtyComponentIds.insert(QUuid().toString());
bool remeshed = componentRemeshed(&m_snapshot->canvas);
CombineMode combineMode;
auto combinedMesh = combineComponentMesh(QUuid().toString(), &combineMode);
@ -1802,7 +1669,6 @@ void MeshGenerator::generate()
if (nullptr != combinedMesh) {
combinedMesh->fetch(combinedVertices, combinedFaces);
if (m_weldEnabled) {
if (!remeshed) {
size_t totalAffectedNum = 0;
size_t affectedNum = 0;
do {
@ -1816,7 +1682,6 @@ void MeshGenerator::generate()
totalAffectedNum += affectedNum;
} while (affectedNum > 0);
}
}
recoverQuads(combinedVertices, combinedFaces, componentCache.sharedQuadEdges, m_object->triangleAndQuads);
m_object->vertices = combinedVertices;
m_object->triangles = combinedFaces;

View File

@ -163,22 +163,12 @@ private:
std::vector<std::vector<QVector3D>> *triangleVertexNormals);
const std::map<QString, QString> *findComponent(const QString &componentIdString);
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,
GeneratedComponent &componentCache);
MeshCombiner::Mesh *combineMultipleMeshes(const std::vector<std::tuple<MeshCombiner::Mesh *, CombineMode, QString>> &multipleMeshes, bool recombine=true);
QString componentColorName(const std::map<QString, QString> *component);
void collectUncombinedComponent(const QString &componentIdString);
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 collectErroredParts();
void preprocessMirror();

View File

@ -342,37 +342,10 @@ void PartTreeWidget::showContextMenu(const QPoint &pos, bool shorted)
layout->addWidget(previewLabel);
}
QComboBox *polyCountSelectBox = nullptr;
QComboBox *combineModeSelectBox = nullptr;
QComboBox *partTargetSelectBox = 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 == part || part->hasCombineModeFunction()) {
@ -416,37 +389,6 @@ void PartTreeWidget::showContextMenu(const QPoint &pos, bool shorted)
}
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) {
std::set<PartBase> partBases;
@ -522,8 +464,6 @@ void PartTreeWidget::showContextMenu(const QPoint &pos, bool shorted)
QWidget *widget = new QWidget;
QFormLayout *componentSettingsLayout = new QFormLayout;
if (nullptr != polyCountSelectBox)
componentSettingsLayout->addRow(tr("Poly"), polyCountSelectBox);
if (nullptr != partBaseSelectBox)
componentSettingsLayout->addRow(tr("Base"), partBaseSelectBox);
if (nullptr != partTargetSelectBox)

View File

@ -23,7 +23,6 @@ signals:
void setComponentExpandState(QUuid componentId, bool expanded);
void setComponentSmoothAll(QUuid componentId, float toSmoothAll);
void setComponentSmoothSeam(QUuid componentId, float toSmoothSeam);
void setComponentPolyCount(QUuid componentId, PolyCount count);
void setPartTarget(QUuid partId, PartTarget target);
void setPartBase(QUuid partId, PartBase base);
void moveComponent(QUuid componentId, QUuid toParentId);

View File

@ -1,7 +0,0 @@
#include <QObject>
#include "polycount.h"
IMPL_PolyCountToString
IMPL_PolyCountFromString
IMPL_PolyCountToDispName
IMPL_PolyCountToValue

View File

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

View File

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

View File

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

View File

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

View File

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