Add hollow thickness parameter
parent
0077986201
commit
9ed4c29b39
|
@ -747,6 +747,10 @@ Tips:
|
|||
<source>Map Scale</source>
|
||||
<translation>映像缩放比</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Hollow</source>
|
||||
<translation>空心</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PoseEditWidget</name>
|
||||
|
|
|
@ -1069,6 +1069,8 @@ void Document::toSnapshot(Snapshot *snapshot, const std::set<QUuid> &limitNodeId
|
|||
part["deformMapImageId"] = partIt.second.deformMapImageId.toString();
|
||||
if (partIt.second.deformMapScaleAdjusted())
|
||||
part["deformMapScale"] = QString::number(partIt.second.deformMapScale);
|
||||
if (partIt.second.hollowThicknessAdjusted())
|
||||
part["hollowThickness"] = QString::number(partIt.second.hollowThickness);
|
||||
if (!partIt.second.name.isEmpty())
|
||||
part["name"] = partIt.second.name;
|
||||
if (partIt.second.materialAdjusted())
|
||||
|
@ -1367,6 +1369,9 @@ void Document::addFromSnapshot(const Snapshot &snapshot, bool fromPaste)
|
|||
const auto &deformMapScaleIt = partKv.second.find("deformMapScale");
|
||||
if (deformMapScaleIt != partKv.second.end())
|
||||
part.deformMapScale = deformMapScaleIt->second.toFloat();
|
||||
const auto &hollowThicknessIt = partKv.second.find("hollowThickness");
|
||||
if (hollowThicknessIt != partKv.second.end())
|
||||
part.hollowThickness = hollowThicknessIt->second.toFloat();
|
||||
const auto &materialIdIt = partKv.second.find("materialId");
|
||||
if (materialIdIt != partKv.second.end())
|
||||
part.materialId = oldNewIdMap[QUuid(materialIdIt->second)];
|
||||
|
@ -2713,6 +2718,21 @@ void Document::setPartColorSolubility(QUuid partId, float solubility)
|
|||
emit skeletonChanged();
|
||||
}
|
||||
|
||||
void Document::setPartHollowThickness(QUuid partId, float hollowThickness)
|
||||
{
|
||||
auto part = partMap.find(partId);
|
||||
if (part == partMap.end()) {
|
||||
qDebug() << "Part not found:" << partId;
|
||||
return;
|
||||
}
|
||||
if (qFuzzyCompare(part->second.hollowThickness, hollowThickness))
|
||||
return;
|
||||
part->second.hollowThickness = hollowThickness;
|
||||
part->second.dirty = true;
|
||||
emit partHollowThicknessChanged(partId);
|
||||
emit skeletonChanged();
|
||||
}
|
||||
|
||||
void Document::setPartCutRotation(QUuid partId, float cutRotation)
|
||||
{
|
||||
auto part = partMap.find(partId);
|
||||
|
|
|
@ -422,6 +422,7 @@ signals:
|
|||
void partChamferStateChanged(QUuid partId);
|
||||
void partTargetChanged(QUuid partId);
|
||||
void partColorSolubilityChanged(QUuid partId);
|
||||
void partHollowThicknessChanged(QUuid partId);
|
||||
void componentCombineModeChanged(QUuid componentId);
|
||||
void cleanup();
|
||||
void cleanupScript();
|
||||
|
@ -609,6 +610,7 @@ public slots:
|
|||
void setPartChamferState(QUuid partId, bool chamfered);
|
||||
void setPartTarget(QUuid partId, PartTarget target);
|
||||
void setPartColorSolubility(QUuid partId, float solubility);
|
||||
void setPartHollowThickness(QUuid partId, float hollowThickness);
|
||||
void setComponentCombineMode(QUuid componentId, CombineMode combineMode);
|
||||
void moveComponentUp(QUuid componentId);
|
||||
void moveComponentDown(QUuid componentId);
|
||||
|
|
|
@ -338,6 +338,7 @@ nodemesh::Combiner::Mesh *MeshGenerator::combinePartMesh(const QString &partIdSt
|
|||
float deformThickness = 1.0;
|
||||
float deformWidth = 1.0;
|
||||
float cutRotation = 0.0;
|
||||
float hollowThickness = 0.0;
|
||||
auto target = PartTargetFromString(valueOfKeyInMapOrEmpty(part, "target").toUtf8().constData());
|
||||
auto base = PartBaseFromString(valueOfKeyInMapOrEmpty(part, "base").toUtf8().constData());
|
||||
|
||||
|
@ -352,6 +353,11 @@ nodemesh::Combiner::Mesh *MeshGenerator::combinePartMesh(const QString &partIdSt
|
|||
cutRotation = cutRotationString.toFloat();
|
||||
}
|
||||
|
||||
QString hollowThicknessString = valueOfKeyInMapOrEmpty(part, "hollowThickness");
|
||||
if (!hollowThicknessString.isEmpty()) {
|
||||
hollowThickness = hollowThicknessString.toFloat();
|
||||
}
|
||||
|
||||
QString thicknessString = valueOfKeyInMapOrEmpty(part, "deformThickness");
|
||||
if (!thicknessString.isEmpty()) {
|
||||
deformThickness = thicknessString.toFloat();
|
||||
|
@ -559,6 +565,7 @@ nodemesh::Combiner::Mesh *MeshGenerator::combinePartMesh(const QString &partIdSt
|
|||
builder->setDeformThickness(deformThickness);
|
||||
builder->setDeformWidth(deformWidth);
|
||||
builder->setDeformMapScale(deformMapScale);
|
||||
builder->setHollowThickness(hollowThickness);
|
||||
if (nullptr != deformImage)
|
||||
builder->setDeformMapImage(deformImage);
|
||||
if (PartBase::YZ == base) {
|
||||
|
|
|
@ -171,6 +171,7 @@ PartWidget::PartWidget(const Document *document, QUuid partId) :
|
|||
connect(this, &PartWidget::setPartColorState, m_document, &Document::setPartColorState);
|
||||
connect(this, &PartWidget::setPartMaterialId, m_document, &Document::setPartMaterialId);
|
||||
connect(this, &PartWidget::setPartColorSolubility, m_document, &Document::setPartColorSolubility);
|
||||
connect(this, &PartWidget::setPartHollowThickness, m_document, &Document::setPartHollowThickness);
|
||||
connect(this, &PartWidget::checkPart, m_document, &Document::checkPart);
|
||||
connect(this, &PartWidget::enableBackgroundBlur, m_document, &Document::enableBackgroundBlur);
|
||||
connect(this, &PartWidget::disableBackgroundBlur, m_document, &Document::disableBackgroundBlur);
|
||||
|
@ -465,6 +466,28 @@ void PartWidget::showCutRotationSettingPopup(const QPoint &pos)
|
|||
rotationLayout->addWidget(rotationEraser);
|
||||
rotationLayout->addWidget(rotationWidget);
|
||||
|
||||
FloatNumberWidget *hollowThicknessWidget = new FloatNumberWidget;
|
||||
hollowThicknessWidget->setItemName(tr("Hollow"));
|
||||
hollowThicknessWidget->setRange(0.0, 1.0);
|
||||
hollowThicknessWidget->setValue(part->hollowThickness);
|
||||
|
||||
connect(hollowThicknessWidget, &FloatNumberWidget::valueChanged, [=](float value) {
|
||||
emit setPartHollowThickness(m_partId, value);
|
||||
emit groupOperationAdded();
|
||||
});
|
||||
|
||||
QPushButton *hollowThicknessEraser = new QPushButton(QChar(fa::eraser));
|
||||
initToolButton(hollowThicknessEraser);
|
||||
|
||||
connect(hollowThicknessEraser, &QPushButton::clicked, [=]() {
|
||||
hollowThicknessWidget->setValue(0.0);
|
||||
emit groupOperationAdded();
|
||||
});
|
||||
|
||||
QHBoxLayout *hollowThicknessLayout = new QHBoxLayout;
|
||||
hollowThicknessLayout->addWidget(hollowThicknessEraser);
|
||||
hollowThicknessLayout->addWidget(hollowThicknessWidget);
|
||||
|
||||
QHBoxLayout *standardFacesLayout = new QHBoxLayout;
|
||||
QPushButton *buttons[(int)CutFace::Count] = {0};
|
||||
|
||||
|
@ -525,6 +548,7 @@ void PartWidget::showCutRotationSettingPopup(const QPoint &pos)
|
|||
|
||||
QVBoxLayout *popupLayout = new QVBoxLayout;
|
||||
popupLayout->addLayout(rotationLayout);
|
||||
popupLayout->addLayout(hollowThicknessLayout);
|
||||
popupLayout->addSpacing(10);
|
||||
popupLayout->addLayout(standardFacesLayout);
|
||||
popupLayout->addWidget(cutFaceListWidget);
|
||||
|
|
|
@ -28,6 +28,7 @@ signals:
|
|||
void setPartCutFaceLinkedId(QUuid partId, QUuid linkedId);
|
||||
void setPartMaterialId(QUuid partId, QUuid materialId);
|
||||
void setPartColorSolubility(QUuid partId, float colorSolubility);
|
||||
void setPartHollowThickness(QUuid partId, float hollowThickness);
|
||||
void movePartUp(QUuid partId);
|
||||
void movePartDown(QUuid partId);
|
||||
void movePartToTop(QUuid partId);
|
||||
|
|
|
@ -136,6 +136,7 @@ public:
|
|||
float colorSolubility;
|
||||
float deformMapScale;
|
||||
QUuid deformMapImageId;
|
||||
float hollowThickness;
|
||||
SkeletonPart(const QUuid &withId=QUuid()) :
|
||||
visible(true),
|
||||
locked(false),
|
||||
|
@ -155,7 +156,8 @@ public:
|
|||
cutFace(CutFace::Quad),
|
||||
target(PartTarget::Model),
|
||||
colorSolubility(0.0),
|
||||
deformMapScale(1.0)
|
||||
deformMapScale(1.0),
|
||||
hollowThickness(0.0)
|
||||
{
|
||||
id = withId.isNull() ? QUuid::createUuid() : withId;
|
||||
}
|
||||
|
@ -225,6 +227,10 @@ public:
|
|||
{
|
||||
return fabs(cutRotation - 0.0) >= 0.01;
|
||||
}
|
||||
bool hollowThicknessAdjusted() const
|
||||
{
|
||||
return fabs(hollowThickness - 0.0) >= 0.01;
|
||||
}
|
||||
bool cutFaceAdjusted() const
|
||||
{
|
||||
return cutFace != CutFace::Quad;
|
||||
|
|
|
@ -422,6 +422,7 @@ bool Builder::build()
|
|||
|
||||
applyWeld();
|
||||
applyDeform();
|
||||
finalizeHollow();
|
||||
|
||||
return succeed;
|
||||
}
|
||||
|
@ -609,7 +610,11 @@ bool Builder::generateCutsForNode(size_t nodeIndex)
|
|||
node.hasAdjustableCutFace = true;
|
||||
std::vector<size_t> vertices;
|
||||
insertCutVertices(cut, vertices, nodeIndex, cutNormal, cutFlipped);
|
||||
if (qFuzzyIsNull(m_hollowThickness)) {
|
||||
m_generatedFaces.push_back(vertices);
|
||||
} else {
|
||||
m_endCuts.push_back(vertices);
|
||||
}
|
||||
m_edges[node.edges[0]].cuts.push_back({vertices, -cutNormal});
|
||||
} else if (2 == neighborsCount) {
|
||||
QVector3D cutNormal = node.cutNormal;
|
||||
|
@ -1014,6 +1019,11 @@ void Builder::setDeformMapImage(const QImage *image)
|
|||
m_deformMapImage = image;
|
||||
}
|
||||
|
||||
void Builder::setHollowThickness(float hollowThickness)
|
||||
{
|
||||
m_hollowThickness = hollowThickness;
|
||||
}
|
||||
|
||||
void Builder::setDeformMapScale(float scale)
|
||||
{
|
||||
m_deformMapScale = scale;
|
||||
|
@ -1027,6 +1037,46 @@ QVector3D Builder::calculateDeformPosition(const QVector3D &vertexPosition, cons
|
|||
return vertexPosition + (scaledProjct - projectRayOnRevisedNormal);
|
||||
}
|
||||
|
||||
void Builder::finalizeHollow()
|
||||
{
|
||||
if (qFuzzyIsNull(m_hollowThickness))
|
||||
return;
|
||||
|
||||
size_t startVertexIndex = m_generatedVertices.size();
|
||||
for (size_t i = 0; i < startVertexIndex; ++i) {
|
||||
const auto &position = m_generatedVertices[i];
|
||||
const auto &node = m_nodes[m_generatedVerticesSourceNodeIndices[i]];
|
||||
auto ray = position - node.position;
|
||||
|
||||
auto newPosition = position - ray * m_hollowThickness;
|
||||
m_generatedVertices.push_back(newPosition);
|
||||
m_generatedVerticesCutDirects.push_back(m_generatedVerticesCutDirects[i]);
|
||||
m_generatedVerticesSourceNodeIndices.push_back(m_generatedVerticesSourceNodeIndices[i]);
|
||||
m_generatedVerticesInfos.push_back(m_generatedVerticesInfos[i]);
|
||||
}
|
||||
|
||||
size_t oldFaceNum = m_generatedFaces.size();
|
||||
for (size_t i = 0; i < oldFaceNum; ++i) {
|
||||
auto newFace = m_generatedFaces[i];
|
||||
std::reverse(newFace.begin(), newFace.end());
|
||||
for (auto &it: newFace)
|
||||
it += startVertexIndex;
|
||||
m_generatedFaces.push_back(newFace);
|
||||
}
|
||||
|
||||
for (const auto &cut: m_endCuts) {
|
||||
for (size_t i = 0; i < cut.size(); ++i) {
|
||||
size_t j = (i + 1) % cut.size();
|
||||
std::vector<size_t> quad;
|
||||
quad.push_back(cut[i]);
|
||||
quad.push_back(cut[j]);
|
||||
quad.push_back(startVertexIndex + cut[j]);
|
||||
quad.push_back(startVertexIndex + cut[i]);
|
||||
m_generatedFaces.push_back(quad);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Builder::applyDeform()
|
||||
{
|
||||
for (size_t i = 0; i < m_generatedVertices.size(); ++i) {
|
||||
|
|
|
@ -31,6 +31,7 @@ public:
|
|||
void setDeformWidth(float width);
|
||||
void setDeformMapImage(const QImage *image);
|
||||
void setDeformMapScale(float scale);
|
||||
void setHollowThickness(float hollowThickness);
|
||||
void enableBaseNormalOnX(bool enabled);
|
||||
void enableBaseNormalOnY(bool enabled);
|
||||
void enableBaseNormalOnZ(bool enabled);
|
||||
|
@ -133,6 +134,8 @@ private:
|
|||
bool m_baseNormalAverageEnabled = false;
|
||||
const QImage *m_deformMapImage = nullptr;
|
||||
float m_deformMapScale = 0.0;
|
||||
float m_hollowThickness = 0.2;
|
||||
std::vector<std::vector<size_t>> m_endCuts;
|
||||
|
||||
void sortNodeIndices();
|
||||
void prepareNode(size_t nodeIndex);
|
||||
|
@ -168,6 +171,7 @@ private:
|
|||
void stitchEdgeCuts();
|
||||
void applyWeld();
|
||||
void applyDeform();
|
||||
void finalizeHollow();
|
||||
QVector3D calculateDeformPosition(const QVector3D &vertexPosition, const QVector3D &ray, const QVector3D &deformNormal, float deformFactor);
|
||||
bool swallowEdgeForNode(size_t nodeIndex, size_t edgeOrder);
|
||||
static QVector3D calculateBaseNormalFromTraverseDirection(const QVector3D &traverseDirection);
|
||||
|
|
Loading…
Reference in New Issue