Fix pose editor

master
Jeremy Hu 2019-11-09 17:45:49 +09:30
parent 9f12f03d58
commit 839e081d10
7 changed files with 109 additions and 36 deletions

View File

@ -29,6 +29,23 @@ void JointNodeTree::reset()
} }
} }
void JointNodeTree::calculateBonePositions(std::vector<std::pair<QVector3D, QVector3D>> *bonePositions,
const std::vector<RiggerBone> *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() void JointNodeTree::recalculateTransformMatrices()
{ {
for (decltype(m_boneNodes.size()) i = 0; i < m_boneNodes.size(); i++) { for (decltype(m_boneNodes.size()) i = 0; i < m_boneNodes.size(); i++) {

View File

@ -28,6 +28,8 @@ public:
void addTranslation(int index, QVector3D translation); void addTranslation(int index, QVector3D translation);
void reset(); void reset();
void recalculateTransformMatrices(); void recalculateTransformMatrices();
void calculateBonePositions(std::vector<std::pair<QVector3D, QVector3D>> *bonePositions,
const std::vector<RiggerBone> *rigBones) const;
static JointNodeTree slerp(const JointNodeTree &first, const JointNodeTree &second, float t); static JointNodeTree slerp(const JointNodeTree &first, const JointNodeTree &second, float t);
private: private:
std::vector<JointNode> m_boneNodes; std::vector<JointNode> m_boneNodes;

View File

@ -103,14 +103,16 @@ float MotionsGenerator::calculatePoseDuration(const QUuid &poseId)
return totalDuration; return totalDuration;
} }
const std::vector<std::pair<float, JointNodeTree>> &MotionsGenerator::getProceduralAnimation(ProceduralAnimation proceduralAnimation) const std::vector<std::pair<float, JointNodeTree>> &MotionsGenerator::getProceduralAnimation(ProceduralAnimation proceduralAnimation,
const JointNodeTree *initialJointNodeTree)
{ {
auto findResult = m_proceduralAnimations.find((int)proceduralAnimation); auto findResult = m_proceduralAnimations.find((int)proceduralAnimation);
if (findResult != m_proceduralAnimations.end()) if (findResult != m_proceduralAnimations.end())
return findResult->second; return findResult->second;
std::vector<std::pair<float, JointNodeTree>> &resultFrames = m_proceduralAnimations[(int)proceduralAnimation]; std::vector<std::pair<float, JointNodeTree>> &resultFrames = m_proceduralAnimations[(int)proceduralAnimation];
if (ProceduralAnimation::FallToDeath == proceduralAnimation) {
//std::vector<MeshLoader *> &resultPreviews = m_proceduralPreviews[(int)proceduralAnimation]; //std::vector<MeshLoader *> &resultPreviews = m_proceduralPreviews[(int)proceduralAnimation];
RagDoll ragdoll(&m_rigBones); RagDoll ragdoll(&m_rigBones, initialJointNodeTree);
float stepSeconds = 1.0 / 60; float stepSeconds = 1.0 / 60;
float maxSeconds = 1.5; float maxSeconds = 1.5;
int maxSteps = maxSeconds / stepSeconds; int maxSteps = maxSeconds / stepSeconds;
@ -121,12 +123,18 @@ const std::vector<std::pair<float, JointNodeTree>> &MotionsGenerator::getProcedu
//resultPreviews.push_back(preview); //resultPreviews.push_back(preview);
++steps; ++steps;
} }
}
if (resultFrames.empty()) {
resultFrames.push_back(std::make_pair(0, JointNodeTree(&m_rigBones)));
}
return resultFrames; 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; float totalDuration = 0;
for (const auto &it: result) { for (const auto &it: result) {
totalDuration += it.first; totalDuration += it.first;
@ -145,14 +153,20 @@ float MotionsGenerator::calculateMotionDuration(const QUuid &motionId, std::set<
} }
float totalDuration = 0; float totalDuration = 0;
visited.insert(motionId); 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) if (clip.clipType == MotionClipType::Interpolation)
totalDuration += clip.duration; totalDuration += clip.duration;
else if (clip.clipType == MotionClipType::Pose) else if (clip.clipType == MotionClipType::Pose)
totalDuration += calculatePoseDuration(clip.linkToId); totalDuration += calculatePoseDuration(clip.linkToId);
else if (clip.clipType == MotionClipType::ProceduralAnimation) else if (clip.clipType == MotionClipType::ProceduralAnimation) {
totalDuration += calculateProceduralAnimationDuration(clip.proceduralAnimation); const JointNodeTree *previousJointNodeTree = nullptr;
else if (clip.clipType == MotionClipType::Motion) if (clipIndex > 1) {
previousJointNodeTree = findClipEndJointNodeTree((*motionClips)[clipIndex - 2]);
}
totalDuration += calculateProceduralAnimationDuration(clip.proceduralAnimation,
previousJointNodeTree);
} else if (clip.clipType == MotionClipType::Motion)
totalDuration += calculateMotionDuration(clip.linkToId, visited); totalDuration += calculateMotionDuration(clip.linkToId, visited);
} }
return totalDuration; return totalDuration;
@ -173,14 +187,20 @@ void MotionsGenerator::generateMotion(const QUuid &motionId, std::set<QUuid> &vi
std::vector<float> timePoints; std::vector<float> timePoints;
float totalDuration = 0; 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) { if (clip.clipType == MotionClipType::Motion) {
std::set<QUuid> subVisited; std::set<QUuid> subVisited;
clip.duration = calculateMotionDuration(clip.linkToId, subVisited); clip.duration = calculateMotionDuration(clip.linkToId, subVisited);
} else if (clip.clipType == MotionClipType::Pose) { } else if (clip.clipType == MotionClipType::Pose) {
clip.duration = calculatePoseDuration(clip.linkToId); clip.duration = calculatePoseDuration(clip.linkToId);
} else if (clip.clipType == MotionClipType::ProceduralAnimation) { } 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); timePoints.push_back(totalDuration);
totalDuration += clip.duration; totalDuration += clip.duration;
@ -220,11 +240,16 @@ void MotionsGenerator::generateMotion(const QUuid &motionId, std::set<QUuid> &vi
qDebug() << "findClipEndJointNodeTree failed"; qDebug() << "findClipEndJointNodeTree failed";
break; break;
} }
const JointNodeTree *endJointNodeTree = findClipBeginJointNodeTree((*motionClips)[clipIndex + 1]); const JointNodeTree *endJointNodeTree = nullptr;
if (MotionClipType::ProceduralAnimation == (*motionClips)[clipIndex + 1].clipType) {
endJointNodeTree = beginJointNodeTree;
} else {
endJointNodeTree = findClipBeginJointNodeTree((*motionClips)[clipIndex + 1]);
if (nullptr == endJointNodeTree) { if (nullptr == endJointNodeTree) {
qDebug() << "findClipBeginJointNodeTree failed"; qDebug() << "findClipBeginJointNodeTree failed";
break; break;
} }
}
outcomes.push_back({progress - lastProgress, outcomes.push_back({progress - lastProgress,
generateInterpolation(progressClip.interpolationType, *beginJointNodeTree, *endJointNodeTree, clipLocalProgress / std::max((float)0.0001, progressClip.duration))}); generateInterpolation(progressClip.interpolationType, *beginJointNodeTree, *endJointNodeTree, clipLocalProgress / std::max((float)0.0001, progressClip.duration))});
lastProgress = progress; lastProgress = progress;
@ -258,7 +283,12 @@ void MotionsGenerator::generateMotion(const QUuid &motionId, std::set<QUuid> &vi
progress += progressClip.duration; progress += progressClip.duration;
continue; continue;
} else if (MotionClipType::ProceduralAnimation == progressClip.clipType) { } 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); float clipDuration = std::max((float)0.0001, progressClip.duration);
int frame = clipLocalProgress * frames.size() / clipDuration; int frame = clipLocalProgress * frames.size() / clipDuration;
if (frame >= (int)frames.size()) if (frame >= (int)frames.size())

View File

@ -45,8 +45,10 @@ private:
void generatePreviewsForOutcomes(const std::vector<std::pair<float, JointNodeTree>> &outcomes, std::vector<std::pair<float, MeshLoader *>> &previews); void generatePreviewsForOutcomes(const std::vector<std::pair<float, JointNodeTree>> &outcomes, std::vector<std::pair<float, MeshLoader *>> &previews);
float calculateMotionDuration(const QUuid &motionId, std::set<QUuid> &visited); float calculateMotionDuration(const QUuid &motionId, std::set<QUuid> &visited);
float calculatePoseDuration(const QUuid &poseId); float calculatePoseDuration(const QUuid &poseId);
float calculateProceduralAnimationDuration(ProceduralAnimation proceduralAnimation); float calculateProceduralAnimationDuration(ProceduralAnimation proceduralAnimation,
const std::vector<std::pair<float, JointNodeTree>> &getProceduralAnimation(ProceduralAnimation proceduralAnimation); const JointNodeTree *initialJointNodeTree=nullptr);
const std::vector<std::pair<float, JointNodeTree>> &getProceduralAnimation(ProceduralAnimation proceduralAnimation,
const JointNodeTree *initialJointNodeTree=nullptr);
RigType m_rigType = RigType::None; RigType m_rigType = RigType::None;
std::vector<RiggerBone> m_rigBones; std::vector<RiggerBone> m_rigBones;

View File

@ -367,6 +367,7 @@ void PoseDocument::parametersToNodes(const std::vector<RiggerBone> *rigBones,
node.setY(fromOutcomeY(bone.headPosition.y())); node.setY(fromOutcomeY(bone.headPosition.y()));
node.setZ(fromOutcomeZ(bone.headPosition.z())); node.setZ(fromOutcomeZ(bone.headPosition.z()));
nodeMap[node.id] = node; nodeMap[node.id] = node;
qDebug() << "Add first node:" << (*rigBones)[edgePair.first].name;
newAddedNodeIds.insert(node.id); newAddedNodeIds.insert(node.id);
boneIndexToHeadNodeIdMap[edgePair.first] = node.id; boneIndexToHeadNodeIdMap[edgePair.first] = node.id;
firstNodeId = node.id; firstNodeId = node.id;
@ -376,6 +377,7 @@ void PoseDocument::parametersToNodes(const std::vector<RiggerBone> *rigBones,
} }
auto findSecond = boneIndexToHeadNodeIdMap.find(edgePair.second); auto findSecond = boneIndexToHeadNodeIdMap.find(edgePair.second);
if (findSecond == boneIndexToHeadNodeIdMap.end()) { if (findSecond == boneIndexToHeadNodeIdMap.end()) {
const auto &firstBone = (*rigBones)[edgePair.first];
const auto &bone = (*rigBones)[edgePair.second]; const auto &bone = (*rigBones)[edgePair.second];
if (!bone.name.startsWith("Virtual_") || !m_hideRootAndVirtual) { if (!bone.name.startsWith("Virtual_") || !m_hideRootAndVirtual) {
SkeletonNode node; SkeletonNode node;
@ -383,10 +385,11 @@ void PoseDocument::parametersToNodes(const std::vector<RiggerBone> *rigBones,
node.id = QUuid::createUuid(); node.id = QUuid::createUuid();
partMap[node.partId].nodeIds.push_back(node.id); partMap[node.partId].nodeIds.push_back(node.id);
node.setRadius(m_nodeRadius); node.setRadius(m_nodeRadius);
node.setX(fromOutcomeX(bone.headPosition.x())); node.setX(fromOutcomeX(firstBone.tailPosition.x()));
node.setY(fromOutcomeY(bone.headPosition.y())); node.setY(fromOutcomeY(firstBone.tailPosition.y()));
node.setZ(fromOutcomeZ(bone.headPosition.z())); node.setZ(fromOutcomeZ(firstBone.tailPosition.z()));
nodeMap[node.id] = node; nodeMap[node.id] = node;
qDebug() << "Add second node:" << (*rigBones)[edgePair.second].name;
newAddedNodeIds.insert(node.id); newAddedNodeIds.insert(node.id);
boneIndexToHeadNodeIdMap[edgePair.second] = node.id; boneIndexToHeadNodeIdMap[edgePair.second] = node.id;
secondNodeId = node.id; secondNodeId = node.id;
@ -395,8 +398,9 @@ void PoseDocument::parametersToNodes(const std::vector<RiggerBone> *rigBones,
secondNodeId = findSecond->second; secondNodeId = findSecond->second;
} }
if (firstNodeId.isNull() || secondNodeId.isNull()) if (firstNodeId.isNull() || secondNodeId.isNull()) {
continue; continue;
}
if (firstNodeSide != secondNodeSide) { if (firstNodeSide != secondNodeSide) {
qDebug() << "First node side:" << SkeletonSideToDispName(firstNodeSide) << "is different with second node side:" << SkeletonSideToDispName(secondNodeSide); qDebug() << "First node side:" << SkeletonSideToDispName(firstNodeSide) << "is different with second node side:" << SkeletonSideToDispName(secondNodeSide);

View File

@ -14,7 +14,8 @@
#include "ragdoll.h" #include "ragdoll.h"
#include "poser.h" #include "poser.h"
RagDoll::RagDoll(const std::vector<RiggerBone> *rigBones) : RagDoll::RagDoll(const std::vector<RiggerBone> *rigBones,
const JointNodeTree *initialJointNodeTree) :
m_jointNodeTree(rigBones), m_jointNodeTree(rigBones),
m_stepJointNodeTree(rigBones) m_stepJointNodeTree(rigBones)
{ {
@ -23,6 +24,18 @@ RagDoll::RagDoll(const std::vector<RiggerBone> *rigBones) :
m_bones = *rigBones; m_bones = *rigBones;
std::vector<std::pair<QVector3D, QVector3D>> 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) { for (const auto &bone: m_bones) {
auto radius = qMax(bone.headRadius, bone.tailRadius); auto radius = qMax(bone.headRadius, bone.tailRadius);
m_stepBonePositions.push_back(std::make_tuple(bone.headPosition, bone.tailPosition, radius)); m_stepBonePositions.push_back(std::make_tuple(bone.headPosition, bone.tailPosition, radius));
@ -44,9 +57,11 @@ RagDoll::RagDoll(const std::vector<RiggerBone> *rigBones) :
Poser::fetchChains(boneNames, m_chains); Poser::fetchChains(boneNames, m_chains);
for (const auto &bone: *rigBones) { 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 radius = (bone.headRadius + bone.tailRadius) * 0.5;
float height = bone.headPosition.distanceToPoint(bone.tailPosition); float height = headPosition.distanceToPoint(tailPosition);
QVector3D middlePosition = (bone.headPosition + bone.tailPosition) * 0.5; QVector3D middlePosition = (headPosition + tailPosition) * 0.5;
m_boneLengthMap[bone.name] = height; m_boneLengthMap[bone.name] = height;
m_boneRadiusMap[bone.name] = radius; m_boneRadiusMap[bone.name] = radius;
m_boneMiddleMap[bone.name] = middlePosition; m_boneMiddleMap[bone.name] = middlePosition;
@ -55,6 +70,8 @@ RagDoll::RagDoll(const std::vector<RiggerBone> *rigBones) :
std::set<std::pair<QString, QString>> constraintPairs; std::set<std::pair<QString, QString>> constraintPairs;
for (const auto &bone: m_bones) { 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 height = m_boneLengthMap[bone.name];
float radius = m_boneRadiusMap[bone.name]; float radius = m_boneRadiusMap[bone.name];
float mass = 1.0; float mass = 1.0;
@ -72,7 +89,7 @@ RagDoll::RagDoll(const std::vector<RiggerBone> *rigBones) :
btScalar(middlePosition.y()), btScalar(middlePosition.y()),
btScalar(middlePosition.z()) btScalar(middlePosition.z())
)); ));
QVector3D to = (bone.tailPosition - bone.headPosition).normalized(); QVector3D to = (tailPosition - headPosition).normalized();
QVector3D from = QVector3D(0, 1, 0); QVector3D from = QVector3D(0, 1, 0);
QQuaternion rotation = QQuaternion::rotationTo(from, to); QQuaternion rotation = QQuaternion::rotationTo(from, to);
btQuaternion btRotation(btScalar(rotation.x()), btScalar(rotation.y()), btScalar(rotation.z()), btQuaternion btRotation(btScalar(rotation.x()), btScalar(rotation.y()), btScalar(rotation.z()),

View File

@ -23,7 +23,8 @@ class RagDoll : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
RagDoll(const std::vector<RiggerBone> *rigBones); RagDoll(const std::vector<RiggerBone> *rigBones,
const JointNodeTree *initialJointNodeTree=nullptr);
~RagDoll(); ~RagDoll();
bool stepSimulation(float amount); bool stepSimulation(float amount);
const JointNodeTree &getStepJointNodeTree(); const JointNodeTree &getStepJointNodeTree();