Implement component remesh

master
Jeremy Hu 2019-12-29 18:22:35 +09:30
parent 6875bee519
commit 191dbacd89
13 changed files with 291 additions and 64 deletions

View File

@ -736,6 +736,10 @@ Tips:
<source>Paste Color</source>
<translation></translation>
</message>
<message>
<source>Remeshed</source>
<translation></translation>
</message>
</context>
<context>
<name>PartWidget</name>

View File

@ -37,6 +37,7 @@ Document::Document() :
textureAmbientOcclusionImage(nullptr),
rigType(RigType::None),
weldEnabled(true),
remeshed(false),
// private
m_isResultMeshObsolete(false),
m_meshGenerator(nullptr),
@ -1201,6 +1202,8 @@ 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.remeshed)
component["remeshed"] = "true";
QStringList childIdList;
for (const auto &childId: componentIt.second.childrenIds) {
childIdList.append(childId.toString());
@ -1315,6 +1318,8 @@ 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->remeshed)
canvas["remeshed"] = "true";
snapshot->canvas = canvas;
}
}
@ -1472,6 +1477,7 @@ void Document::addFromSnapshot(const Snapshot &snapshot, bool fromPaste)
bool isOriginChanged = false;
bool isRigTypeChanged = false;
if (!fromPaste) {
this->remeshed = isTrueValueString(valueOfKeyInMapOrEmpty(snapshot.canvas, "remeshed"));
const auto &originXit = snapshot.canvas.find("originX");
const auto &originYit = snapshot.canvas.find("originY");
const auto &originZit = snapshot.canvas.find("originZ");
@ -1704,6 +1710,7 @@ void Document::addFromSnapshot(const Snapshot &snapshot, bool fromPaste)
const auto &smoothSeamIt = componentKv.second.find("smoothSeam");
if (smoothSeamIt != componentKv.second.end())
component.setSmoothSeam(smoothSeamIt->second.toFloat());
component.remeshed = isTrueValueString(valueOfKeyInMapOrEmpty(componentKv.second, "remeshed"));
//qDebug() << "Add component:" << component.id << " old:" << componentKv.first << "name:" << component.name;
if ("partId" == linkDataType) {
QUuid partId = oldNewIdMap[QUuid(linkData)];
@ -2488,6 +2495,29 @@ void Document::setComponentExpandState(QUuid componentId, bool expanded)
emit optionsChanged();
}
void Document::setComponentRemeshState(QUuid componentId, bool remeshed)
{
if (componentId.isNull()) {
if (this->remeshed == remeshed)
return;
this->remeshed = remeshed;
emit componentRemeshStateChanged(componentId);
emit skeletonChanged();
return;
}
Component *component = (Component *)findComponent(componentId);
if (nullptr == component)
return;
if (component->remeshed == remeshed)
return;
component->remeshed = remeshed;
component->dirty = true;
emit componentRemeshStateChanged(componentId);
emit skeletonChanged();
}
void Document::createNewComponentAndMoveThisIn(QUuid componentId)
{
auto component = componentMap.find(componentId);

View File

@ -66,6 +66,7 @@ public:
bool dirty = true;
float smoothAll = 0.0;
float smoothSeam = 0.0;
bool remeshed = false;
std::vector<QUuid> childrenIds;
QString linkData() const
{
@ -394,6 +395,7 @@ signals:
void componentExpandStateChanged(QUuid componentId);
void componentSmoothAllChanged(QUuid componentId);
void componentSmoothSeamChanged(QUuid componentId);
void componentRemeshStateChanged(QUuid componentId);
void nodeRemoved(QUuid nodeId);
void edgeRemoved(QUuid edgeId);
void nodeRadiusChanged(QUuid nodeId);
@ -503,6 +505,7 @@ public: // need initialize
QImage *textureAmbientOcclusionImage;
RigType rigType;
bool weldEnabled;
bool remeshed;
public:
Document();
~Document();
@ -647,6 +650,7 @@ public slots:
void setComponentExpandState(QUuid componentId, bool expanded);
void setComponentSmoothAll(QUuid componentId, float toSmoothAll);
void setComponentSmoothSeam(QUuid componentId, float toSmoothSeam);
void setComponentRemeshState(QUuid componentId, bool remeshed);
void hideOtherComponents(QUuid componentId);
void lockOtherComponents(QUuid componentId);
void hideAllComponents();

View File

@ -997,6 +997,7 @@ DocumentWindow::DocumentWindow() :
connect(partTreeWidget, &PartTreeWidget::setComponentExpandState, m_document, &Document::setComponentExpandState);
connect(partTreeWidget, &PartTreeWidget::setComponentSmoothAll, m_document, &Document::setComponentSmoothAll);
connect(partTreeWidget, &PartTreeWidget::setComponentSmoothSeam, m_document, &Document::setComponentSmoothSeam);
connect(partTreeWidget, &PartTreeWidget::setComponentRemeshState, m_document, &Document::setComponentRemeshState);
connect(partTreeWidget, &PartTreeWidget::moveComponent, m_document, &Document::moveComponent);
connect(partTreeWidget, &PartTreeWidget::removeComponent, m_document, &Document::removeComponent);
connect(partTreeWidget, &PartTreeWidget::hideOtherComponents, m_document, &Document::hideOtherComponents);

View File

@ -10,7 +10,7 @@
typedef CGAL::Exact_predicates_inexact_constructions_kernel CgalKernel;
typedef CGAL::Surface_mesh<CgalKernel::Point_3> CgalMesh;
MeshCombiner::Mesh::Mesh(const std::vector<QVector3D> &vertices, const std::vector<std::vector<size_t>> &faces, bool removeSelfIntersects)
MeshCombiner::Mesh::Mesh(const std::vector<QVector3D> &vertices, const std::vector<std::vector<size_t>> &faces, bool disableSelfIntersects)
{
CgalMesh *cgalMesh = nullptr;
if (!faces.empty()) {
@ -21,15 +21,9 @@ MeshCombiner::Mesh::Mesh(const std::vector<QVector3D> &vertices, const std::vect
cgalMesh = nullptr;
} else {
if (CGAL::Polygon_mesh_processing::triangulate_faces(*cgalMesh)) {
if (CGAL::Polygon_mesh_processing::does_self_intersect(*cgalMesh)) {
m_isSelfIntersected = true;
if (removeSelfIntersects) {
if (!CGAL::Polygon_mesh_processing::remove_self_intersections(*cgalMesh)) {
qDebug() << "Mesh remove_self_intersections failed";
delete cgalMesh;
cgalMesh = nullptr;
}
} else {
if (!disableSelfIntersects) {
if (CGAL::Polygon_mesh_processing::does_self_intersect(*cgalMesh)) {
m_isSelfIntersected = true;
qDebug() << "Mesh does_self_intersect";
delete cgalMesh;
cgalMesh = nullptr;

View File

@ -23,7 +23,7 @@ public:
{
public:
Mesh() = default;
Mesh(const std::vector<QVector3D> &vertices, const std::vector<std::vector<size_t>> &faces, bool removeSelfIntersects=true);
Mesh(const std::vector<QVector3D> &vertices, const std::vector<std::vector<size_t>> &faces, bool disableSelfIntersects=true);
Mesh(const Mesh &other);
~Mesh();
void fetch(std::vector<QVector3D> &vertices, std::vector<std::vector<size_t>> &faces) const;

View File

@ -838,6 +838,13 @@ CombineMode MeshGenerator::componentCombineMode(const std::map<QString, QString>
return combineMode;
}
bool MeshGenerator::componentRemeshed(const std::map<QString, QString> *component)
{
if (nullptr == component)
return false;
return isTrueValueString(valueOfKeyInMapOrEmpty(*component, "remeshed"));
}
QString MeshGenerator::componentColorName(const std::map<QString, QString> *component)
{
if (nullptr == component)
@ -1019,6 +1026,44 @@ MeshCombiner::Mesh *MeshGenerator::combineComponentMesh(const QString &component
mesh = nullptr;
}
if (nullptr != mesh) {
bool remeshed = componentId.isNull() ? componentRemeshed(&m_snapshot->canvas) : componentRemeshed(component);
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;
remesh(componentCache.outcomeNodes,
combinedVertices,
combinedFaces,
&newVertices,
&newQuads,
&newTriangles,
&componentCache.outcomeNodeVertices);
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 = new MeshCombiner::Mesh(newVertices, newTriangles, componentId.isNull());
if (nullptr != mesh) {
delete componentCache.mesh;
componentCache.mesh = new MeshCombiner::Mesh(*mesh);
}
}
}
return mesh;
}
@ -1280,6 +1325,8 @@ void MeshGenerator::generate()
m_mainProfileMiddleY = valueOfKeyInMapOrEmpty(m_snapshot->canvas, "originY").toFloat();
m_sideProfileMiddleX = valueOfKeyInMapOrEmpty(m_snapshot->canvas, "originZ").toFloat();
bool remeshed = componentRemeshed(&m_snapshot->canvas);
CombineMode combineMode;
auto combinedMesh = combineComponentMesh(QUuid().toString(), &combineMode);
@ -1290,44 +1337,43 @@ void MeshGenerator::generate()
if (nullptr != combinedMesh) {
combinedMesh->fetch(combinedVertices, combinedFaces);
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);
qDebug() << "Total weld affected triangles:" << totalAffectedNum;
recoverQuads(combinedVertices, combinedFaces, componentCache.sharedQuadEdges, m_outcome->triangleAndQuads);
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);
qDebug() << "Total weld affected triangles:" << totalAffectedNum;
}
m_outcome->nodes = componentCache.outcomeNodes;
m_outcome->nodeVertices = componentCache.outcomeNodeVertices;
m_outcome->vertices = combinedVertices;
m_outcome->triangles = combinedFaces;
m_outcome->paintMaps = componentCache.outcomePaintMaps;
recoverQuads(combinedVertices, combinedFaces, componentCache.sharedQuadEdges, m_outcome->triangleAndQuads);
m_outcome->nodeVertices = componentCache.outcomeNodeVertices;
m_outcome->vertices = combinedVertices;
m_outcome->triangles = combinedFaces;
/*
Remesher remesher;
remesher.setMesh(combinedVertices, combinedFaces);
remesher.remesh();
m_outcome->vertices = remesher.getRemeshedVertices();
const auto &remeshedFaces = remesher.getRemeshedFaces();
m_outcome->triangleAndQuads = remeshedFaces;
m_outcome->triangles.clear();
m_outcome->triangles.reserve(remeshedFaces.size() * 2);
for (const auto &it: remeshedFaces) {
m_outcome->triangles.push_back(std::vector<size_t> {
it[0], it[1], it[2]
});
m_outcome->triangles.push_back(std::vector<size_t> {
it[2], it[3], it[0]
});
if (remeshed) {
remesh(componentCache.outcomeNodes,
combinedVertices,
combinedFaces,
&m_outcome->vertices,
&m_outcome->triangleAndQuads,
&m_outcome->triangles,
&m_outcome->nodeVertices);
} else {
recoverQuads(combinedVertices, combinedFaces, componentCache.sharedQuadEdges, m_outcome->triangleAndQuads);
m_outcome->nodeVertices = componentCache.outcomeNodeVertices;
m_outcome->vertices = combinedVertices;
m_outcome->triangles = combinedFaces;
}
*/
}
@ -1411,6 +1457,50 @@ void MeshGenerator::generate()
qDebug() << "The mesh generation took" << countTimeConsumed.elapsed() << "milliseconds";
}
void MeshGenerator::remesh(const std::vector<OutcomeNode> &inputNodes,
const std::vector<QVector3D> &inputVertices,
const std::vector<std::vector<size_t>> &inputFaces,
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(inputNodes.size());
sourceIds.reserve(inputNodes.size());
for (const auto &it: inputNodes) {
nodes.push_back(std::make_pair(it.origin, it.radius));
sourceIds.push_back(std::make_pair(it.partId, it.nodeId));
}
Remesher remesher;
remesher.setMesh(inputVertices, inputFaces);
remesher.setNodes(nodes, sourceIds);
remesher.remesh();
*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]
});
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::collectUncombinedComponent(const QString &componentIdString)
{
const auto &component = findComponent(componentIdString);

View File

@ -120,12 +120,20 @@ 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);
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<OutcomeNode> &inputNodes,
const std::vector<QVector3D> &inputVertices,
const std::vector<std::vector<size_t>> &inputFaces,
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);
};
#endif

View File

@ -11,6 +11,7 @@
#include <QClipboard>
#include <QMimeData>
#include <QApplication>
#include <QCheckBox>
#include "parttreewidget.h"
#include "partwidget.h"
#include "skeletongraphicswidget.h"
@ -31,8 +32,6 @@ PartTreeWidget::PartTreeWidget(const Document *document, QWidget *parent) :
setColumnCount(1);
setHeaderHidden(true);
m_componentItemMap[QUuid()] = invisibleRootItem();
setContextMenuPolicy(Qt::CustomContextMenu);
//setIconSize(QSize(Theme::miniIconFontSize, Theme::miniIconFontSize));
@ -61,6 +60,17 @@ PartTreeWidget::PartTreeWidget(const Document *document, QWidget *parent) :
gradient.setColorAt(1, Qt::transparent);
m_hightlightedPartBackground = QBrush(gradient);
QTreeWidgetItem *item = new QTreeWidgetItem(QStringList(tr("Root")));
invisibleRootItem()->addChild(item);
item->setData(0, Qt::UserRole, QVariant(QUuid().toString()));
item->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
item->setExpanded(true);
item->setFlags((item->flags() | Qt::ItemIsEnabled) & ~(Qt::ItemIsSelectable));
m_rootItem = item;
m_componentItemMap[QUuid()] = item;
m_firstSelect = true;
selectComponent(QUuid());
connect(this, &QTreeWidget::customContextMenuRequested, this, &PartTreeWidget::showContextMenu);
connect(this, &QTreeWidget::itemChanged, this, &PartTreeWidget::groupChanged);
connect(this, &QTreeWidget::itemExpanded, this, &PartTreeWidget::groupExpanded);
@ -69,6 +79,11 @@ PartTreeWidget::PartTreeWidget(const Document *document, QWidget *parent) :
void PartTreeWidget::selectComponent(QUuid componentId, bool multiple)
{
if (m_firstSelect) {
m_firstSelect = false;
updateComponentSelectState(QUuid(), true);
return;
}
if (multiple) {
if (!m_currentSelectedComponentId.isNull()) {
m_selectedComponentIds.insert(m_currentSelectedComponentId);
@ -97,13 +112,13 @@ void PartTreeWidget::selectComponent(QUuid componentId, bool multiple)
m_selectedComponentIds.clear();
}
if (m_currentSelectedComponentId != componentId) {
if (!m_currentSelectedComponentId.isNull()) {
//if (!m_currentSelectedComponentId.isNull()) {
updateComponentSelectState(m_currentSelectedComponentId, false);
}
//}
m_currentSelectedComponentId = componentId;
if (!m_currentSelectedComponentId.isNull()) {
//if (!m_currentSelectedComponentId.isNull()) {
updateComponentSelectState(m_currentSelectedComponentId, true);
}
//}
emit currentComponentChanged(m_currentSelectedComponentId);
}
}
@ -269,9 +284,30 @@ void PartTreeWidget::showContextMenu(const QPoint &pos)
previewLabel->setText(component->name);
} else if (!componentIds.empty()) {
previewLabel->setText(tr("(%1 items)").arg(QString::number(componentIds.size())));
} else {
previewLabel->hide();
}
layout->addWidget(previewLabel);
}
QCheckBox *remeshBox = nullptr;
if (componentIds.size() <= 1) {
remeshBox = new QCheckBox();
remeshBox->setText(tr("Remeshed"));
if (nullptr == component) {
if (m_document->remeshed)
remeshBox->setChecked(true);
connect(remeshBox, &QCheckBox::stateChanged, this, [=]() {
emit setComponentRemeshState(QUuid(), remeshBox->isChecked());
});
} else {
if (component->remeshed)
remeshBox->setChecked(true);
connect(remeshBox, &QCheckBox::stateChanged, this, [=]() {
emit setComponentRemeshState(component->id, remeshBox->isChecked());
});
}
Theme::initCheckbox(remeshBox);
}
QWidget *widget = new QWidget;
if (nullptr != component) {
QComboBox *combineModeSelectBox = new QComboBox;
@ -325,16 +361,22 @@ void PartTreeWidget::showContextMenu(const QPoint &pos)
QVBoxLayout *newLayout = new QVBoxLayout;
newLayout->addLayout(layout);
if (nullptr != remeshBox)
newLayout->addWidget(remeshBox);
newLayout->addLayout(componentSettingsLayout);
widget->setLayout(newLayout);
} else {
widget->setLayout(layout);
QVBoxLayout *newLayout = new QVBoxLayout;
newLayout->addLayout(layout);
if (nullptr != remeshBox)
newLayout->addWidget(remeshBox);
widget->setLayout(newLayout);
}
forDisplayPartImage.setDefaultWidget(widget);
if (!componentIds.empty()) {
//if (!componentIds.empty()) {
contextMenu.addAction(&forDisplayPartImage);
contextMenu.addSeparator();
}
//}
QAction showAction(tr("Show"), this);
showAction.setIcon(Theme::awesome()->icon(fa::eye));
@ -456,12 +498,14 @@ void PartTreeWidget::showContextMenu(const QPoint &pos)
QAction collapseAllAction(tr("Collapse All"), this);
connect(&collapseAllAction, &QAction::triggered, [=]() {
m_rootItem->setExpanded(false);
emit collapseAllComponents();
});
contextMenu.addAction(&collapseAllAction);
QAction expandAllAction(tr("Expand All"), this);
connect(&expandAllAction, &QAction::triggered, [=]() {
m_rootItem->setExpanded(true);
emit expandAllComponents();
});
contextMenu.addAction(&expandAllAction);
@ -810,9 +854,9 @@ void PartTreeWidget::componentChildrenChanged(QUuid componentId)
addComponentChildrenToItem(componentId, parentItem);
// Fix the last item show in the wrong place sometimes
int childCount = invisibleRootItem()->childCount();
int childCount = m_rootItem->childCount();
if (childCount > 0) {
QTreeWidgetItem *lastItem = invisibleRootItem()->child(childCount - 1);
QTreeWidgetItem *lastItem = m_rootItem->child(childCount - 1);
bool isExpanded = lastItem->isExpanded();
lastItem->setExpanded(!isExpanded);
lastItem->setExpanded(isExpanded);
@ -821,10 +865,10 @@ void PartTreeWidget::componentChildrenChanged(QUuid componentId)
void PartTreeWidget::removeAllContent()
{
qDeleteAll(invisibleRootItem()->takeChildren());
qDeleteAll(m_rootItem->takeChildren());
m_partItemMap.clear();
m_componentItemMap.clear();
m_componentItemMap[QUuid()] = invisibleRootItem();
m_componentItemMap[QUuid()] = m_rootItem;
}
void PartTreeWidget::componentRemoved(QUuid componentId)

View File

@ -3,6 +3,7 @@
#include <QTreeWidget>
#include <QUuid>
#include <QMouseEvent>
#include <QTreeWidgetItem>
#include "document.h"
class PartTreeWidget : public QTreeWidget
@ -21,6 +22,7 @@ signals:
void setComponentExpandState(QUuid componentId, bool expanded);
void setComponentSmoothAll(QUuid componentId, float toSmoothAll);
void setComponentSmoothSeam(QUuid componentId, float toSmoothSeam);
void setComponentRemeshState(QUuid componentId, bool remeshed);
void setPartTarget(QUuid partId, PartTarget target);
void setPartBase(QUuid partId, PartBase base);
void moveComponent(QUuid componentId, QUuid toParentId);
@ -93,6 +95,8 @@ private:
bool isComponentSelected(QUuid componentId);
private:
const Document *m_document = nullptr;
QTreeWidgetItem *m_rootItem = nullptr;
bool m_firstSelect = true;
std::map<QUuid, QTreeWidgetItem *> m_partItemMap;
std::map<QUuid, QTreeWidgetItem *> m_componentItemMap;
QFont m_normalFont;

View File

@ -2,6 +2,7 @@
#include <field-math.hpp>
#include <optimizer.hpp>
#include <parametrizer.hpp>
#include <cmath>
#ifdef WITH_CUDA
#include <cuda_runtime.h>
#endif
@ -20,15 +21,21 @@ void Remesher::setMesh(const std::vector<QVector3D> &vertices,
m_triangles = triangles;
}
const std::vector<QVector3D> &Remesher::getRemeshedVertices()
const std::vector<QVector3D> &Remesher::getRemeshedVertices() const
{
return m_remeshedVertices;
}
const std::vector<std::vector<size_t>> &Remesher::getRemeshedFaces()
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()
{
Parametrizer field;
@ -104,6 +111,39 @@ void Remesher::remesh()
});
}
printf("m_remeshedVertices.size:%lu\r\n", m_remeshedVertices.size());
printf("m_remeshedFaces.size:%lu\r\n", m_remeshedFaces.size());
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()
{
m_remeshedVertexSources.resize(m_remeshedVertices.size());
std::vector<float> nodeRadius2(m_nodes.size());
for (size_t nodeIndex = 0; nodeIndex < m_nodes.size(); ++nodeIndex) {
nodeRadius2[nodeIndex] = std::pow(m_nodes[nodeIndex].second, 2);
}
for (size_t vertexIndex = 0; vertexIndex < m_remeshedVertices.size(); ++vertexIndex) {
std::vector<std::pair<float, size_t>> matches;
const auto &vertexPosition = m_remeshedVertices[vertexIndex];
for (size_t nodeIndex = 0; nodeIndex < m_nodes.size(); ++nodeIndex) {
const auto &nodePosition = m_nodes[nodeIndex].first;
auto length2 = (vertexPosition - nodePosition).lengthSquared();
if (length2 > nodeRadius2[nodeIndex])
continue;
matches.push_back(std::make_pair(length2, nodeIndex));
}
std::sort(matches.begin(), matches.end(), [](const std::pair<float, size_t> &first,
const std::pair<float, size_t> &second) {
return first.first < second.first;
});
if (matches.empty())
continue;
m_remeshedVertexSources[vertexIndex] = m_sourceIds[matches[0].second];
}
}

View File

@ -3,6 +3,7 @@
#include <QObject>
#include <vector>
#include <QVector3D>
#include <QUuid>
class Remesher : public QObject
{
@ -11,14 +12,21 @@ public:
~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();
const std::vector<QVector3D> &getRemeshedVertices();
const std::vector<std::vector<size_t>> &getRemeshedFaces();
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

View File

@ -56,7 +56,7 @@ void Theme::initAwsomeBaseSizes()
Theme::miniIconFontSize = (int)(Theme::toolIconFontSize * 0.7);
Theme::miniIconSize = (int)(Theme::miniIconFontSize * 1.67);
Theme::partPreviewImageSize = (Theme::miniIconSize * 3);
Theme::sidebarPreferredWidth = Theme::partPreviewImageSize * 3.7;
Theme::sidebarPreferredWidth = Theme::partPreviewImageSize * 4; //3.7;
Theme::posePreviewImageSize = Theme::sidebarPreferredWidth * 0.4;
Theme::materialPreviewImageSize = Theme::posePreviewImageSize;
Theme::cutFacePreviewImageSize = Theme::posePreviewImageSize;