diff --git a/dust3d.pro b/dust3d.pro index 54650a86..034a9c2e 100644 --- a/dust3d.pro +++ b/dust3d.pro @@ -65,10 +65,10 @@ macx { } isEmpty(HUMAN_VERSION) { - HUMAN_VERSION = "1.0.0-beta.30" + HUMAN_VERSION = "1.0.0-rc.1" } isEmpty(VERSION) { - VERSION = 1.0.0.30 + VERSION = 1.0.0.31 } HOMEPAGE_URL = "https://dust3d.org/" @@ -568,8 +568,8 @@ HEADERS += thirdparty/bullet3/src/BulletCollision/CollisionShapes/btConvexShape. SOURCES += thirdparty/bullet3/src/BulletCollision/CollisionShapes/btConvexInternalShape.cpp HEADERS += thirdparty/bullet3/src/BulletCollision/CollisionShapes/btConvexInternalShape.h -SOURCES += thirdparty/bullet3/src/BulletDynamics/ConstraintSolver/btHingeConstraint.cpp -HEADERS += thirdparty/bullet3/src/BulletDynamics/ConstraintSolver/btHingeConstraint.h +SOURCES += thirdparty/bullet3/src/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.cpp +HEADERS += thirdparty/bullet3/src/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h SOURCES += thirdparty/bullet3/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.cpp HEADERS += thirdparty/bullet3/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.h diff --git a/languages/dust3d_zh_CN.ts b/languages/dust3d_zh_CN.ts index e68943f0..858677a9 100644 --- a/languages/dust3d_zh_CN.ts +++ b/languages/dust3d_zh_CN.ts @@ -549,10 +549,6 @@ Tips: Motions 动作 - - Procedural Animations - 程序化动画 - MotionListWidget diff --git a/resources/model-dog.ds3 b/resources/model-dog.ds3 index 814cdefe..e55a73ca 100644 --- a/resources/model-dog.ds3 +++ b/resources/model-dog.ds3 @@ -1,287 +1,287 @@ DUST3D 1.0 xml 0000000194 - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - + + + + - - - - + + + + - - - - + + + + diff --git a/resources/model-giraffe.ds3 b/resources/model-giraffe.ds3 index a6006ea5..29cab47f 100644 --- a/resources/model-giraffe.ds3 +++ b/resources/model-giraffe.ds3 @@ -1,273 +1,273 @@ DUST3D 1.0 xml 0000000494 - - - - - + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - + diff --git a/resources/model-seagull.ds3 b/resources/model-seagull.ds3 index 7e1476f5..f272ea15 100644 --- a/resources/model-seagull.ds3 +++ b/resources/model-seagull.ds3 @@ -1,110 +1,110 @@ DUST3D 1.0 xml 0000000194 - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - + - - + + - - + + @@ -112,15 +112,15 @@ DUST3D 1.0 xml 0000000194 - + - - + + - - + + @@ -130,13 +130,13 @@ DUST3D 1.0 xml 0000000194 - + - + - + - + diff --git a/src/jointnodetree.cpp b/src/jointnodetree.cpp index 42d1439d..5a9c435f 100644 --- a/src/jointnodetree.cpp +++ b/src/jointnodetree.cpp @@ -30,19 +30,17 @@ void JointNodeTree::reset() } void JointNodeTree::calculateBonePositions(std::vector> *bonePositions, + const JointNodeTree *jointNodeTree, const std::vector *rigBones) const { - if (nullptr == bonePositions) + if (nullptr == bonePositions || nullptr == jointNodeTree || nullptr == rigBones) return; - (*bonePositions).resize(m_boneNodes.size()); - for (int i = 0; i < (int)m_boneNodes.size(); i++) { - const auto &node = m_boneNodes[i]; - QVector3D headPosition = node.transformMatrix * node.position; - QVector3D tailPosition = node.transformMatrix * (node.position + ((*rigBones)[i].tailPosition - (*rigBones)[i].headPosition)); - if (-1 != node.parentIndex) - (*bonePositions)[node.parentIndex].second = headPosition; - (*bonePositions)[i] = std::make_pair(headPosition, tailPosition); + (*bonePositions).resize(jointNodeTree->nodes().size()); + for (int i = 0; i < (int)jointNodeTree->nodes().size(); i++) { + const auto &node = jointNodeTree->nodes()[i]; + (*bonePositions)[i] = std::make_pair(node.transformMatrix * node.position, + node.transformMatrix * (node.position + ((*rigBones)[i].tailPosition - (*rigBones)[i].headPosition))); } } diff --git a/src/jointnodetree.h b/src/jointnodetree.h index 94a2cb5d..e172e03e 100644 --- a/src/jointnodetree.h +++ b/src/jointnodetree.h @@ -29,6 +29,7 @@ public: void reset(); void recalculateTransformMatrices(); void calculateBonePositions(std::vector> *bonePositions, + const JointNodeTree *jointNodeTree, const std::vector *rigBones) const; static JointNodeTree slerp(const JointNodeTree &first, const JointNodeTree &second, float t); private: diff --git a/src/meshgenerator.cpp b/src/meshgenerator.cpp index 330840c5..d74e9ec8 100644 --- a/src/meshgenerator.cpp +++ b/src/meshgenerator.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "strokemeshbuilder.h" #include "strokemodifier.h" #include "meshrecombiner.h" @@ -1487,6 +1488,13 @@ void MeshGenerator::generate() std::vector> sourceNodes; triangleSourceNodeResolve(*outcome, sourceNodes, &outcome->vertexSourceNodes); + { + for (const auto &it: outcome->vertexSourceNodes) { + if (!it.first.isNull() && !it.second.isNull()) + continue; + std::cout << "source node:" << it.first.toString().toUtf8().constData() << " " << it.second.toString().toUtf8().constData() << std::endl; + } + } outcome->setTriangleSourceNodes(sourceNodes); std::map, QColor> sourceNodeToColorMap; @@ -1661,6 +1669,7 @@ void MeshGenerator::collectClothComponent(const QString &componentIdString) clothMesh.clothStiffness = componentClothStiffness(component); clothMesh.clothIteration = componentClothIteration(component); clothMesh.outcomeNodeVertices = &componentCache.outcomeNodeVertices; + m_outcome->clothNodes.insert(m_outcome->clothNodes.end(), componentCache.outcomeNodes.begin(), componentCache.outcomeNodes.end()); m_outcome->nodes.insert(m_outcome->nodes.end(), componentCache.outcomeNodes.begin(), componentCache.outcomeNodes.end()); m_outcome->edges.insert(m_outcome->edges.end(), componentCache.outcomeEdges.begin(), componentCache.outcomeEdges.end()); } diff --git a/src/motioneditwidget.cpp b/src/motioneditwidget.cpp index bbb90d4e..776f0a03 100644 --- a/src/motioneditwidget.cpp +++ b/src/motioneditwidget.cpp @@ -52,20 +52,20 @@ MotionEditWidget::MotionEditWidget(const Document *document, QWidget *parent) : m_timelineWidget->addPose(poseId); }); - FlowLayout *proceduralAnimationListLayout = new FlowLayout; - for (size_t i = 0; i < (int)ProceduralAnimation::Count - 1; ++i) { - auto proceduralAnimation = (ProceduralAnimation)(i + 1); - QString dispName = ProceduralAnimationToDispName(proceduralAnimation); - QPushButton *addButton = new QPushButton(Theme::awesome()->icon(fa::plus), dispName); - connect(addButton, &QPushButton::clicked, this, [=]() { - m_timelineWidget->addProceduralAnimation(proceduralAnimation); - }); - proceduralAnimationListLayout->addWidget(addButton); - } - QWidget *proceduralAnimationListContainerWidget = new QWidget; - proceduralAnimationListContainerWidget->setLayout(proceduralAnimationListLayout); + //FlowLayout *proceduralAnimationListLayout = new FlowLayout; + //for (size_t i = 0; i < (int)ProceduralAnimation::Count - 1; ++i) { + // auto proceduralAnimation = (ProceduralAnimation)(i + 1); + // QString dispName = ProceduralAnimationToDispName(proceduralAnimation); + // QPushButton *addButton = new QPushButton(Theme::awesome()->icon(fa::plus), dispName); + // connect(addButton, &QPushButton::clicked, this, [=]() { + // m_timelineWidget->addProceduralAnimation(proceduralAnimation); + // }); + // proceduralAnimationListLayout->addWidget(addButton); + //} + //QWidget *proceduralAnimationListContainerWidget = new QWidget; + //proceduralAnimationListContainerWidget->setLayout(proceduralAnimationListLayout); - proceduralAnimationListContainerWidget->resize(512, Theme::motionPreviewImageSize); + //proceduralAnimationListContainerWidget->resize(512, Theme::motionPreviewImageSize); MotionListWidget *motionListWidget = new MotionListWidget(document); motionListWidget->setCornerButtonVisible(true); @@ -79,7 +79,7 @@ MotionEditWidget::MotionEditWidget(const Document *document, QWidget *parent) : QStackedWidget *stackedWidget = new QStackedWidget; stackedWidget->addWidget(poseListContainerWidget); - stackedWidget->addWidget(proceduralAnimationListContainerWidget); + //stackedWidget->addWidget(proceduralAnimationListContainerWidget); stackedWidget->addWidget(motionListContainerWidget); connect(motionListWidget, &MotionListWidget::cornerButtonClicked, this, [=](QUuid motionId) { @@ -88,7 +88,7 @@ MotionEditWidget::MotionEditWidget(const Document *document, QWidget *parent) : std::vector tabs = { tr("Poses"), - tr("Procedural Animations"), + //tr("Procedural Animations"), tr("Motions") }; TabWidget *tabWidget = new TabWidget(tabs); diff --git a/src/motionsgenerator.cpp b/src/motionsgenerator.cpp index 8aa2aea0..630abb5d 100644 --- a/src/motionsgenerator.cpp +++ b/src/motionsgenerator.cpp @@ -26,11 +26,13 @@ MotionsGenerator::~MotionsGenerator() delete subItem.second; } } - for (const auto &item: m_proceduralPreviews) { +#if ENABLE_PROCEDURAL_DEBUG + for (const auto &item: m_proceduralDebugPreviews) { for (const auto &subItem: item.second) { delete subItem; } } +#endif delete m_poser; } @@ -111,7 +113,9 @@ const std::vector> &MotionsGenerator::getProcedu return findResult->second; std::vector> &resultFrames = m_proceduralAnimations[(int)proceduralAnimation]; if (ProceduralAnimation::FallToDeath == proceduralAnimation) { - //std::vector &resultPreviews = m_proceduralPreviews[(int)proceduralAnimation]; +#if ENABLE_PROCEDURAL_DEBUG + std::vector &resultPreviews = m_proceduralDebugPreviews[(int)proceduralAnimation]; +#endif RagDoll ragdoll(&m_rigBones, initialJointNodeTree); float stepSeconds = 1.0 / 60; float maxSeconds = 1.5; @@ -119,8 +123,10 @@ const std::vector> &MotionsGenerator::getProcedu int steps = 0; while (steps < maxSteps && ragdoll.stepSimulation(stepSeconds)) { resultFrames.push_back(std::make_pair(stepSeconds * 2, ragdoll.getStepJointNodeTree())); - //MeshLoader *preview = buildBoundingBoxMesh(ragdoll.getStepBonePositions()); - //resultPreviews.push_back(preview); +#if ENABLE_PROCEDURAL_DEBUG + MeshLoader *preview = buildBoundingBoxMesh(ragdoll.getStepBonePositions()); + resultPreviews.push_back(preview); +#endif ++steps; } } @@ -294,8 +300,10 @@ void MotionsGenerator::generateMotion(const QUuid &motionId, std::set &vi if (frame >= (int)frames.size()) frame = frames.size() - 1; if (frame >= 0 && frame < (int)frames.size()) { - //if (nullptr != previews) - // previews->push_back(m_proceduralPreviews[(int)progressClip.proceduralAnimation][frame]); +#if ENABLE_PROCEDURAL_DEBUG + if (nullptr != previews) + previews->push_back(m_proceduralDebugPreviews[(int)progressClip.proceduralAnimation][frame]); +#endif outcomes.push_back({progress - lastProgress, frames[frame].second}); lastProgress = progress; } @@ -404,10 +412,14 @@ void MotionsGenerator::generate() for (const auto &motionId: m_requiredMotionIds) { std::set visited; - //std::vector previews; +#if ENABLE_PROCEDURAL_DEBUG + std::vector previews; + generateMotion(motionId, visited, m_resultJointNodeTrees[motionId], &previews); +#else generateMotion(motionId, visited, m_resultJointNodeTrees[motionId]); +#endif generatePreviewsForOutcomes(m_resultJointNodeTrees[motionId], m_resultPreviewMeshs[motionId]); - /* +#if ENABLE_PROCEDURAL_DEBUG if (!previews.empty()) { const auto &tree = m_resultJointNodeTrees[motionId]; auto &target = m_resultPreviewMeshs[motionId]; @@ -421,9 +433,10 @@ void MotionsGenerator::generate() edgeVertices[j] = source[j]; } target[i].second->updateEdges(edgeVertices, edgeVertexCount); - target[i].second->updateTriangleVertices(nullptr, 0); + //target[i].second->updateTriangleVertices(nullptr, 0); } - }*/ + } +#endif m_generatedMotionIds.insert(motionId); } } diff --git a/src/motionsgenerator.h b/src/motionsgenerator.h index 4b114730..a632e3c4 100644 --- a/src/motionsgenerator.h +++ b/src/motionsgenerator.h @@ -10,6 +10,8 @@ #include "document.h" #include "poser.h" +#define ENABLE_PROCEDURAL_DEBUG 1 + class MotionsGenerator : public QObject { Q_OBJECT @@ -54,7 +56,9 @@ private: std::vector m_rigBones; std::map m_rigWeights; std::map>> m_proceduralAnimations; - std::map> m_proceduralPreviews; +#if ENABLE_PROCEDURAL_DEBUG + std::map> m_proceduralDebugPreviews; +#endif Outcome m_outcome; std::map, std::map>>>> m_poses; std::map m_posesYtranslationScales; diff --git a/src/outcome.h b/src/outcome.h index a352c23d..d50222e0 100644 --- a/src/outcome.h +++ b/src/outcome.h @@ -56,6 +56,7 @@ class Outcome public: std::vector nodes; std::vector bodyNodes; + std::vector clothNodes; std::vector, std::pair>> edges; std::vector, std::pair>> bodyEdges; std::vector>> nodeVertices; diff --git a/src/ragdoll.cpp b/src/ragdoll.cpp index 03e6b67c..6e5a71ba 100644 --- a/src/ragdoll.cpp +++ b/src/ragdoll.cpp @@ -3,46 +3,51 @@ #include #include #include -#include -#include -#include +#include +#include #include #include #include #include #include +#include #include "ragdoll.h" #include "poser.h" RagDoll::RagDoll(const std::vector *rigBones, const JointNodeTree *initialJointNodeTree) : m_jointNodeTree(rigBones), - m_stepJointNodeTree(rigBones) + m_stepJointNodeTree(nullptr == initialJointNodeTree ? rigBones : *initialJointNodeTree) { if (nullptr == rigBones || rigBones->empty()) return; + if (m_stepJointNodeTree.nodes().size() != m_jointNodeTree.nodes().size()) + return; + m_bones = *rigBones; - std::vector> bonePositions; if (nullptr != initialJointNodeTree) { - m_jointNodeTree.calculateBonePositions(&bonePositions, + m_jointNodeTree.calculateBonePositions(&m_boneInitialPositions, + initialJointNodeTree, rigBones); } else { - bonePositions.resize(m_bones.size()); + m_boneInitialPositions.resize(m_bones.size()); for (size_t i = 0; i < m_bones.size(); ++i) { const auto &bone = m_bones[i]; - bonePositions[i] = std::make_pair(bone.headPosition, bone.tailPosition); + m_boneInitialPositions[i] = std::make_pair(bone.headPosition, bone.tailPosition); } } for (const auto &bone: m_bones) { - auto radius = qMax(bone.headRadius, bone.tailRadius); - m_stepBonePositions.push_back(std::make_tuple(bone.headPosition, bone.tailPosition, radius)); - float groundY = bone.headPosition.y() - radius; + const auto &bonePosition = m_boneInitialPositions[bone.index]; + auto radius = (bone.headRadius + bone.tailRadius) * 0.5; + m_stepBonePositions.push_back(std::make_tuple(bonePosition.first, + bonePosition.second, bone.headRadius, bone.tailRadius, bone.color)); + float groundY = bonePosition.first.y() - radius; if (groundY < m_groundY) m_groundY = groundY; - groundY = bone.tailPosition.y() - radius; + groundY = bonePosition.second.y() - radius; if (groundY < m_groundY) m_groundY = groundY; } @@ -57,9 +62,9 @@ RagDoll::RagDoll(const std::vector *rigBones, Poser::fetchChains(boneNames, m_chains); for (const auto &bone: *rigBones) { - const auto &headPosition = bonePositions[bone.index].first; - const auto &tailPosition = bonePositions[bone.index].second; - float radius = (bone.headRadius + bone.tailRadius) * 0.5; + const auto &headPosition = m_boneInitialPositions[bone.index].first; + const auto &tailPosition = m_boneInitialPositions[bone.index].second; + float radius = qMin(bone.headRadius, bone.tailRadius); float height = headPosition.distanceToPoint(tailPosition); QVector3D middlePosition = (headPosition + tailPosition) * 0.5; m_boneLengthMap[bone.name] = height; @@ -70,13 +75,26 @@ RagDoll::RagDoll(const std::vector *rigBones, std::set> constraintPairs; for (const auto &bone: m_bones) { - const auto &headPosition = bonePositions[bone.index].first; - const auto &tailPosition = bonePositions[bone.index].second; + if (0 == bone.index) + continue; + + const auto &headPosition = m_boneInitialPositions[bone.index].first; + const auto &tailPosition = m_boneInitialPositions[bone.index].second; float height = m_boneLengthMap[bone.name]; float radius = m_boneRadiusMap[bone.name]; - float mass = 1.0; + float mass = radius * height; - btCollisionShape *shape = new btCapsuleShape(btScalar(radius), btScalar(height)); + btCollisionShape *shape = nullptr; + + if (bone.name.startsWith("Spine")) { + float halfHeight = height * 0.5f; + float revisedRadius = radius < halfHeight ? radius : halfHeight; + mass *= 5.0f; + shape = new btBoxShape(btVector3(revisedRadius, halfHeight, revisedRadius * 0.1f)); + } else { + shape = new btCapsuleShape(btScalar(radius), btScalar(height)); + } + shape->setUserIndex(bone.index); m_boneShapes[bone.name] = shape; @@ -97,51 +115,27 @@ RagDoll::RagDoll(const std::vector *rigBones, transform.getBasis().setRotation(btRotation); btRigidBody *body = createRigidBody(btScalar(mass), transform, shape); + + //body->setDamping(btScalar(0.05), btScalar(0.85)); + //body->setDeactivationTime(btScalar(0.8)); + //body->setSleepingThresholds(btScalar(1.6), btScalar(2.5)); + m_boneBodies[bone.name] = body; } - // Setup some damping on the m_bodies for (const auto &bone: m_bones) { - m_boneBodies[bone.name]->setDamping(btScalar(0.05), btScalar(0.85)); - m_boneBodies[bone.name]->setDeactivationTime(btScalar(0.8)); - m_boneBodies[bone.name]->setSleepingThresholds(btScalar(1.6), btScalar(2.5)); - } - - for (const auto &it: m_chains) { - for (size_t i = 1; i < it.second.size(); ++i) { - const auto &parent = (*rigBones)[m_boneNameToIndexMap[it.second[i - 1]]]; - const auto &child = (*rigBones)[m_boneNameToIndexMap[it.second[i]]]; - if (constraintPairs.find(std::make_pair(parent.name, child.name)) == constraintPairs.end()) { - constraintPairs.insert(std::make_pair(parent.name, child.name)); - if (parent.name.startsWith("Spine")) { - addFixedConstraint(parent, child); - } else { - addFreeConstraint(parent, child); - } - } - } - } - - for (const auto &parent: m_bones) { - for (const auto &childIndex: parent.children) { - const auto &child = m_bones[childIndex]; - if (parent.children.size() <= 1 && !child.name.startsWith("Virtual")) + if (0 == bone.index || -1 == bone.parent) + continue; + if (0 == bone.parent) { + if ("Spine1" == bone.name) continue; - if (constraintPairs.find(std::make_pair(parent.name, child.name)) == constraintPairs.end()) { - constraintPairs.insert(std::make_pair(parent.name, child.name)); - addFixedConstraint(parent, child); - } - } - } - - for (const auto &parent: m_bones) { - for (const auto &childIndex: parent.children) { - const auto &child = m_bones[childIndex]; - if (constraintPairs.find(std::make_pair(parent.name, child.name)) == constraintPairs.end()) { - constraintPairs.insert(std::make_pair(parent.name, child.name)); - addFreeConstraint(parent, child); - } + auto findFirstSpine = m_boneNameToIndexMap.find("Spine1"); + if (findFirstSpine == m_boneNameToIndexMap.end()) + continue; + addConstraint(bone, m_bones[findFirstSpine->second], true); + continue; } + addConstraint(bone, m_bones[bone.parent]); } for (const auto &bone: m_bones) { @@ -171,7 +165,7 @@ RagDoll::RagDoll(const std::vector *rigBones, } } -void RagDoll::addFreeConstraint(const RiggerBone &parent, const RiggerBone &child) +void RagDoll::addConstraint(const RiggerBone &child, const RiggerBone &parent, bool isBorrowedParent) { btRigidBody *parentBoneBody = m_boneBodies[parent.name]; btRigidBody *childBoneBody = m_boneBodies[child.name]; @@ -179,43 +173,53 @@ void RagDoll::addFreeConstraint(const RiggerBone &parent, const RiggerBone &chil if (nullptr == parentBoneBody || nullptr == childBoneBody) return; - float parentLength = m_boneLengthMap[parent.name]; - float childLength = m_boneLengthMap[child.name]; - const btVector3 btPivotA(0, parentLength * 0.5, 0.0f); - const btVector3 btPivotB(0, -childLength * 0.5, 0.0f); + bool reversed = isBorrowedParent; - btPoint2PointConstraint *constraint = new btPoint2PointConstraint(*parentBoneBody, *childBoneBody, - btPivotA, btPivotB); - m_world->addConstraint(constraint, true); - m_boneConstraints.push_back(constraint); -} - -void RagDoll::addFixedConstraint(const RiggerBone &parent, const RiggerBone &child) -{ - btRigidBody *parentBoneBody = m_boneBodies[parent.name]; - btRigidBody *childBoneBody = m_boneBodies[child.name]; - - if (nullptr == parentBoneBody || nullptr == childBoneBody) - return; + std::cout << "addConstraint parent:" << parent.name.toUtf8().constData() << " child:" << child.name.toUtf8().constData() << " reversed:" << reversed << std::endl; float parentLength = m_boneLengthMap[parent.name]; float childLength = m_boneLengthMap[child.name]; - const btVector3 btPivotA(0, parentLength * 0.5, 0.0f); + const btVector3 btPivotA(0, (reversed ? -1 : 1) * parentLength * 0.5, 0.0f); const btVector3 btPivotB(0, -childLength * 0.5, 0.0f); btTransform localA; btTransform localB; - btFixedConstraint *constraint = nullptr; - localA.setIdentity(); localB.setIdentity(); localA.setOrigin(btPivotA); localB.setOrigin(btPivotB); - constraint = new btFixedConstraint(*parentBoneBody, *childBoneBody, localA, localB); - m_world->addConstraint(constraint, true); - m_boneConstraints.push_back(constraint); + if (child.name.startsWith("Spine") || child.name.startsWith("Virtual")) { + btFixedConstraint *fixedConstraint = new btFixedConstraint(*parentBoneBody, *childBoneBody, + localA, localB); + m_world->addConstraint(fixedConstraint, true); + m_boneConstraints.push_back(fixedConstraint); + return; + } + + btGeneric6DofConstraint *g6dConstraint = nullptr; + bool useLinearReferenceFrameA = true; + g6dConstraint = new btGeneric6DofConstraint(*parentBoneBody, *childBoneBody, localA, localB, useLinearReferenceFrameA); + if ("LeftLimb1_Joint1" == parent.name || "LeftLimb2_Joint1" == parent.name) { + g6dConstraint->setAngularLowerLimit(btVector3(SIMD_EPSILON, -SIMD_EPSILON, -SIMD_EPSILON)); + g6dConstraint->setAngularUpperLimit(btVector3(-SIMD_PI * 0.7f, SIMD_EPSILON, SIMD_EPSILON)); + } else if ("RightLimb1_Joint1" == parent.name || "RightLimb2_Joint1" == parent.name) { + g6dConstraint->setAngularLowerLimit(btVector3(SIMD_EPSILON, -SIMD_EPSILON, -SIMD_EPSILON)); + g6dConstraint->setAngularUpperLimit(btVector3(SIMD_PI * 0.7f, SIMD_EPSILON, SIMD_EPSILON)); + } else if ("LeftLimb1_Joint1" == child.name || "LeftLimb2_Joint1" == child.name) { + g6dConstraint->setAngularLowerLimit(btVector3(-SIMD_HALF_PI * 0.5, -SIMD_EPSILON, -SIMD_EPSILON)); + g6dConstraint->setAngularUpperLimit(btVector3(SIMD_HALF_PI * 0.8, SIMD_EPSILON, SIMD_HALF_PI * 0.6f)); + } else if ("RightLimb1_Joint1" == child.name || "RightLimb2_Joint1" == child.name) { + g6dConstraint->setAngularLowerLimit(btVector3(-SIMD_HALF_PI * 0.5, -SIMD_EPSILON, -SIMD_HALF_PI * 0.6f)); + g6dConstraint->setAngularUpperLimit(btVector3(SIMD_HALF_PI * 0.8, SIMD_EPSILON, SIMD_EPSILON)); + } else { + g6dConstraint->setAngularLowerLimit(btVector3(-SIMD_EPSILON, -SIMD_EPSILON, -SIMD_EPSILON)); + g6dConstraint->setAngularUpperLimit(btVector3(SIMD_EPSILON, SIMD_EPSILON, SIMD_EPSILON)); + } + + m_world->addConstraint(g6dConstraint, true); + m_boneConstraints.push_back(g6dConstraint); } RagDoll::~RagDoll() @@ -319,8 +323,10 @@ bool RagDoll::stepSimulation(float amount) std::vector directions(m_stepBonePositions.size()); for (size_t index = 0; index < m_stepBonePositions.size(); ++index) { - const auto &bone = m_bones[index]; - directions[index] = bone.tailPosition - bone.headPosition; + if (index >= m_bones.size()) + continue; + const auto &boneNode = m_bones[index]; + directions[index] = boneNode.tailPosition - boneNode.headPosition; } std::function rotateChildren; rotateChildren = [&](size_t index, const QQuaternion &rotation) { @@ -331,8 +337,7 @@ bool RagDoll::stepSimulation(float amount) } }; for (size_t index = 1; index < m_stepBonePositions.size(); ++index) { - if (m_bones[index].name.startsWith("Virtual") || - m_bones[index].name.startsWith("Spine01")) + if (m_bones[index].name.startsWith("Virtual")) continue; QQuaternion rotation; const auto &oldDirection = directions[index]; @@ -351,7 +356,7 @@ const JointNodeTree &RagDoll::getStepJointNodeTree() return m_stepJointNodeTree; } -const std::vector> &RagDoll::getStepBonePositions() +const std::vector> &RagDoll::getStepBonePositions() { return m_stepBonePositions; } diff --git a/src/ragdoll.h b/src/ragdoll.h index 9547fba1..9f7d5a16 100644 --- a/src/ragdoll.h +++ b/src/ragdoll.h @@ -16,6 +16,7 @@ #include #include #include +#include #include "rigger.h" #include "jointnodetree.h" @@ -28,7 +29,7 @@ public: ~RagDoll(); bool stepSimulation(float amount); const JointNodeTree &getStepJointNodeTree(); - const std::vector> &getStepBonePositions(); + const std::vector> &getStepBonePositions(); private: btDefaultCollisionConfiguration *m_collisionConfiguration = nullptr; @@ -39,6 +40,7 @@ private: btCollisionShape *m_groundShape = nullptr; btRigidBody *m_groundBody = nullptr; float m_groundY = 0; + std::vector> m_boneInitialPositions; std::map m_boneShapes; std::map m_boneBodies; @@ -51,15 +53,14 @@ private: JointNodeTree m_jointNodeTree; JointNodeTree m_stepJointNodeTree; std::vector m_bones; - std::vector> m_stepBonePositions; + std::vector> m_stepBonePositions; std::map m_boneNameToIndexMap; std::map> m_chains; btRigidBody *createRigidBody(btScalar mass, const btTransform &startTransform, btCollisionShape *shape); void createDynamicsWorld(); - void addFixedConstraint(const RiggerBone &parent, const RiggerBone &child); - void addFreeConstraint(const RiggerBone &parent, const RiggerBone &child); + void addConstraint(const RiggerBone &child, const RiggerBone &parent, bool isBorrowedParent=false); }; #endif diff --git a/src/riggenerator.cpp b/src/riggenerator.cpp index 89e644fe..73c40466 100644 --- a/src/riggenerator.cpp +++ b/src/riggenerator.cpp @@ -299,9 +299,9 @@ void RigGenerator::buildBoneNodeChain() } else if (BoneMark::Tail == node.boneMark) { m_tailChains.push_back(i); } else if (BoneMark::Limb == node.boneMark) { - if (node.origin.x() < 0) { + if (node.origin.x() > 0) { m_leftLimbChains.push_back(i); - } else if (node.origin.x() > 0) { + } else if (node.origin.x() < 0) { m_rightLimbChains.push_back(i); } } @@ -668,6 +668,20 @@ void RigGenerator::computeSkinWeights() const auto &node = m_outcome->bodyNodes[nodeIndex]; nodeIdToIndexMap[{node.partId, node.nodeId}] = nodeIndex; } + if (!m_outcome->bodyNodes.empty()) { + for (size_t clothNodeIndex = 0; clothNodeIndex < m_outcome->clothNodes.size(); ++clothNodeIndex) { + const auto &clothNode = m_outcome->clothNodes[clothNodeIndex]; + std::vector> distance2s(m_outcome->bodyNodes.size()); + for (size_t nodeIndex = 0; nodeIndex < m_outcome->bodyNodes.size(); ++nodeIndex) { + distance2s[nodeIndex] = std::make_pair(nodeIndex, + (clothNode.origin - m_outcome->bodyNodes[nodeIndex].origin).lengthSquared()); + } + nodeIdToIndexMap[{clothNode.partId, clothNode.nodeId}] = std::min_element(distance2s.begin(), distance2s.end(), [](const std::pair &first, + const std::pair &second) { + return first.second < second.second; + })->first; + } + } for (size_t vertexIndex = 0; vertexIndex < m_outcome->vertices.size(); ++vertexIndex) { const auto &vertexSourceId = m_outcome->vertexSourceNodes[vertexIndex]; auto findNodeIndex = nodeIdToIndexMap.find(vertexSourceId); @@ -868,23 +882,8 @@ void RigGenerator::extractJoints(const size_t &fromNodeIndex, if (checkLastNoneMarkedNode && !jointIndices.empty() && jointIndices[jointIndices.size() - 1] + 1 != nodeIndicesAndDistance2Array.size()) { - size_t lastIndex = fromNodeIndex; - float sumOfDistances = 0.0f; - for (const auto &itemIndex: jointIndices) { - const auto &item = nodeIndicesAndDistance2Array[itemIndex]; - const auto ¤tNode = m_outcome->bodyNodes[item.first]; - const auto &lastNode = m_outcome->bodyNodes[lastIndex]; - lastIndex = item.first; - sumOfDistances += (currentNode.origin - lastNode.origin).length(); - } - float averageDistance = sumOfDistances / jointIndices.size(); - const auto &lastItem = nodeIndicesAndDistance2Array[nodeIndicesAndDistance2Array.size() - 1]; - float distance = (m_outcome->bodyNodes[lastItem.first].origin - - m_outcome->bodyNodes[lastIndex].origin).length(); - // FIXME: replace the hardcoded value - if (distance >= averageDistance * 0.5) { + if (jointIndices.empty()) appendLastJoint = true; - } } if (jointIndices.empty() || appendLastJoint) { jointIndices.push_back(nodeIndicesAndDistance2Array.size() - 1); @@ -948,42 +947,6 @@ void RigGenerator::extractSpineJoints() } } -/* -void RigGenerator::extractSpineJoints() -{ - auto &spine = m_boneNodeChain[m_spineChains[0]]; - auto findTail = m_branchNodesMapByMark.find((int)BoneMark::Tail); - if (findTail != m_branchNodesMapByMark.end()) { - m_spineJoints.push_back(findTail->second[0]); - } else { - std::reverse(spine.nodeChain.begin(), spine.nodeChain.end()); - std::reverse(spine.nodeIsJointFlags.begin(), spine.nodeIsJointFlags.end()); - std::reverse(m_attachLimbsToSpineChainPositions.begin(), m_attachLimbsToSpineChainPositions.end()); - for (auto &it: m_attachLimbsToSpineChainPositions) { - it = spine.nodeChain.size() - 1 - it; - } - } - m_attachLimbsToSpineJointIndices.resize(m_attachLimbsToSpineChainPositions.size()); - for (size_t i = 0; i < spine.nodeChain.size(); ++i) { - bool limbsAttached = false; - for (size_t j = 0; j < m_attachLimbsToSpineChainPositions.size(); ++j) { - if (i == m_attachLimbsToSpineChainPositions[j]) { - m_attachLimbsToSpineJointIndices[j] = m_spineJoints.size(); - limbsAttached = true; - } - } - if (limbsAttached || spine.nodeIsJointFlags[i]) { - m_spineJoints.push_back(spine.nodeChain[i]); - continue; - } - } - auto findNeck = m_branchNodesMapByMark.find((int)BoneMark::Neck); - if (findNeck != m_branchNodesMapByMark.end()) { - m_spineJoints.push_back(findNeck->second[0]); - } -} -*/ - void RigGenerator::splitByNodeIndex(size_t nodeIndex, std::unordered_set *left, std::unordered_set *right) diff --git a/src/trianglesourcenoderesolve.cpp b/src/trianglesourcenoderesolve.cpp index 684a4bc0..048ec423 100644 --- a/src/trianglesourcenoderesolve.cpp +++ b/src/trianglesourcenoderesolve.cpp @@ -17,6 +17,28 @@ struct CandidateEdge float length; }; +static void fixRemainVertexSourceNodes(const Outcome &outcome, std::vector> &triangleSourceNodes, + std::vector> *vertexSourceNodes) +{ + if (nullptr != vertexSourceNodes) { + std::map, size_t>> remainVertexSourcesMap; + for (size_t faceIndex = 0; faceIndex < outcome.triangles.size(); ++faceIndex) { + for (const auto &vertexIndex: outcome.triangles[faceIndex]) { + if (!(*vertexSourceNodes)[vertexIndex].second.isNull()) + continue; + remainVertexSourcesMap[vertexIndex][triangleSourceNodes[faceIndex]]++; + } + } + for (const auto &it: remainVertexSourcesMap) { + (*vertexSourceNodes)[it.first] = std::max_element(it.second.begin(), it.second.end(), []( + const std::map, size_t>::value_type &first, + const std::map, size_t>::value_type &second) { + return first.second < second.second; + })->first; + } + } +} + void triangleSourceNodeResolve(const Outcome &outcome, std::vector> &triangleSourceNodes, std::vector> *vertexSourceNodes) { @@ -128,8 +150,10 @@ void triangleSourceNodeResolve(const Outcome &outcome, std::vector bool { if (a.dot > b.dot) return true; @@ -163,21 +187,5 @@ void triangleSourceNodeResolve(const Outcome &outcome, std::vector, size_t>> remainVertexSourcesMap; - for (size_t faceIndex = 0; faceIndex < outcome.triangles.size(); ++faceIndex) { - for (const auto &vertexIndex: outcome.triangles[faceIndex]) { - if (!(*vertexSourceNodes)[vertexIndex].second.isNull()) - continue; - remainVertexSourcesMap[vertexIndex][triangleSourceNodes[faceIndex]]++; - } - } - for (const auto &it: remainVertexSourcesMap) { - (*vertexSourceNodes)[it.first] = std::max_element(it.second.begin(), it.second.end(), []( - const std::map, size_t>::value_type &first, - const std::map, size_t>::value_type &second) { - return first.second < second.second; - })->first; - } - } + fixRemainVertexSourceNodes(outcome, triangleSourceNodes, vertexSourceNodes); }