Fix pose editor
parent
9f12f03d58
commit
839e081d10
|
@ -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++) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()),
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue