Add stiffness setting for cloth simulation
parent
c4882dec1f
commit
44cd33d799
|
@ -752,6 +752,10 @@ Tips:
|
||||||
<source>Layer</source>
|
<source>Layer</source>
|
||||||
<translation>层</translation>
|
<translation>层</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Stiffness</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PartWidget</name>
|
<name>PartWidget</name>
|
||||||
|
|
|
@ -55,16 +55,13 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
// System parameters
|
// System parameters
|
||||||
namespace SystemParam {
|
//namespace SystemParam {
|
||||||
static const int n = 61; // must be odd, n * n = n_vertices | 61
|
// static const int n = 61; // must be odd, n * n = n_vertices | 61
|
||||||
static const float w = 2.0f; // width | 2.0f
|
// static const float h = 0.001f; // time step, smaller for better results | 0.008f = 0.016f/2
|
||||||
static const float h = 0.008f; // time step, smaller for better results | 0.008f = 0.016f/2
|
// static const float m = 0.25f / (n * n); // point mass | 0.25f
|
||||||
static const float r = w / (n - 1) * 1.05f; // spring rest legnth
|
// static const float a = 0.993f; // damping, close to 1.0 | 0.993f
|
||||||
static const float k = 1.0f; // spring stiffness | 1.0f;
|
// static const float g = 9.8f * m; // gravitational force | 9.8f
|
||||||
static const float m = 0.25f / (n * n); // point mass | 0.25f
|
//}
|
||||||
static const float a = 0.993f; // damping, close to 1.0 | 0.993f
|
|
||||||
static const float g = 9.8f * m; // gravitational force | 9.8f
|
|
||||||
}
|
|
||||||
|
|
||||||
// Point - mesh collision node
|
// Point - mesh collision node
|
||||||
class CgMeshCollisionNode : public CgPointNode {
|
class CgMeshCollisionNode : public CgPointNode {
|
||||||
|
@ -136,6 +133,11 @@ ClothSimulator::~ClothSimulator()
|
||||||
delete m_meshCollisionNode;
|
delete m_meshCollisionNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClothSimulator::setStiffness(float stiffness)
|
||||||
|
{
|
||||||
|
m_stiffness = 1.0f + 5.0f * stiffness;
|
||||||
|
}
|
||||||
|
|
||||||
void ClothSimulator::convertMeshToCloth()
|
void ClothSimulator::convertMeshToCloth()
|
||||||
{
|
{
|
||||||
m_clothPointSources.reserve(m_vertices.size());
|
m_clothPointSources.reserve(m_vertices.size());
|
||||||
|
@ -176,7 +178,7 @@ void ClothSimulator::getCurrentVertices(std::vector<QVector3D> *currentVertices)
|
||||||
size_t oldIndex = m_clothPointSources[newIndex];
|
size_t oldIndex = m_clothPointSources[newIndex];
|
||||||
auto offset = newIndex * 3;
|
auto offset = newIndex * 3;
|
||||||
(*currentVertices)[oldIndex] = QVector3D(m_clothPointBuffer[offset + 0],
|
(*currentVertices)[oldIndex] = QVector3D(m_clothPointBuffer[offset + 0],
|
||||||
m_clothPointBuffer[offset + 1],
|
m_clothPointBuffer[offset + 1] + 0.01,
|
||||||
m_clothPointBuffer[offset + 2]);
|
m_clothPointBuffer[offset + 2]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -200,7 +202,12 @@ void ClothSimulator::create()
|
||||||
if (m_clothPointSources.empty())
|
if (m_clothPointSources.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mass_spring_system::VectorXf masses(SystemParam::m * mass_spring_system::VectorXf::Ones((unsigned int)m_clothSprings.size()));
|
float mass = 0.25f / m_clothPointSources.size();
|
||||||
|
float gravitationalForce = 9.8f * mass;
|
||||||
|
float damping = 0.993f; // damping, close to 1.0 | 0.993f;
|
||||||
|
float timeStep = 0.001f; //smaller for better results | 0.008f = 0.016f/2;
|
||||||
|
|
||||||
|
mass_spring_system::VectorXf masses(mass * mass_spring_system::VectorXf::Ones((unsigned int)m_clothSprings.size()));
|
||||||
|
|
||||||
mass_spring_system::EdgeList springList(m_clothSprings.size());
|
mass_spring_system::EdgeList springList(m_clothSprings.size());
|
||||||
mass_spring_system::VectorXf restLengths(m_clothSprings.size());
|
mass_spring_system::VectorXf restLengths(m_clothSprings.size());
|
||||||
|
@ -210,13 +217,13 @@ void ClothSimulator::create()
|
||||||
const auto &source = m_clothSprings[i];
|
const auto &source = m_clothSprings[i];
|
||||||
springList[i] = mass_spring_system::Edge(source.first, source.second);
|
springList[i] = mass_spring_system::Edge(source.first, source.second);
|
||||||
restLengths[i] = (m_vertices[m_clothPointSources[source.first]] - m_vertices[m_clothPointSources[source.second]]).length();
|
restLengths[i] = (m_vertices[m_clothPointSources[source.first]] - m_vertices[m_clothPointSources[source.second]]).length();
|
||||||
stiffnesses[i] = SystemParam::k;
|
stiffnesses[i] = m_stiffness;
|
||||||
}
|
}
|
||||||
|
|
||||||
mass_spring_system::VectorXf fext = Eigen::Vector3f(0, -SystemParam::g, 0).replicate(m_clothPointSources.size(), 1);
|
mass_spring_system::VectorXf fext = Eigen::Vector3f(0, -gravitationalForce, 0).replicate(m_clothPointSources.size(), 1);
|
||||||
|
|
||||||
m_massSpringSystem = new mass_spring_system(m_clothPointSources.size(), m_clothSprings.size(), SystemParam::h, springList, restLengths,
|
m_massSpringSystem = new mass_spring_system(m_clothPointSources.size(), m_clothSprings.size(), timeStep, springList, restLengths,
|
||||||
stiffnesses, masses, fext, SystemParam::a);
|
stiffnesses, masses, fext, damping);
|
||||||
|
|
||||||
m_massSpringSolver = new MassSpringSolver(m_massSpringSystem, m_clothPointBuffer.data());
|
m_massSpringSolver = new MassSpringSolver(m_massSpringSystem, m_clothPointBuffer.data());
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ public:
|
||||||
const std::vector<QVector3D> &collisionVertices,
|
const std::vector<QVector3D> &collisionVertices,
|
||||||
const std::vector<std::vector<size_t>> &collisionTriangles);
|
const std::vector<std::vector<size_t>> &collisionTriangles);
|
||||||
~ClothSimulator();
|
~ClothSimulator();
|
||||||
|
void setStiffness(float stiffness);
|
||||||
void create();
|
void create();
|
||||||
void step();
|
void step();
|
||||||
void getCurrentVertices(std::vector<QVector3D> *currentVertices);
|
void getCurrentVertices(std::vector<QVector3D> *currentVertices);
|
||||||
|
@ -30,6 +31,7 @@ private:
|
||||||
std::vector<float> m_clothPointBuffer;
|
std::vector<float> m_clothPointBuffer;
|
||||||
std::vector<size_t> m_clothPointSources;
|
std::vector<size_t> m_clothPointSources;
|
||||||
std::vector<std::pair<size_t, size_t>> m_clothSprings;
|
std::vector<std::pair<size_t, size_t>> m_clothSprings;
|
||||||
|
float m_stiffness = 1.0f;
|
||||||
mass_spring_system *m_massSpringSystem = nullptr;
|
mass_spring_system *m_massSpringSystem = nullptr;
|
||||||
MassSpringSolver *m_massSpringSolver = nullptr;
|
MassSpringSolver *m_massSpringSolver = nullptr;
|
||||||
CgRootNode *m_rootNode = nullptr;
|
CgRootNode *m_rootNode = nullptr;
|
||||||
|
|
|
@ -1203,6 +1203,8 @@ void Document::toSnapshot(Snapshot *snapshot, const std::set<QUuid> &limitNodeId
|
||||||
component["polyCount"] = PolyCountToString(componentIt.second.polyCount);
|
component["polyCount"] = PolyCountToString(componentIt.second.polyCount);
|
||||||
if (componentIt.second.layer != ComponentLayer::Body)
|
if (componentIt.second.layer != ComponentLayer::Body)
|
||||||
component["layer"] = ComponentLayerToString(componentIt.second.layer);
|
component["layer"] = ComponentLayerToString(componentIt.second.layer);
|
||||||
|
if (componentIt.second.clothStiffnessAdjusted())
|
||||||
|
component["clothStiffness"] = QString::number(componentIt.second.clothStiffness);
|
||||||
QStringList childIdList;
|
QStringList childIdList;
|
||||||
for (const auto &childId: componentIt.second.childrenIds) {
|
for (const auto &childId: componentIt.second.childrenIds) {
|
||||||
childIdList.append(childId.toString());
|
childIdList.append(childId.toString());
|
||||||
|
@ -1711,6 +1713,9 @@ void Document::addFromSnapshot(const Snapshot &snapshot, bool fromPaste)
|
||||||
component.setSmoothSeam(smoothSeamIt->second.toFloat());
|
component.setSmoothSeam(smoothSeamIt->second.toFloat());
|
||||||
component.polyCount = PolyCountFromString(valueOfKeyInMapOrEmpty(componentKv.second, "polyCount").toUtf8().constData());
|
component.polyCount = PolyCountFromString(valueOfKeyInMapOrEmpty(componentKv.second, "polyCount").toUtf8().constData());
|
||||||
component.layer = ComponentLayerFromString(valueOfKeyInMapOrEmpty(componentKv.second, "layer").toUtf8().constData());
|
component.layer = ComponentLayerFromString(valueOfKeyInMapOrEmpty(componentKv.second, "layer").toUtf8().constData());
|
||||||
|
auto findClothStiffness = componentKv.second.find("clothStiffness");
|
||||||
|
if (findClothStiffness != componentKv.second.end())
|
||||||
|
component.clothStiffness = findClothStiffness->second.toFloat();
|
||||||
//qDebug() << "Add component:" << component.id << " old:" << componentKv.first << "name:" << component.name;
|
//qDebug() << "Add component:" << component.id << " old:" << componentKv.first << "name:" << component.name;
|
||||||
if ("partId" == linkDataType) {
|
if ("partId" == linkDataType) {
|
||||||
QUuid partId = oldNewIdMap[QUuid(linkData)];
|
QUuid partId = oldNewIdMap[QUuid(linkData)];
|
||||||
|
@ -2514,6 +2519,20 @@ void Document::setComponentLayer(QUuid componentId, ComponentLayer layer)
|
||||||
emit skeletonChanged();
|
emit skeletonChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Document::setComponentClothStiffness(QUuid componentId, float stiffness)
|
||||||
|
{
|
||||||
|
Component *component = (Component *)findComponent(componentId);
|
||||||
|
if (nullptr == component)
|
||||||
|
return;
|
||||||
|
if (qFuzzyCompare(component->clothStiffness, stiffness))
|
||||||
|
return;
|
||||||
|
|
||||||
|
component->clothStiffness = stiffness;
|
||||||
|
component->dirty = true;
|
||||||
|
emit componentClothStiffnessChanged(componentId);
|
||||||
|
emit skeletonChanged();
|
||||||
|
}
|
||||||
|
|
||||||
void Document::createNewComponentAndMoveThisIn(QUuid componentId)
|
void Document::createNewComponentAndMoveThisIn(QUuid componentId)
|
||||||
{
|
{
|
||||||
auto component = componentMap.find(componentId);
|
auto component = componentMap.find(componentId);
|
||||||
|
|
|
@ -69,6 +69,7 @@ public:
|
||||||
float smoothSeam = 0.0;
|
float smoothSeam = 0.0;
|
||||||
PolyCount polyCount = PolyCount::Original;
|
PolyCount polyCount = PolyCount::Original;
|
||||||
ComponentLayer layer = ComponentLayer::Body;
|
ComponentLayer layer = ComponentLayer::Body;
|
||||||
|
float clothStiffness = 1.0f;
|
||||||
std::vector<QUuid> childrenIds;
|
std::vector<QUuid> childrenIds;
|
||||||
QString linkData() const
|
QString linkData() const
|
||||||
{
|
{
|
||||||
|
@ -188,6 +189,10 @@ public:
|
||||||
{
|
{
|
||||||
return smoothAllAdjusted() || smoothSeamAdjusted();
|
return smoothAllAdjusted() || smoothSeamAdjusted();
|
||||||
}
|
}
|
||||||
|
bool clothStiffnessAdjusted() const
|
||||||
|
{
|
||||||
|
return fabs(clothStiffness - 1.0) >= 0.01;
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
std::set<QUuid> m_childrenIdSet;
|
std::set<QUuid> m_childrenIdSet;
|
||||||
};
|
};
|
||||||
|
@ -399,6 +404,7 @@ signals:
|
||||||
void componentSmoothSeamChanged(QUuid componentId);
|
void componentSmoothSeamChanged(QUuid componentId);
|
||||||
void componentPolyCountChanged(QUuid componentId);
|
void componentPolyCountChanged(QUuid componentId);
|
||||||
void componentLayerChanged(QUuid componentId);
|
void componentLayerChanged(QUuid componentId);
|
||||||
|
void componentClothStiffnessChanged(QUuid componentId);
|
||||||
void nodeRemoved(QUuid nodeId);
|
void nodeRemoved(QUuid nodeId);
|
||||||
void edgeRemoved(QUuid edgeId);
|
void edgeRemoved(QUuid edgeId);
|
||||||
void nodeRadiusChanged(QUuid nodeId);
|
void nodeRadiusChanged(QUuid nodeId);
|
||||||
|
@ -646,6 +652,7 @@ public slots:
|
||||||
void setComponentSmoothSeam(QUuid componentId, float toSmoothSeam);
|
void setComponentSmoothSeam(QUuid componentId, float toSmoothSeam);
|
||||||
void setComponentPolyCount(QUuid componentId, PolyCount count);
|
void setComponentPolyCount(QUuid componentId, PolyCount count);
|
||||||
void setComponentLayer(QUuid componentId, ComponentLayer layer);
|
void setComponentLayer(QUuid componentId, ComponentLayer layer);
|
||||||
|
void setComponentClothStiffness(QUuid componentId, float stiffness);
|
||||||
void hideOtherComponents(QUuid componentId);
|
void hideOtherComponents(QUuid componentId);
|
||||||
void lockOtherComponents(QUuid componentId);
|
void lockOtherComponents(QUuid componentId);
|
||||||
void hideAllComponents();
|
void hideAllComponents();
|
||||||
|
|
|
@ -1029,6 +1029,7 @@ DocumentWindow::DocumentWindow() :
|
||||||
connect(partTreeWidget, &PartTreeWidget::setPartVisibleState, m_document, &Document::setPartVisibleState);
|
connect(partTreeWidget, &PartTreeWidget::setPartVisibleState, m_document, &Document::setPartVisibleState);
|
||||||
connect(partTreeWidget, &PartTreeWidget::setPartColorState, m_document, &Document::setPartColorState);
|
connect(partTreeWidget, &PartTreeWidget::setPartColorState, m_document, &Document::setPartColorState);
|
||||||
connect(partTreeWidget, &PartTreeWidget::setComponentCombineMode, m_document, &Document::setComponentCombineMode);
|
connect(partTreeWidget, &PartTreeWidget::setComponentCombineMode, m_document, &Document::setComponentCombineMode);
|
||||||
|
connect(partTreeWidget, &PartTreeWidget::setComponentClothStiffness, m_document, &Document::setComponentClothStiffness);
|
||||||
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::setPartBase, m_document, &Document::setPartBase);
|
||||||
connect(partTreeWidget, &PartTreeWidget::hideDescendantComponents, m_document, &Document::hideDescendantComponents);
|
connect(partTreeWidget, &PartTreeWidget::hideDescendantComponents, m_document, &Document::hideDescendantComponents);
|
||||||
|
|
|
@ -893,6 +893,16 @@ ComponentLayer MeshGenerator::componentLayer(const std::map<QString, QString> *c
|
||||||
return ComponentLayerFromString(valueOfKeyInMapOrEmpty(*component, "layer").toUtf8().constData());
|
return ComponentLayerFromString(valueOfKeyInMapOrEmpty(*component, "layer").toUtf8().constData());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float MeshGenerator::componentClothStiffness(const std::map<QString, QString> *component)
|
||||||
|
{
|
||||||
|
if (nullptr == component)
|
||||||
|
return 1.0f;
|
||||||
|
auto findClothStiffness = component->find("clothStiffness");
|
||||||
|
if (findClothStiffness == component->end())
|
||||||
|
return 1.0f;
|
||||||
|
return findClothStiffness->second.toFloat();
|
||||||
|
}
|
||||||
|
|
||||||
MeshCombiner::Mesh *MeshGenerator::combineComponentMesh(const QString &componentIdString, CombineMode *combineMode)
|
MeshCombiner::Mesh *MeshGenerator::combineComponentMesh(const QString &componentIdString, CombineMode *combineMode)
|
||||||
{
|
{
|
||||||
MeshCombiner::Mesh *mesh = nullptr;
|
MeshCombiner::Mesh *mesh = nullptr;
|
||||||
|
@ -1613,10 +1623,13 @@ void MeshGenerator::collectClothComponent(const QString &componentIdString)
|
||||||
isotropicRemesh(uncombinedVertices, uncombinedFaces, uncombinedVertices, uncombinedFaces, 0.02f, 3);
|
isotropicRemesh(uncombinedVertices, uncombinedFaces, uncombinedVertices, uncombinedFaces, 0.02f, 3);
|
||||||
|
|
||||||
std::map<PositionKey, std::pair<QUuid, QUuid>> positionMap;
|
std::map<PositionKey, std::pair<QUuid, QUuid>> positionMap;
|
||||||
|
std::pair<QUuid, QUuid> defaultSource;
|
||||||
for (const auto &it: componentCache.outcomeNodeVertices) {
|
for (const auto &it: componentCache.outcomeNodeVertices) {
|
||||||
|
if (!it.second.first.isNull())
|
||||||
|
defaultSource.first = it.second.first;
|
||||||
positionMap.insert({PositionKey(it.first), it.second});
|
positionMap.insert({PositionKey(it.first), it.second});
|
||||||
}
|
}
|
||||||
std::vector<std::pair<QUuid, QUuid>> uncombinedVertexSources(uncombinedVertices.size());
|
std::vector<std::pair<QUuid, QUuid>> uncombinedVertexSources(uncombinedVertices.size(), defaultSource);
|
||||||
for (size_t i = 0; i < uncombinedVertices.size(); ++i) {
|
for (size_t i = 0; i < uncombinedVertices.size(); ++i) {
|
||||||
auto findSource = positionMap.find(PositionKey(uncombinedVertices[i]));
|
auto findSource = positionMap.find(PositionKey(uncombinedVertices[i]));
|
||||||
if (findSource == positionMap.end())
|
if (findSource == positionMap.end())
|
||||||
|
@ -1628,8 +1641,9 @@ void MeshGenerator::collectClothComponent(const QString &componentIdString)
|
||||||
uncombinedFaces,
|
uncombinedFaces,
|
||||||
m_clothCollisionVertices,
|
m_clothCollisionVertices,
|
||||||
m_clothCollisionTriangles);
|
m_clothCollisionTriangles);
|
||||||
|
clothSimulator.setStiffness(componentClothStiffness(component));
|
||||||
clothSimulator.create();
|
clothSimulator.create();
|
||||||
for (size_t i = 0; i < 30; ++i)
|
for (size_t i = 0; i < 400; ++i)
|
||||||
clothSimulator.step();
|
clothSimulator.step();
|
||||||
clothSimulator.getCurrentVertices(&uncombinedVertices);
|
clothSimulator.getCurrentVertices(&uncombinedVertices);
|
||||||
|
|
||||||
|
|
|
@ -129,6 +129,7 @@ private:
|
||||||
MeshCombiner::Mesh *combineMultipleMeshes(const std::vector<std::tuple<MeshCombiner::Mesh *, CombineMode, QString>> &multipleMeshes, bool recombine=true);
|
MeshCombiner::Mesh *combineMultipleMeshes(const std::vector<std::tuple<MeshCombiner::Mesh *, CombineMode, QString>> &multipleMeshes, bool recombine=true);
|
||||||
QString componentColorName(const std::map<QString, QString> *component);
|
QString componentColorName(const std::map<QString, QString> *component);
|
||||||
ComponentLayer componentLayer(const std::map<QString, QString> *component);
|
ComponentLayer componentLayer(const std::map<QString, QString> *component);
|
||||||
|
float componentClothStiffness(const std::map<QString, QString> *component);
|
||||||
void collectUncombinedComponent(const QString &componentIdString);
|
void collectUncombinedComponent(const QString &componentIdString);
|
||||||
void collectClothComponent(const QString &componentIdString);
|
void collectClothComponent(const QString &componentIdString);
|
||||||
void cutFaceStringToCutTemplate(const QString &cutFaceString, std::vector<QVector2D> &cutTemplate);
|
void cutFaceStringToCutTemplate(const QString &cutFaceString, std::vector<QVector2D> &cutTemplate);
|
||||||
|
|
|
@ -214,6 +214,51 @@ void PartTreeWidget::mousePressEvent(QMouseEvent *event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PartTreeWidget::showClothSettingMenu(const QPoint &pos, const QUuid &componentId)
|
||||||
|
{
|
||||||
|
const Component *component = nullptr;
|
||||||
|
|
||||||
|
if (componentId.isNull())
|
||||||
|
return;
|
||||||
|
|
||||||
|
component = m_document->findComponent(componentId);
|
||||||
|
if (nullptr == component)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QMenu popupMenu;
|
||||||
|
|
||||||
|
QWidget *popup = new QWidget;
|
||||||
|
|
||||||
|
FloatNumberWidget *clothStiffnessWidget = new FloatNumberWidget;
|
||||||
|
clothStiffnessWidget->setItemName(tr("Stiffness"));
|
||||||
|
clothStiffnessWidget->setRange(0.0f, 1.0f);
|
||||||
|
clothStiffnessWidget->setValue(component->clothStiffness);
|
||||||
|
|
||||||
|
connect(clothStiffnessWidget, &FloatNumberWidget::valueChanged, [=](float value) {
|
||||||
|
emit setComponentClothStiffness(componentId, value);
|
||||||
|
emit groupOperationAdded();
|
||||||
|
});
|
||||||
|
|
||||||
|
QPushButton *clothStiffnessEraser = new QPushButton(QChar(fa::eraser));
|
||||||
|
Theme::initAwesomeToolButton(clothStiffnessEraser);
|
||||||
|
|
||||||
|
QHBoxLayout *clothStiffnessLayout = new QHBoxLayout;
|
||||||
|
clothStiffnessLayout->addWidget(clothStiffnessEraser);
|
||||||
|
clothStiffnessLayout->addWidget(clothStiffnessWidget);
|
||||||
|
|
||||||
|
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||||
|
mainLayout->addLayout(clothStiffnessLayout);
|
||||||
|
|
||||||
|
popup->setLayout(mainLayout);
|
||||||
|
|
||||||
|
QWidgetAction action(this);
|
||||||
|
action.setDefaultWidget(popup);
|
||||||
|
|
||||||
|
popupMenu.addAction(&action);
|
||||||
|
|
||||||
|
popupMenu.exec(mapToGlobal(pos));
|
||||||
|
}
|
||||||
|
|
||||||
void PartTreeWidget::showContextMenu(const QPoint &pos)
|
void PartTreeWidget::showContextMenu(const QPoint &pos)
|
||||||
{
|
{
|
||||||
const Component *component = nullptr;
|
const Component *component = nullptr;
|
||||||
|
@ -315,6 +360,13 @@ void PartTreeWidget::showContextMenu(const QPoint &pos)
|
||||||
}
|
}
|
||||||
QWidget *widget = new QWidget;
|
QWidget *widget = new QWidget;
|
||||||
if (nullptr != component) {
|
if (nullptr != component) {
|
||||||
|
QPushButton *clothSettingButton = new QPushButton();
|
||||||
|
connect(clothSettingButton, &QPushButton::clicked, this, [=]() {
|
||||||
|
showClothSettingMenu(mapFromGlobal(QCursor::pos()), component->id);
|
||||||
|
});
|
||||||
|
clothSettingButton->setIcon(Theme::awesome()->icon(fa::gear));
|
||||||
|
if (ComponentLayer::Cloth != component->layer)
|
||||||
|
clothSettingButton->hide();
|
||||||
QComboBox *componentLayerSelectBox = new QComboBox;
|
QComboBox *componentLayerSelectBox = new QComboBox;
|
||||||
for (size_t i = 0; i < (size_t)ComponentLayer::Count; ++i) {
|
for (size_t i = 0; i < (size_t)ComponentLayer::Count; ++i) {
|
||||||
ComponentLayer layer = (ComponentLayer)i;
|
ComponentLayer layer = (ComponentLayer)i;
|
||||||
|
@ -322,9 +374,14 @@ void PartTreeWidget::showContextMenu(const QPoint &pos)
|
||||||
}
|
}
|
||||||
componentLayerSelectBox->setCurrentIndex((int)component->layer);
|
componentLayerSelectBox->setCurrentIndex((int)component->layer);
|
||||||
connect(componentLayerSelectBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, [=](int index) {
|
connect(componentLayerSelectBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, [=](int index) {
|
||||||
|
clothSettingButton->setVisible(ComponentLayer::Cloth == (ComponentLayer)index);
|
||||||
emit setComponentLayer(component->id, (ComponentLayer)index);
|
emit setComponentLayer(component->id, (ComponentLayer)index);
|
||||||
emit groupOperationAdded();
|
emit groupOperationAdded();
|
||||||
});
|
});
|
||||||
|
QHBoxLayout *componentLayerLayout = new QHBoxLayout;
|
||||||
|
componentLayerLayout->addWidget(componentLayerSelectBox);
|
||||||
|
componentLayerLayout->addWidget(clothSettingButton);
|
||||||
|
componentLayerLayout->setStretch(0, 1);
|
||||||
|
|
||||||
QComboBox *combineModeSelectBox = new QComboBox;
|
QComboBox *combineModeSelectBox = new QComboBox;
|
||||||
for (size_t i = 0; i < (size_t)CombineMode::Count; ++i) {
|
for (size_t i = 0; i < (size_t)CombineMode::Count; ++i) {
|
||||||
|
@ -379,7 +436,7 @@ void PartTreeWidget::showContextMenu(const QPoint &pos)
|
||||||
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);
|
||||||
componentSettingsLayout->addRow(tr("Layer"), componentLayerSelectBox);
|
componentSettingsLayout->addRow(tr("Layer"), componentLayerLayout);
|
||||||
|
|
||||||
QVBoxLayout *newLayout = new QVBoxLayout;
|
QVBoxLayout *newLayout = new QVBoxLayout;
|
||||||
newLayout->addLayout(layout);
|
newLayout->addLayout(layout);
|
||||||
|
|
|
@ -41,6 +41,7 @@ signals:
|
||||||
void setPartVisibleState(QUuid partId, bool visible);
|
void setPartVisibleState(QUuid partId, bool visible);
|
||||||
void setPartColorState(QUuid partId, bool hasColor, QColor color);
|
void setPartColorState(QUuid partId, bool hasColor, QColor color);
|
||||||
void setComponentCombineMode(QUuid componentId, CombineMode combineMode);
|
void setComponentCombineMode(QUuid componentId, CombineMode combineMode);
|
||||||
|
void setComponentClothStiffness(QUuid componentId, float clothStiffness);
|
||||||
void hideDescendantComponents(QUuid componentId);
|
void hideDescendantComponents(QUuid componentId);
|
||||||
void showDescendantComponents(QUuid componentId);
|
void showDescendantComponents(QUuid componentId);
|
||||||
void lockDescendantComponents(QUuid componentId);
|
void lockDescendantComponents(QUuid componentId);
|
||||||
|
@ -83,6 +84,7 @@ public slots:
|
||||||
void groupCollapsed(QTreeWidgetItem *item);
|
void groupCollapsed(QTreeWidgetItem *item);
|
||||||
void removeAllContent();
|
void removeAllContent();
|
||||||
void showContextMenu(const QPoint &pos);
|
void showContextMenu(const QPoint &pos);
|
||||||
|
void showClothSettingMenu(const QPoint &pos, const QUuid &componentId);
|
||||||
protected:
|
protected:
|
||||||
QSize sizeHint() const override;
|
QSize sizeHint() const override;
|
||||||
void mousePressEvent(QMouseEvent *event) override;
|
void mousePressEvent(QMouseEvent *event) override;
|
||||||
|
|
Loading…
Reference in New Issue