Remove poly count
parent
62418b9340
commit
1e7057bd90
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,20 +1669,18 @@ void MeshGenerator::generate()
|
|||
if (nullptr != combinedMesh) {
|
||||
combinedMesh->fetch(combinedVertices, combinedFaces);
|
||||
if (m_weldEnabled) {
|
||||
if (!remeshed) {
|
||||
size_t totalAffectedNum = 0;
|
||||
size_t affectedNum = 0;
|
||||
do {
|
||||
std::vector<QVector3D> weldedVertices;
|
||||
std::vector<std::vector<size_t>> weldedFaces;
|
||||
affectedNum = weldSeam(combinedVertices, combinedFaces,
|
||||
0.025, componentCache.noneSeamVertices,
|
||||
weldedVertices, weldedFaces);
|
||||
combinedVertices = weldedVertices;
|
||||
combinedFaces = weldedFaces;
|
||||
totalAffectedNum += affectedNum;
|
||||
} while (affectedNum > 0);
|
||||
}
|
||||
size_t totalAffectedNum = 0;
|
||||
size_t affectedNum = 0;
|
||||
do {
|
||||
std::vector<QVector3D> weldedVertices;
|
||||
std::vector<std::vector<size_t>> weldedFaces;
|
||||
affectedNum = weldSeam(combinedVertices, combinedFaces,
|
||||
0.025, componentCache.noneSeamVertices,
|
||||
weldedVertices, weldedFaces);
|
||||
combinedVertices = weldedVertices;
|
||||
combinedFaces = weldedFaces;
|
||||
totalAffectedNum += affectedNum;
|
||||
} while (affectedNum > 0);
|
||||
}
|
||||
recoverQuads(combinedVertices, combinedFaces, componentCache.sharedQuadEdges, m_object->triangleAndQuads);
|
||||
m_object->vertices = combinedVertices;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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