17 #include "linmath/float3x3.h" 18 #include <ResourceManager.h> 20 #include "BoneTransformer.h" 23 BoneTransformer::BoneTransformer(aiScene *aiScene){
25 globalInverseTransform = convertAiMatrixToFloat4x4(aiScene->mRootNode->mTransformation.Inverse());
26 this->assimpScene = aiScene;
29 void BoneTransformer::readNodeHierarchyAndUpdateBoneTransformations(
float currentAnimationTick,
30 aiNode *currentAssimpNode,
31 chag::float4x4 parentMatrix) {
32 std::string nodeName(currentAssimpNode->mName.data);
34 chag::float4x4 nodeTransformationMatrix = getCurrentNodeTransformation(currentAnimationTick, currentAssimpNode, nodeName);
35 chag::float4x4 globalTransformation = parentMatrix * nodeTransformationMatrix;
38 if(nodeIsABone(nodeName)) {
39 updateBoneTransformation(nodeName, globalTransformation);
42 for (
unsigned int i = 0; i < currentAssimpNode->mNumChildren; i++) {
43 readNodeHierarchyAndUpdateBoneTransformations(currentAnimationTick, currentAssimpNode->mChildren[i],
44 globalTransformation);
48 void BoneTransformer::updateBoneTransformation(
const std::string &nodeName,
const chag::float4x4 &globalTransformation) {
49 uint boneIndex = boneNameToIndexMapping[nodeName];
51 boneInfos[boneIndex]->finalTransformation = globalInverseTransform * globalTransformation * boneInfos[boneIndex]->boneOffset;
54 bool BoneTransformer::nodeIsABone(
const std::string &nodeName)
const {
55 return boneNameToIndexMapping.find(nodeName) != boneNameToIndexMapping.end();
58 chag::float4x4 BoneTransformer::getCurrentNodeTransformation(
float currentAnimationTick,
59 const aiNode *currentAssimpNode,
60 const std::string nodeName) {
61 const aiNodeAnim *nodeAnimation = getAnimationNode(nodeName);
62 if(nodeAnimation ==
nullptr) {
68 return convertAiMatrixToFloat4x4(currentAssimpNode->mTransformation);
70 return getInterpolatedAnimationMatrix(currentAnimationTick, nodeAnimation);
75 chag::float4x4 BoneTransformer::getInterpolatedAnimationMatrix(
float currentAnimationTick,
const aiNodeAnim *nodeAnimation) {
76 chag::float4x4 scalingMatrix = getInterpolatedScalingMatrix(currentAnimationTick, nodeAnimation);
77 chag::float4x4 rotationMatrix = getInterpolatedRotationMatrix(currentAnimationTick, nodeAnimation);
78 chag::float4x4 translationMatrix = getInterpolatedTranslationMatrix(currentAnimationTick, nodeAnimation);
80 chag::float4x4 interpolatedMatrix = translationMatrix * rotationMatrix * scalingMatrix;
81 return interpolatedMatrix;
84 chag::float4x4 BoneTransformer::getInterpolatedTranslationMatrix(
float currentAnimationTick,
const aiNodeAnim *nodeAnimation) {
85 aiVector3D translation = calculateTranslationInterpolation(currentAnimationTick, nodeAnimation);
86 chag::float4x4 translationMatrix =
87 chag::make_translation(chag::make_vector(
91 return translationMatrix;
94 chag::float4x4 BoneTransformer::getInterpolatedRotationMatrix(
float currentAnimationTick,
const aiNodeAnim *nodeAnimation) {
95 aiQuaternion rotationQuaternion = calculateRotationInterpolation(currentAnimationTick, nodeAnimation);
96 chag::float4x4 rotationMatrix = chag::make_matrix(
97 convertAiMatrixToFloat3x3(rotationQuaternion.GetMatrix()),
98 chag::make_vector(0.0f, 0.0f, 0.0f)
100 return rotationMatrix;
103 chag::float4x4 BoneTransformer::getInterpolatedScalingMatrix(
float currentAnimationTick,
const aiNodeAnim *nodeAnimation) {
104 aiVector3D scaling = calculateScalingInterpolation(currentAnimationTick, nodeAnimation);
105 chag::float4x4 scalingMatrix = chag::make_scale<chag::float4x4>(chag::make_vector(scaling.x, scaling.y, scaling.z));
106 return scalingMatrix;
109 const aiNodeAnim *BoneTransformer::getAnimationNode(
const std::string &nodeName) {
110 const aiAnimation* animation = assimpScene->mAnimations[0];
112 const aiNodeAnim* nodeAnimation = findNodeAnim(animation, nodeName);
113 return nodeAnimation;
116 const aiNodeAnim* BoneTransformer::findNodeAnim(
const aiAnimation* animation,
const std::string nodeName) {
117 for (
unsigned int i = 0; i < animation->mNumChannels; i++) {
118 const aiNodeAnim* nodeAnimation = animation->mChannels[i];
119 if(std::string(nodeAnimation->mNodeName.data) == nodeName) {
120 return nodeAnimation;
126 aiVector3D BoneTransformer::calculateScalingInterpolation(
float currentAnimationTick,
const aiNodeAnim *nodeAnimation) {
127 if(nodeAnimation->mNumScalingKeys <= 1) {
128 return nodeAnimation->mScalingKeys[0].mValue;
131 unsigned int currentScalingIndex = findScalingIndexRightBeforeTick(currentAnimationTick, nodeAnimation);
132 unsigned int nextScalingIndex = currentScalingIndex + 1;
133 assert(nextScalingIndex < nodeAnimation->mNumScalingKeys);
135 double deltaTimeBetweenAnimations = nodeAnimation->mScalingKeys[nextScalingIndex].mTime -
136 nodeAnimation->mScalingKeys[currentScalingIndex].mTime;
137 double deltaFactor = (currentAnimationTick - nodeAnimation->mScalingKeys[currentScalingIndex].mTime) /
138 deltaTimeBetweenAnimations;
139 assert(deltaFactor >= 0.0f && deltaFactor <= 1.0f);
140 const aiVector3D ¤tScalingVector = nodeAnimation->mScalingKeys[currentScalingIndex].mValue;
141 const aiVector3D &nextScalingVector = nodeAnimation->mScalingKeys[nextScalingIndex].mValue;
143 return (nextScalingVector - currentScalingVector) * (float)deltaFactor;
146 aiQuaternion BoneTransformer::calculateRotationInterpolation(
float currentAnimationTick,
const aiNodeAnim *nodeAnimation) {
147 if(nodeAnimation->mNumRotationKeys <= 1) {
148 return nodeAnimation->mRotationKeys[0].mValue;
151 unsigned int currentRotationIndex = findRotationIndexRightBeforeTick(currentAnimationTick, nodeAnimation);
152 unsigned int nextRotationIndex = currentRotationIndex + 1;
153 assert(nextRotationIndex < nodeAnimation->mNumRotationKeys);
155 double deltaTimeBetweenAnimations = nodeAnimation->mRotationKeys[nextRotationIndex].mTime -
156 nodeAnimation->mRotationKeys[currentRotationIndex].mTime;
157 double deltaFactor = (currentAnimationTick - nodeAnimation->mRotationKeys[currentRotationIndex].mTime) /
158 deltaTimeBetweenAnimations;
159 assert(deltaFactor >= 0.0f && deltaFactor <= 1.0f);
160 const aiQuaternion ¤tRotationQuaternion = nodeAnimation->mRotationKeys[currentRotationIndex].mValue;
161 const aiQuaternion &nextRotationQuaternion = nodeAnimation->mRotationKeys[nextRotationIndex].mValue;
162 aiQuaternion interpolatedQuaternion;
163 aiQuaterniont<float>::Interpolate(interpolatedQuaternion, currentRotationQuaternion, nextRotationQuaternion, deltaFactor);
165 return interpolatedQuaternion;
168 aiVector3D BoneTransformer::calculateTranslationInterpolation(
float currentAnimationTick,
const aiNodeAnim *nodeAnimation) {
169 if(nodeAnimation->mNumPositionKeys <= 1) {
170 return nodeAnimation->mPositionKeys[0].mValue;
173 unsigned int currentTranslationIndex = findTranslationIndexRightBeforeTick(currentAnimationTick, nodeAnimation);
174 unsigned int nextTranslationIndex = currentTranslationIndex + 1;
175 assert(nextTranslationIndex < nodeAnimation->mNumPositionKeys);
177 double deltaTimeBetweenAnimations = nodeAnimation->mPositionKeys[nextTranslationIndex].mTime -
178 nodeAnimation->mPositionKeys[currentTranslationIndex].mTime;
179 double deltaFactor = (currentAnimationTick - nodeAnimation->mPositionKeys[currentTranslationIndex].mTime) /
180 deltaTimeBetweenAnimations;
181 assert(deltaFactor >= 0.0f && deltaFactor <= 1.0f);
182 const aiVector3D ¤tTranslationVector = nodeAnimation->mPositionKeys[currentTranslationIndex].mValue;
183 const aiVector3D &nextTranslationVector = nodeAnimation->mPositionKeys[nextTranslationIndex].mValue;
185 return currentTranslationVector + ((nextTranslationVector - currentTranslationVector) * (
float)deltaFactor);
189 unsigned int BoneTransformer::findScalingIndexRightBeforeTick(
float currentAnimationTick, const aiNodeAnim *nodeAnimation) {
190 for (
unsigned int i = 0; i < nodeAnimation->mNumScalingKeys - 1; i++) {
191 if(currentAnimationTick < nodeAnimation->mScalingKeys[i + 1].mTime) {
196 throw std::invalid_argument(
"Tried to find a scaling index in an animation, but couldn't find it");
199 unsigned int BoneTransformer::findRotationIndexRightBeforeTick(
float currentAnimationTick,
const aiNodeAnim *nodeAnimation) {
200 for (
unsigned int i = 0; i < nodeAnimation->mNumRotationKeys - 1; i++) {
201 if(currentAnimationTick < nodeAnimation->mRotationKeys[i + 1].mTime) {
206 throw std::invalid_argument(
"Tried to find a rotation index in an animation, but couldn't find it");
209 unsigned int BoneTransformer::findTranslationIndexRightBeforeTick(
float currentAnimationTick,
const aiNodeAnim *nodeAnimation) {
210 for (
unsigned int i = 0; i < nodeAnimation->mNumPositionKeys - 1; i++) {
211 if(currentAnimationTick < nodeAnimation->mPositionKeys[i + 1].mTime) {
216 throw std::invalid_argument(
"Tried to find a translation index in an animation, but couldn't find it");
221 chag::float4x4 rootMatrix = chag::make_identity<chag::float4x4>();
223 double currentAnimationTick = getCurrentAnimationTick(totalElapsedTimeInSeconds);
225 readNodeHierarchyAndUpdateBoneTransformations((
float)currentAnimationTick, assimpScene->mRootNode, rootMatrix);
227 std::vector<chag::float4x4> boneTransformMatrices;
228 boneTransformMatrices.resize(numberOfBones);
229 for (
int bone = 0; bone < numberOfBones; bone++) {
230 boneTransformMatrices[bone] = boneInfos[bone]->finalTransformation;
232 return boneTransformMatrices;
237 std::string boneName(bone->mName.data);
239 if(boneNameToIndexMapping.find(boneName) == boneNameToIndexMapping.end()) {
241 boneNameToIndexMapping.insert(std::pair<std::string, int>(boneName, numberOfBones));
244 boneInfos.push_back(boneInfo);
245 boneInfo->boneOffset = convertAiMatrixToFloat4x4(bone->mOffsetMatrix);
247 boneIndex = numberOfBones;
250 boneIndex = boneNameToIndexMapping[boneName];
255 double BoneTransformer::getCurrentAnimationTick(
float totalElapsedTimeInSeconds)
const {
256 double ticksPerSecond = assimpScene->mAnimations[0]->mTicksPerSecond;
257 ticksPerSecond = ticksPerSecond == 0 ? 25 : ticksPerSecond;
259 double elapsedTimeInTicks = totalElapsedTimeInSeconds * ticksPerSecond;
260 double animationDurationInTicks = assimpScene->mAnimations[0]->mDuration;
261 double currentAnimationTick = fmod(elapsedTimeInTicks, animationDurationInTicks);
262 return currentAnimationTick;