Add base plane constrain settings
Mesh layout and thickness adjustment are depend on base plane calculation. In this build, the base plane calculation could be limited to front plane, side plane, and so on, compare to without any limitation in previous implementation.master
parent
b09df89da2
commit
bb19489ee1
|
@ -298,6 +298,9 @@ HEADERS += src/cutface.h
|
||||||
SOURCES += src/parttarget.cpp
|
SOURCES += src/parttarget.cpp
|
||||||
HEADERS += src/parttarget.h
|
HEADERS += src/parttarget.h
|
||||||
|
|
||||||
|
SOURCES += src/partbase.cpp
|
||||||
|
HEADERS += src/partbase.h
|
||||||
|
|
||||||
SOURCES += src/cutfacewidget.cpp
|
SOURCES += src/cutfacewidget.cpp
|
||||||
HEADERS += src/cutfacewidget.h
|
HEADERS += src/cutfacewidget.h
|
||||||
|
|
||||||
|
|
|
@ -893,7 +893,10 @@ void Document::toSnapshot(Snapshot *snapshot, const std::set<QUuid> &limitNodeId
|
||||||
part["subdived"] = partIt.second.subdived ? "true" : "false";
|
part["subdived"] = partIt.second.subdived ? "true" : "false";
|
||||||
part["disabled"] = partIt.second.disabled ? "true" : "false";
|
part["disabled"] = partIt.second.disabled ? "true" : "false";
|
||||||
part["xMirrored"] = partIt.second.xMirrored ? "true" : "false";
|
part["xMirrored"] = partIt.second.xMirrored ? "true" : "false";
|
||||||
part["zMirrored"] = partIt.second.zMirrored ? "true" : "false";
|
if (partIt.second.zMirrored)
|
||||||
|
part["zMirrored"] = partIt.second.zMirrored ? "true" : "false";
|
||||||
|
if (partIt.second.base != PartBase::XYZ)
|
||||||
|
part["base"] = PartBaseToString(partIt.second.base);
|
||||||
part["rounded"] = partIt.second.rounded ? "true" : "false";
|
part["rounded"] = partIt.second.rounded ? "true" : "false";
|
||||||
part["chamfered"] = partIt.second.chamfered ? "true" : "false";
|
part["chamfered"] = partIt.second.chamfered ? "true" : "false";
|
||||||
if (PartTarget::Model != partIt.second.target)
|
if (PartTarget::Model != partIt.second.target)
|
||||||
|
@ -1163,6 +1166,7 @@ void Document::addFromSnapshot(const Snapshot &snapshot, bool fromPaste)
|
||||||
part.disabled = isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "disabled"));
|
part.disabled = isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "disabled"));
|
||||||
part.xMirrored = isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "xMirrored"));
|
part.xMirrored = isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "xMirrored"));
|
||||||
part.zMirrored = isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "zMirrored"));
|
part.zMirrored = isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "zMirrored"));
|
||||||
|
part.base = PartBaseFromString(valueOfKeyInMapOrEmpty(partKv.second, "base").toUtf8().constData());
|
||||||
part.rounded = isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "rounded"));
|
part.rounded = isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "rounded"));
|
||||||
part.chamfered = isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "chamfered"));
|
part.chamfered = isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "chamfered"));
|
||||||
part.target = PartTargetFromString(valueOfKeyInMapOrEmpty(partKv.second, "target").toUtf8().constData());
|
part.target = PartTargetFromString(valueOfKeyInMapOrEmpty(partKv.second, "target").toUtf8().constData());
|
||||||
|
@ -2219,6 +2223,21 @@ void Document::setPartDeformThickness(QUuid partId, float thickness)
|
||||||
emit skeletonChanged();
|
emit skeletonChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Document::setPartBase(QUuid partId, PartBase base)
|
||||||
|
{
|
||||||
|
auto part = partMap.find(partId);
|
||||||
|
if (part == partMap.end()) {
|
||||||
|
qDebug() << "Part not found:" << partId;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (part->second.base == base)
|
||||||
|
return;
|
||||||
|
part->second.base = base;
|
||||||
|
part->second.dirty = true;
|
||||||
|
emit partBaseChanged(partId);
|
||||||
|
emit skeletonChanged();
|
||||||
|
}
|
||||||
|
|
||||||
void Document::setPartDeformWidth(QUuid partId, float width)
|
void Document::setPartDeformWidth(QUuid partId, float width)
|
||||||
{
|
{
|
||||||
auto part = partMap.find(partId);
|
auto part = partMap.find(partId);
|
||||||
|
|
|
@ -396,6 +396,7 @@ signals:
|
||||||
void partDisableStateChanged(QUuid partId);
|
void partDisableStateChanged(QUuid partId);
|
||||||
void partXmirrorStateChanged(QUuid partId);
|
void partXmirrorStateChanged(QUuid partId);
|
||||||
//void partZmirrorStateChanged(QUuid partId);
|
//void partZmirrorStateChanged(QUuid partId);
|
||||||
|
void partBaseChanged(QUuid partId);
|
||||||
void partDeformThicknessChanged(QUuid partId);
|
void partDeformThicknessChanged(QUuid partId);
|
||||||
void partDeformWidthChanged(QUuid partId);
|
void partDeformWidthChanged(QUuid partId);
|
||||||
void partRoundStateChanged(QUuid partId);
|
void partRoundStateChanged(QUuid partId);
|
||||||
|
@ -553,6 +554,7 @@ public slots:
|
||||||
void setPartDisableState(QUuid partId, bool disabled);
|
void setPartDisableState(QUuid partId, bool disabled);
|
||||||
void setPartXmirrorState(QUuid partId, bool mirrored);
|
void setPartXmirrorState(QUuid partId, bool mirrored);
|
||||||
//void setPartZmirrorState(QUuid partId, bool mirrored);
|
//void setPartZmirrorState(QUuid partId, bool mirrored);
|
||||||
|
void setPartBase(QUuid partId, PartBase base);
|
||||||
void setPartDeformThickness(QUuid partId, float thickness);
|
void setPartDeformThickness(QUuid partId, float thickness);
|
||||||
void setPartDeformWidth(QUuid partId, float width);
|
void setPartDeformWidth(QUuid partId, float width);
|
||||||
void setPartRoundState(QUuid partId, bool rounded);
|
void setPartRoundState(QUuid partId, bool rounded);
|
||||||
|
|
|
@ -832,6 +832,7 @@ DocumentWindow::DocumentWindow() :
|
||||||
connect(partTreeWidget, &PartTreeWidget::setPartVisibleState, m_document, &Document::setPartVisibleState);
|
connect(partTreeWidget, &PartTreeWidget::setPartVisibleState, m_document, &Document::setPartVisibleState);
|
||||||
connect(partTreeWidget, &PartTreeWidget::setComponentCombineMode, m_document, &Document::setComponentCombineMode);
|
connect(partTreeWidget, &PartTreeWidget::setComponentCombineMode, m_document, &Document::setComponentCombineMode);
|
||||||
connect(partTreeWidget, &PartTreeWidget::setPartTarget, m_document, &Document::setPartTarget);
|
connect(partTreeWidget, &PartTreeWidget::setPartTarget, m_document, &Document::setPartTarget);
|
||||||
|
connect(partTreeWidget, &PartTreeWidget::setPartBase, m_document, &Document::setPartBase);
|
||||||
connect(partTreeWidget, &PartTreeWidget::hideDescendantComponents, m_document, &Document::hideDescendantComponents);
|
connect(partTreeWidget, &PartTreeWidget::hideDescendantComponents, m_document, &Document::hideDescendantComponents);
|
||||||
connect(partTreeWidget, &PartTreeWidget::showDescendantComponents, m_document, &Document::showDescendantComponents);
|
connect(partTreeWidget, &PartTreeWidget::showDescendantComponents, m_document, &Document::showDescendantComponents);
|
||||||
connect(partTreeWidget, &PartTreeWidget::lockDescendantComponents, m_document, &Document::lockDescendantComponents);
|
connect(partTreeWidget, &PartTreeWidget::lockDescendantComponents, m_document, &Document::lockDescendantComponents);
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "cutface.h"
|
#include "cutface.h"
|
||||||
#include "parttarget.h"
|
#include "parttarget.h"
|
||||||
#include "theme.h"
|
#include "theme.h"
|
||||||
|
#include "partbase.h"
|
||||||
|
|
||||||
MeshGenerator::MeshGenerator(Snapshot *snapshot) :
|
MeshGenerator::MeshGenerator(Snapshot *snapshot) :
|
||||||
m_snapshot(snapshot)
|
m_snapshot(snapshot)
|
||||||
|
@ -171,6 +172,7 @@ nodemesh::Combiner::Mesh *MeshGenerator::combinePartMesh(const QString &partIdSt
|
||||||
float deformWidth = 1.0;
|
float deformWidth = 1.0;
|
||||||
float cutRotation = 0.0;
|
float cutRotation = 0.0;
|
||||||
auto target = PartTargetFromString(valueOfKeyInMapOrEmpty(part, "target").toUtf8().constData());
|
auto target = PartTargetFromString(valueOfKeyInMapOrEmpty(part, "target").toUtf8().constData());
|
||||||
|
auto base = PartBaseFromString(valueOfKeyInMapOrEmpty(part, "base").toUtf8().constData());
|
||||||
|
|
||||||
std::vector<QVector2D> cutTemplate;
|
std::vector<QVector2D> cutTemplate;
|
||||||
QString cutFaceString = valueOfKeyInMapOrEmpty(part, "cutFace");
|
QString cutFaceString = valueOfKeyInMapOrEmpty(part, "cutFace");
|
||||||
|
@ -441,6 +443,13 @@ nodemesh::Combiner::Mesh *MeshGenerator::combinePartMesh(const QString &partIdSt
|
||||||
builder->setDeformThickness(deformThickness);
|
builder->setDeformThickness(deformThickness);
|
||||||
builder->setDeformWidth(deformWidth);
|
builder->setDeformWidth(deformWidth);
|
||||||
builder->setCutRotation(cutRotation);
|
builder->setCutRotation(cutRotation);
|
||||||
|
if (PartBase::YZ == base) {
|
||||||
|
builder->enableBaseNormalOnX(false);
|
||||||
|
} else if (PartBase::XY == base) {
|
||||||
|
builder->enableBaseNormalOnZ(false);
|
||||||
|
} else if (PartBase::ZX == base) {
|
||||||
|
builder->enableBaseNormalOnY(false);
|
||||||
|
}
|
||||||
|
|
||||||
for (const auto &node: modifier->nodes())
|
for (const auto &node: modifier->nodes())
|
||||||
builder->addNode(node.position, node.radius, node.cutTemplate);
|
builder->addNode(node.position, node.radius, node.cutTemplate);
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
#include "partbase.h"
|
||||||
|
|
||||||
|
IMPL_PartBaseFromString
|
||||||
|
IMPL_PartBaseToString
|
||||||
|
IMPL_PartBaseToDispName
|
|
@ -0,0 +1,64 @@
|
||||||
|
#ifndef DUST3D_PART_BASE_H
|
||||||
|
#define DUST3D_PART_BASE_H
|
||||||
|
#include <QString>
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
enum class PartBase
|
||||||
|
{
|
||||||
|
XYZ = 0,
|
||||||
|
YZ,
|
||||||
|
XY,
|
||||||
|
ZX,
|
||||||
|
Count
|
||||||
|
};
|
||||||
|
PartBase PartBaseFromString(const char *baseString);
|
||||||
|
#define IMPL_PartBaseFromString \
|
||||||
|
PartBase PartBaseFromString(const char *baseString) \
|
||||||
|
{ \
|
||||||
|
QString base = baseString; \
|
||||||
|
if (base == "XYZ") \
|
||||||
|
return PartBase::XYZ; \
|
||||||
|
if (base == "YZ") \
|
||||||
|
return PartBase::YZ; \
|
||||||
|
if (base == "XY") \
|
||||||
|
return PartBase::XY; \
|
||||||
|
if (base == "ZX") \
|
||||||
|
return PartBase::ZX; \
|
||||||
|
return PartBase::XYZ; \
|
||||||
|
}
|
||||||
|
const char *PartBaseToString(PartBase base);
|
||||||
|
#define IMPL_PartBaseToString \
|
||||||
|
const char *PartBaseToString(PartBase base) \
|
||||||
|
{ \
|
||||||
|
switch (base) { \
|
||||||
|
case PartBase::XYZ: \
|
||||||
|
return "XYZ"; \
|
||||||
|
case PartBase::YZ: \
|
||||||
|
return "YZ"; \
|
||||||
|
case PartBase::XY: \
|
||||||
|
return "XY"; \
|
||||||
|
case PartBase::ZX: \
|
||||||
|
return "ZX"; \
|
||||||
|
default: \
|
||||||
|
return "XYZ"; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
QString PartBaseToDispName(PartBase base);
|
||||||
|
#define IMPL_PartBaseToDispName \
|
||||||
|
QString PartBaseToDispName(PartBase base) \
|
||||||
|
{ \
|
||||||
|
switch (base) { \
|
||||||
|
case PartBase::XYZ: \
|
||||||
|
return QObject::tr("Dynamic"); \
|
||||||
|
case PartBase::YZ: \
|
||||||
|
return QObject::tr("Side Plane"); \
|
||||||
|
case PartBase::XY: \
|
||||||
|
return QObject::tr("Front Plane"); \
|
||||||
|
case PartBase::ZX: \
|
||||||
|
return QObject::tr("Top Plane"); \
|
||||||
|
default: \
|
||||||
|
return QObject::tr("Dynamic"); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -294,6 +294,19 @@ void PartTreeWidget::showContextMenu(const QPoint &pos)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QComboBox *partBaseSelectBox = nullptr;
|
||||||
|
if (nullptr != part && nullptr != partWidget) {
|
||||||
|
partBaseSelectBox = new QComboBox;
|
||||||
|
for (size_t i = 0; i < (size_t)PartBase::Count; ++i) {
|
||||||
|
PartBase base = (PartBase)i;
|
||||||
|
partBaseSelectBox->addItem(PartBaseToDispName(base));
|
||||||
|
}
|
||||||
|
partBaseSelectBox->setCurrentIndex((int)part->base);
|
||||||
|
connect(partBaseSelectBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, [=](int index) {
|
||||||
|
emit setPartBase(part->id, (PartBase)index);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
//QHBoxLayout *combineModeLayout = new QHBoxLayout;
|
//QHBoxLayout *combineModeLayout = new QHBoxLayout;
|
||||||
//combineModeLayout->setAlignment(Qt::AlignCenter);
|
//combineModeLayout->setAlignment(Qt::AlignCenter);
|
||||||
//combineModeLayout->setContentsMargins(0, 0, 0, 0);
|
//combineModeLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
@ -301,6 +314,8 @@ void PartTreeWidget::showContextMenu(const QPoint &pos)
|
||||||
//combineModeLayout->addWidget(combineModeSelectBox);
|
//combineModeLayout->addWidget(combineModeSelectBox);
|
||||||
|
|
||||||
QFormLayout *componentSettingsLayout = new QFormLayout;
|
QFormLayout *componentSettingsLayout = new QFormLayout;
|
||||||
|
if (nullptr != partBaseSelectBox)
|
||||||
|
componentSettingsLayout->addRow(tr("Base"), partBaseSelectBox);
|
||||||
if (nullptr != partTargetSelectBox)
|
if (nullptr != partTargetSelectBox)
|
||||||
componentSettingsLayout->addRow(tr("Target"), partTargetSelectBox);
|
componentSettingsLayout->addRow(tr("Target"), partTargetSelectBox);
|
||||||
componentSettingsLayout->addRow(tr("Mode"), combineModeSelectBox);
|
componentSettingsLayout->addRow(tr("Mode"), combineModeSelectBox);
|
||||||
|
|
|
@ -22,6 +22,7 @@ signals:
|
||||||
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 setPartTarget(QUuid partId, PartTarget target);
|
void setPartTarget(QUuid partId, PartTarget target);
|
||||||
|
void setPartBase(QUuid partId, PartBase base);
|
||||||
void moveComponent(QUuid componentId, QUuid toParentId);
|
void moveComponent(QUuid componentId, QUuid toParentId);
|
||||||
void removeComponent(QUuid componentId);
|
void removeComponent(QUuid componentId);
|
||||||
void hideOtherComponents(QUuid componentId);
|
void hideOtherComponents(QUuid componentId);
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "meshloader.h"
|
#include "meshloader.h"
|
||||||
#include "cutface.h"
|
#include "cutface.h"
|
||||||
#include "parttarget.h"
|
#include "parttarget.h"
|
||||||
|
#include "partbase.h"
|
||||||
|
|
||||||
class SkeletonNode
|
class SkeletonNode
|
||||||
{
|
{
|
||||||
|
@ -77,6 +78,7 @@ public:
|
||||||
bool disabled;
|
bool disabled;
|
||||||
bool xMirrored;
|
bool xMirrored;
|
||||||
bool zMirrored;
|
bool zMirrored;
|
||||||
|
PartBase base;
|
||||||
float deformThickness;
|
float deformThickness;
|
||||||
float deformWidth;
|
float deformWidth;
|
||||||
bool rounded;
|
bool rounded;
|
||||||
|
@ -98,6 +100,7 @@ public:
|
||||||
disabled(false),
|
disabled(false),
|
||||||
xMirrored(false),
|
xMirrored(false),
|
||||||
zMirrored(false),
|
zMirrored(false),
|
||||||
|
base(PartBase::XYZ),
|
||||||
deformThickness(1.0),
|
deformThickness(1.0),
|
||||||
deformWidth(1.0),
|
deformWidth(1.0),
|
||||||
rounded(false),
|
rounded(false),
|
||||||
|
@ -189,6 +192,7 @@ public:
|
||||||
disabled = other.disabled;
|
disabled = other.disabled;
|
||||||
xMirrored = other.xMirrored;
|
xMirrored = other.xMirrored;
|
||||||
zMirrored = other.zMirrored;
|
zMirrored = other.zMirrored;
|
||||||
|
base = other.base;
|
||||||
deformThickness = other.deformThickness;
|
deformThickness = other.deformThickness;
|
||||||
deformWidth = other.deformWidth;
|
deformWidth = other.deformWidth;
|
||||||
rounded = other.rounded;
|
rounded = other.rounded;
|
||||||
|
|
|
@ -289,10 +289,45 @@ bool Builder::validateNormal(const QVector3D &normal)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<QVector3D, bool> Builder::calculateBaseNormal(const std::vector<QVector3D> &directs,
|
void Builder::enableBaseNormalOnX(bool enabled)
|
||||||
const std::vector<QVector3D> &positions,
|
{
|
||||||
|
m_baseNormalOnX = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Builder::enableBaseNormalOnY(bool enabled)
|
||||||
|
{
|
||||||
|
m_baseNormalOnY = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Builder::enableBaseNormalOnZ(bool enabled)
|
||||||
|
{
|
||||||
|
m_baseNormalOnZ = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<QVector3D, bool> Builder::calculateBaseNormal(const std::vector<QVector3D> &inputDirects,
|
||||||
|
const std::vector<QVector3D> &inputPositions,
|
||||||
const std::vector<float> &weights)
|
const std::vector<float> &weights)
|
||||||
{
|
{
|
||||||
|
std::vector<QVector3D> directs = inputDirects;
|
||||||
|
std::vector<QVector3D> positions = inputPositions;
|
||||||
|
if (!m_baseNormalOnX || !m_baseNormalOnY || !m_baseNormalOnZ) {
|
||||||
|
for (auto &it: directs) {
|
||||||
|
if (!m_baseNormalOnX)
|
||||||
|
it.setX(0);
|
||||||
|
if (!m_baseNormalOnY)
|
||||||
|
it.setY(0);
|
||||||
|
if (!m_baseNormalOnZ)
|
||||||
|
it.setZ(0);
|
||||||
|
}
|
||||||
|
for (auto &it: positions) {
|
||||||
|
if (!m_baseNormalOnX)
|
||||||
|
it.setX(0);
|
||||||
|
if (!m_baseNormalOnY)
|
||||||
|
it.setY(0);
|
||||||
|
if (!m_baseNormalOnZ)
|
||||||
|
it.setZ(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
auto calculateTwoPointsNormal = [&](size_t i0, size_t i1) -> std::pair<QVector3D, bool> {
|
auto calculateTwoPointsNormal = [&](size_t i0, size_t i1) -> std::pair<QVector3D, bool> {
|
||||||
auto normal = QVector3D::crossProduct(directs[i0], directs[i1]).normalized();
|
auto normal = QVector3D::crossProduct(directs[i0], directs[i1]).normalized();
|
||||||
if (validateNormal(normal)) {
|
if (validateNormal(normal)) {
|
||||||
|
|
|
@ -17,6 +17,9 @@ public:
|
||||||
void setDeformThickness(float thickness);
|
void setDeformThickness(float thickness);
|
||||||
void setDeformWidth(float width);
|
void setDeformWidth(float width);
|
||||||
void setCutRotation(float cutRotation);
|
void setCutRotation(float cutRotation);
|
||||||
|
void enableBaseNormalOnX(bool enabled);
|
||||||
|
void enableBaseNormalOnY(bool enabled);
|
||||||
|
void enableBaseNormalOnZ(bool enabled);
|
||||||
const std::vector<QVector3D> &generatedVertices();
|
const std::vector<QVector3D> &generatedVertices();
|
||||||
const std::vector<std::vector<size_t>> &generatedFaces();
|
const std::vector<std::vector<size_t>> &generatedFaces();
|
||||||
const std::vector<size_t> &generatedVerticesSourceNodeIndices();
|
const std::vector<size_t> &generatedVerticesSourceNodeIndices();
|
||||||
|
@ -92,11 +95,14 @@ private:
|
||||||
float m_deformThickness = 1.0;
|
float m_deformThickness = 1.0;
|
||||||
float m_deformWidth = 1.0;
|
float m_deformWidth = 1.0;
|
||||||
float m_cutRotation = 0.0;
|
float m_cutRotation = 0.0;
|
||||||
|
bool m_baseNormalOnX = true;
|
||||||
|
bool m_baseNormalOnY = true;
|
||||||
|
bool m_baseNormalOnZ = true;
|
||||||
|
|
||||||
void sortNodeIndices();
|
void sortNodeIndices();
|
||||||
void prepareNode(size_t nodeIndex);
|
void prepareNode(size_t nodeIndex);
|
||||||
std::pair<QVector3D, bool> calculateBaseNormal(const std::vector<QVector3D> &directs,
|
std::pair<QVector3D, bool> calculateBaseNormal(const std::vector<QVector3D> &inputDirects,
|
||||||
const std::vector<QVector3D> &positions,
|
const std::vector<QVector3D> &inputPositions,
|
||||||
const std::vector<float> &weights);
|
const std::vector<float> &weights);
|
||||||
bool validateNormal(const QVector3D &normal);
|
bool validateNormal(const QVector3D &normal);
|
||||||
void resolveBaseNormalRecursively(size_t nodeIndex);
|
void resolveBaseNormalRecursively(size_t nodeIndex);
|
||||||
|
|
Loading…
Reference in New Issue