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()
{
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 reset();
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);
private:
std::vector<JointNode> m_boneNodes;

View File

@ -103,30 +103,38 @@ float MotionsGenerator::calculatePoseDuration(const QUuid &poseId)
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);
if (findResult != m_proceduralAnimations.end())
return findResult->second;
std::vector<std::pair<float, JointNodeTree>> &resultFrames = m_proceduralAnimations[(int)proceduralAnimation];
//std::vector<MeshLoader *> &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<MeshLoader *> &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<QUuid> &vi
std::vector<float> 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<QUuid> 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<QUuid> &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<QUuid> &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())

View File

@ -45,8 +45,10 @@ private:
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 calculatePoseDuration(const QUuid &poseId);
float calculateProceduralAnimationDuration(ProceduralAnimation proceduralAnimation);
const std::vector<std::pair<float, JointNodeTree>> &getProceduralAnimation(ProceduralAnimation proceduralAnimation);
float calculateProceduralAnimationDuration(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;
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.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<RiggerBone> *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<RiggerBone> *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<RiggerBone> *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);

View File

@ -14,7 +14,8 @@
#include "ragdoll.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_stepJointNodeTree(rigBones)
{
@ -23,6 +24,18 @@ RagDoll::RagDoll(const std::vector<RiggerBone> *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) {
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<RiggerBone> *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<RiggerBone> *rigBones) :
std::set<std::pair<QString, QString>> 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<RiggerBone> *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()),

View File

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