From 839e081d102eabd3fbaed23247c5027154da58de Mon Sep 17 00:00:00 2001 From: Jeremy Hu Date: Sat, 9 Nov 2019 17:45:49 +0930 Subject: [PATCH] Fix pose editor --- src/jointnodetree.cpp | 17 +++++++++ src/jointnodetree.h | 2 + src/motionsgenerator.cpp | 80 +++++++++++++++++++++++++++------------- src/motionsgenerator.h | 6 ++- src/posedocument.cpp | 12 ++++-- src/ragdoll.cpp | 25 +++++++++++-- src/ragdoll.h | 3 +- 7 files changed, 109 insertions(+), 36 deletions(-) diff --git a/src/jointnodetree.cpp b/src/jointnodetree.cpp index e6cb031d..42d1439d 100644 --- a/src/jointnodetree.cpp +++ b/src/jointnodetree.cpp @@ -29,6 +29,23 @@ void JointNodeTree::reset() } } +void JointNodeTree::calculateBonePositions(std::vector> *bonePositions, + const std::vector *rigBones) const +{ + if (nullptr == bonePositions) + 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); + } +} + void JointNodeTree::recalculateTransformMatrices() { for (decltype(m_boneNodes.size()) i = 0; i < m_boneNodes.size(); i++) { diff --git a/src/jointnodetree.h b/src/jointnodetree.h index d9728270..94a2cb5d 100644 --- a/src/jointnodetree.h +++ b/src/jointnodetree.h @@ -28,6 +28,8 @@ public: void addTranslation(int index, QVector3D translation); void reset(); void recalculateTransformMatrices(); + void calculateBonePositions(std::vector> *bonePositions, + const std::vector *rigBones) const; static JointNodeTree slerp(const JointNodeTree &first, const JointNodeTree &second, float t); private: std::vector m_boneNodes; diff --git a/src/motionsgenerator.cpp b/src/motionsgenerator.cpp index 3b7eed0b..8aa2aea0 100644 --- a/src/motionsgenerator.cpp +++ b/src/motionsgenerator.cpp @@ -103,30 +103,38 @@ float MotionsGenerator::calculatePoseDuration(const QUuid &poseId) return totalDuration; } -const std::vector> &MotionsGenerator::getProceduralAnimation(ProceduralAnimation proceduralAnimation) +const std::vector> &MotionsGenerator::getProceduralAnimation(ProceduralAnimation proceduralAnimation, + const JointNodeTree *initialJointNodeTree) { auto findResult = m_proceduralAnimations.find((int)proceduralAnimation); if (findResult != m_proceduralAnimations.end()) return findResult->second; std::vector> &resultFrames = m_proceduralAnimations[(int)proceduralAnimation]; - //std::vector &resultPreviews = m_proceduralPreviews[(int)proceduralAnimation]; - RagDoll ragdoll(&m_rigBones); - float stepSeconds = 1.0 / 60; - float maxSeconds = 1.5; - int maxSteps = maxSeconds / stepSeconds; - 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); - ++steps; + if (ProceduralAnimation::FallToDeath == proceduralAnimation) { + //std::vector &resultPreviews = m_proceduralPreviews[(int)proceduralAnimation]; + RagDoll ragdoll(&m_rigBones, initialJointNodeTree); + float stepSeconds = 1.0 / 60; + float maxSeconds = 1.5; + int maxSteps = maxSeconds / stepSeconds; + 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); + ++steps; + } + } + if (resultFrames.empty()) { + resultFrames.push_back(std::make_pair(0, JointNodeTree(&m_rigBones))); } return resultFrames; } -float MotionsGenerator::calculateProceduralAnimationDuration(ProceduralAnimation proceduralAnimation) +float MotionsGenerator::calculateProceduralAnimationDuration(ProceduralAnimation proceduralAnimation, + const JointNodeTree *initialJointNodeTree) { - const auto &result = getProceduralAnimation(proceduralAnimation); + const auto &result = getProceduralAnimation(proceduralAnimation, + initialJointNodeTree); float totalDuration = 0; for (const auto &it: result) { totalDuration += it.first; @@ -145,14 +153,20 @@ float MotionsGenerator::calculateMotionDuration(const QUuid &motionId, std::set< } float totalDuration = 0; visited.insert(motionId); - for (const auto &clip: *motionClips) { + for (int clipIndex = 0; clipIndex < (int)(*motionClips).size(); ++clipIndex) { + const auto &clip = (*motionClips)[clipIndex]; if (clip.clipType == MotionClipType::Interpolation) totalDuration += clip.duration; else if (clip.clipType == MotionClipType::Pose) totalDuration += calculatePoseDuration(clip.linkToId); - else if (clip.clipType == MotionClipType::ProceduralAnimation) - totalDuration += calculateProceduralAnimationDuration(clip.proceduralAnimation); - else if (clip.clipType == MotionClipType::Motion) + else if (clip.clipType == MotionClipType::ProceduralAnimation) { + const JointNodeTree *previousJointNodeTree = nullptr; + if (clipIndex > 1) { + previousJointNodeTree = findClipEndJointNodeTree((*motionClips)[clipIndex - 2]); + } + totalDuration += calculateProceduralAnimationDuration(clip.proceduralAnimation, + previousJointNodeTree); + } else if (clip.clipType == MotionClipType::Motion) totalDuration += calculateMotionDuration(clip.linkToId, visited); } return totalDuration; @@ -173,14 +187,20 @@ void MotionsGenerator::generateMotion(const QUuid &motionId, std::set &vi std::vector timePoints; float totalDuration = 0; - for (auto &clip: *motionClips) { + for (int clipIndex = 0; clipIndex < (int)(*motionClips).size(); ++clipIndex) { + auto &clip = (*motionClips)[clipIndex]; if (clip.clipType == MotionClipType::Motion) { std::set subVisited; clip.duration = calculateMotionDuration(clip.linkToId, subVisited); } else if (clip.clipType == MotionClipType::Pose) { clip.duration = calculatePoseDuration(clip.linkToId); } else if (clip.clipType == MotionClipType::ProceduralAnimation) { - clip.duration = calculateProceduralAnimationDuration(clip.proceduralAnimation); + const JointNodeTree *previousJointNodeTree = nullptr; + if (clipIndex > 1) { + previousJointNodeTree = findClipEndJointNodeTree((*motionClips)[clipIndex - 2]); + } + clip.duration = calculateProceduralAnimationDuration(clip.proceduralAnimation, + previousJointNodeTree); } timePoints.push_back(totalDuration); totalDuration += clip.duration; @@ -220,10 +240,15 @@ void MotionsGenerator::generateMotion(const QUuid &motionId, std::set &vi qDebug() << "findClipEndJointNodeTree failed"; break; } - const JointNodeTree *endJointNodeTree = findClipBeginJointNodeTree((*motionClips)[clipIndex + 1]); - if (nullptr == endJointNodeTree) { - qDebug() << "findClipBeginJointNodeTree failed"; - break; + const JointNodeTree *endJointNodeTree = nullptr; + if (MotionClipType::ProceduralAnimation == (*motionClips)[clipIndex + 1].clipType) { + endJointNodeTree = beginJointNodeTree; + } else { + endJointNodeTree = findClipBeginJointNodeTree((*motionClips)[clipIndex + 1]); + if (nullptr == endJointNodeTree) { + qDebug() << "findClipBeginJointNodeTree failed"; + break; + } } outcomes.push_back({progress - lastProgress, generateInterpolation(progressClip.interpolationType, *beginJointNodeTree, *endJointNodeTree, clipLocalProgress / std::max((float)0.0001, progressClip.duration))}); @@ -258,7 +283,12 @@ void MotionsGenerator::generateMotion(const QUuid &motionId, std::set &vi progress += progressClip.duration; continue; } else if (MotionClipType::ProceduralAnimation == progressClip.clipType) { - const auto &frames = getProceduralAnimation(progressClip.proceduralAnimation); + const JointNodeTree *beginJointNodeTree = nullptr; + if (clipIndex > 0) { + beginJointNodeTree = findClipEndJointNodeTree((*motionClips)[clipIndex - 1]); + } + const auto &frames = getProceduralAnimation(progressClip.proceduralAnimation, + beginJointNodeTree); float clipDuration = std::max((float)0.0001, progressClip.duration); int frame = clipLocalProgress * frames.size() / clipDuration; if (frame >= (int)frames.size()) diff --git a/src/motionsgenerator.h b/src/motionsgenerator.h index ef384ffb..4b114730 100644 --- a/src/motionsgenerator.h +++ b/src/motionsgenerator.h @@ -45,8 +45,10 @@ private: void generatePreviewsForOutcomes(const std::vector> &outcomes, std::vector> &previews); float calculateMotionDuration(const QUuid &motionId, std::set &visited); float calculatePoseDuration(const QUuid &poseId); - float calculateProceduralAnimationDuration(ProceduralAnimation proceduralAnimation); - const std::vector> &getProceduralAnimation(ProceduralAnimation proceduralAnimation); + float calculateProceduralAnimationDuration(ProceduralAnimation proceduralAnimation, + const JointNodeTree *initialJointNodeTree=nullptr); + const std::vector> &getProceduralAnimation(ProceduralAnimation proceduralAnimation, + const JointNodeTree *initialJointNodeTree=nullptr); RigType m_rigType = RigType::None; std::vector m_rigBones; diff --git a/src/posedocument.cpp b/src/posedocument.cpp index 7c314883..43e1a8bb 100644 --- a/src/posedocument.cpp +++ b/src/posedocument.cpp @@ -367,6 +367,7 @@ void PoseDocument::parametersToNodes(const std::vector *rigBones, node.setY(fromOutcomeY(bone.headPosition.y())); node.setZ(fromOutcomeZ(bone.headPosition.z())); nodeMap[node.id] = node; + qDebug() << "Add first node:" << (*rigBones)[edgePair.first].name; newAddedNodeIds.insert(node.id); boneIndexToHeadNodeIdMap[edgePair.first] = node.id; firstNodeId = node.id; @@ -376,6 +377,7 @@ void PoseDocument::parametersToNodes(const std::vector *rigBones, } auto findSecond = boneIndexToHeadNodeIdMap.find(edgePair.second); if (findSecond == boneIndexToHeadNodeIdMap.end()) { + const auto &firstBone = (*rigBones)[edgePair.first]; const auto &bone = (*rigBones)[edgePair.second]; if (!bone.name.startsWith("Virtual_") || !m_hideRootAndVirtual) { SkeletonNode node; @@ -383,10 +385,11 @@ void PoseDocument::parametersToNodes(const std::vector *rigBones, node.id = QUuid::createUuid(); partMap[node.partId].nodeIds.push_back(node.id); node.setRadius(m_nodeRadius); - node.setX(fromOutcomeX(bone.headPosition.x())); - node.setY(fromOutcomeY(bone.headPosition.y())); - node.setZ(fromOutcomeZ(bone.headPosition.z())); + node.setX(fromOutcomeX(firstBone.tailPosition.x())); + node.setY(fromOutcomeY(firstBone.tailPosition.y())); + node.setZ(fromOutcomeZ(firstBone.tailPosition.z())); nodeMap[node.id] = node; + qDebug() << "Add second node:" << (*rigBones)[edgePair.second].name; newAddedNodeIds.insert(node.id); boneIndexToHeadNodeIdMap[edgePair.second] = node.id; secondNodeId = node.id; @@ -395,8 +398,9 @@ void PoseDocument::parametersToNodes(const std::vector *rigBones, secondNodeId = findSecond->second; } - if (firstNodeId.isNull() || secondNodeId.isNull()) + if (firstNodeId.isNull() || secondNodeId.isNull()) { continue; + } if (firstNodeSide != secondNodeSide) { qDebug() << "First node side:" << SkeletonSideToDispName(firstNodeSide) << "is different with second node side:" << SkeletonSideToDispName(secondNodeSide); diff --git a/src/ragdoll.cpp b/src/ragdoll.cpp index cc55b0fc..03e6b67c 100644 --- a/src/ragdoll.cpp +++ b/src/ragdoll.cpp @@ -14,7 +14,8 @@ #include "ragdoll.h" #include "poser.h" -RagDoll::RagDoll(const std::vector *rigBones) : +RagDoll::RagDoll(const std::vector *rigBones, + const JointNodeTree *initialJointNodeTree) : m_jointNodeTree(rigBones), m_stepJointNodeTree(rigBones) { @@ -23,6 +24,18 @@ RagDoll::RagDoll(const std::vector *rigBones) : m_bones = *rigBones; + std::vector> bonePositions; + if (nullptr != initialJointNodeTree) { + m_jointNodeTree.calculateBonePositions(&bonePositions, + rigBones); + } else { + bonePositions.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); + } + } + 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)); @@ -44,9 +57,11 @@ 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; - float height = bone.headPosition.distanceToPoint(bone.tailPosition); - QVector3D middlePosition = (bone.headPosition + bone.tailPosition) * 0.5; + float height = headPosition.distanceToPoint(tailPosition); + QVector3D middlePosition = (headPosition + tailPosition) * 0.5; m_boneLengthMap[bone.name] = height; m_boneRadiusMap[bone.name] = radius; m_boneMiddleMap[bone.name] = middlePosition; @@ -55,6 +70,8 @@ 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; float height = m_boneLengthMap[bone.name]; float radius = m_boneRadiusMap[bone.name]; float mass = 1.0; @@ -72,7 +89,7 @@ RagDoll::RagDoll(const std::vector *rigBones) : btScalar(middlePosition.y()), btScalar(middlePosition.z()) )); - QVector3D to = (bone.tailPosition - bone.headPosition).normalized(); + QVector3D to = (tailPosition - headPosition).normalized(); QVector3D from = QVector3D(0, 1, 0); QQuaternion rotation = QQuaternion::rotationTo(from, to); btQuaternion btRotation(btScalar(rotation.x()), btScalar(rotation.y()), btScalar(rotation.z()), diff --git a/src/ragdoll.h b/src/ragdoll.h index 59736a7a..9547fba1 100644 --- a/src/ragdoll.h +++ b/src/ragdoll.h @@ -23,7 +23,8 @@ class RagDoll : public QObject { Q_OBJECT public: - RagDoll(const std::vector *rigBones); + RagDoll(const std::vector *rigBones, + const JointNodeTree *initialJointNodeTree=nullptr); ~RagDoll(); bool stepSimulation(float amount); const JointNodeTree &getStepJointNodeTree();