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