diff --git a/45-animation/src/animation.cpp b/45-animation/src/animation.cpp index 76c56ae..1c31ec9 100644 --- a/45-animation/src/animation.cpp +++ b/45-animation/src/animation.cpp @@ -1 +1,84 @@ #include "animation.hpp" +#include "model.hpp" +#include "assimp_glm_helpers.hpp" + +Animation::Animation(const std::string& animationPath, Model *model) { + Assimp::Importer importer; + + const aiScene* scene = importer.ReadFile(animationPath, aiProcess_Triangulate); + dbc::check(scene != nullptr, $F("Scene for animation {} failed to load.", animationPath)); + dbc::check(scene->mRootNode, $F("Scene {} doesn't have a root node.", animationPath)); + + auto animation = scene->mAnimations[0]; + $duration = animation->mDuration; + $ticks_per_sec = animation->mTicksPerSecond; + aiMatrix4x4 globalTransformation = scene->mRootNode->mTransformation; + globalTransformation = globalTransformation.Inverse(); + ReadHierarchyData($root_node, scene->mRootNode); + ReadMissingBones(animation, *model); +} + +Bone* Animation::FindBone(const std::string& name) { + auto iter = std::find_if($bones.begin(), $bones.end(), + [&](const auto& bone) { + return bone.GetBoneName() == name; + } + ); + + return iter == $bones.end() ? nullptr : &(*iter); +} + +float Animation::GetTicksPerSecond() { + return $ticks_per_sec; +} + +float Animation::GetDuration() { + return $duration; +} + +const AssimpNodeData& Animation::GetRootNode() { + return $root_node; +} + +const std::unordered_map& Animation::GetBoneIDMap() +{ + return $bone_info_map; +} + +void Animation::ReadMissingBones(const aiAnimation* animation, Model& model) { + // this code is weird as hell + int size = animation->mNumChannels; + auto& boneInfoMap = model.bone_info_map; + int& boneCount = model.bone_counter; + + for(int i = 0; i < size; i++) { + auto channel = animation->mChannels[i]; + std::string boneName = channel->mNodeName.data; + + if(!boneInfoMap.contains(boneName)) { + boneInfoMap[boneName].id = boneCount; + boneCount++; + } + + dbc::check(boneCount < MAX_BONES, "Too many bones!"); + + $bones.emplace_back(boneName, + boneInfoMap[boneName].id, channel); + } + + $bone_info_map = boneInfoMap; +} + +void Animation::ReadHierarchyData(AssimpNodeData& dest, const aiNode* src) { + dbc::check(src != nullptr, "aiNode src is null?!"); + + dest.name = src->mName.data; + dest.transformation = AssimpGLMHelpers::ConvertMatrixToGLMFormat(src->mTransformation); + dest.children_count = src->mNumChildren; + + for(size_t i = 0; i < src->mNumChildren; i++) { + AssimpNodeData newData; + ReadHierarchyData(newData, src->mChildren[i]); + dest.children.push_back(newData); + } +} diff --git a/45-animation/src/animation.hpp b/45-animation/src/animation.hpp index 12b9d2b..a07b1a0 100644 --- a/45-animation/src/animation.hpp +++ b/45-animation/src/animation.hpp @@ -7,8 +7,6 @@ #include #include "animdata.hpp" #include "bone.hpp" -#include "model.hpp" -#include "assimp_glm_helpers.hpp" struct Bone; @@ -28,88 +26,21 @@ struct Animation { Animation() = default; - Animation(const std::string& animationPath, Model *model) { - Assimp::Importer importer; + Animation(const std::string& animationPath, Model *model); - const aiScene* scene = importer.ReadFile(animationPath, aiProcess_Triangulate); - dbc::check(scene != nullptr, $F("Scene for animation {} failed to load.", animationPath)); - dbc::check(scene->mRootNode, $F("Scene {} doesn't have a root node.", animationPath)); + ~Animation() {} - auto animation = scene->mAnimations[0]; - $duration = animation->mDuration; - $ticks_per_sec = animation->mTicksPerSecond; - aiMatrix4x4 globalTransformation = scene->mRootNode->mTransformation; - globalTransformation = globalTransformation.Inverse(); - ReadHierarchyData($root_node, scene->mRootNode); - ReadMissingBones(animation, *model); - } + Bone* FindBone(const std::string& name); - ~Animation() { - } + float GetTicksPerSecond(); + float GetDuration(); - Bone* FindBone(const std::string& name) { - auto iter = std::find_if($bones.begin(), $bones.end(), - [&](const auto& bone) { - return bone.GetBoneName() == name; - } - ); + const AssimpNodeData& GetRootNode(); - return iter == $bones.end() ? nullptr : &(*iter); - } + const std::unordered_map& GetBoneIDMap(); - float GetTicksPerSecond() { - return $ticks_per_sec; - } + void ReadMissingBones(const aiAnimation* animation, Model& model); - float GetDuration() { - return $duration; - } - - const AssimpNodeData& GetRootNode() { - return $root_node; - } - - const std::unordered_map& GetBoneIDMap() - { - return $bone_info_map; - } - - void ReadMissingBones(const aiAnimation* animation, Model& model) { - // this code is weird as hell - int size = animation->mNumChannels; - auto& boneInfoMap = model.bone_info_map; - int& boneCount = model.bone_counter; - - for(int i = 0; i < size; i++) { - auto channel = animation->mChannels[i]; - std::string boneName = channel->mNodeName.data; - - if(!boneInfoMap.contains(boneName)) { - boneInfoMap[boneName].id = boneCount; - boneCount++; - } - - dbc::check(boneCount < MAX_BONES, "Too many bones!"); - - $bones.emplace_back(boneName, - boneInfoMap[boneName].id, channel); - } - - $bone_info_map = boneInfoMap; - } - - void ReadHierarchyData(AssimpNodeData& dest, const aiNode* src) { - dbc::check(src != nullptr, "aiNode src is null?!"); - - dest.name = src->mName.data; - dest.transformation = AssimpGLMHelpers::ConvertMatrixToGLMFormat(src->mTransformation); - dest.children_count = src->mNumChildren; - - for(size_t i = 0; i < src->mNumChildren; i++) { - AssimpNodeData newData; - ReadHierarchyData(newData, src->mChildren[i]); - dest.children.push_back(newData); - } - } + void ReadHierarchyData(AssimpNodeData& dest, const aiNode* src); }; diff --git a/45-animation/src/animator.cpp b/45-animation/src/animator.cpp index 4e64561..8fbb05d 100644 --- a/45-animation/src/animator.cpp +++ b/45-animation/src/animator.cpp @@ -1 +1,57 @@ #include "animator.hpp" +#include +#include +#include "bone.hpp" + +Animator::Animator(Animation* animation) : + $current_animation(animation) +{ + $final_bone_matrices.reserve(MAX_BONES); + + for(size_t i = 0; i < MAX_BONES; i++) { + $final_bone_matrices.push_back(glm::mat4(1.0f)); + } +} + +void Animator::UpdateAnimation(float current_time) { + if($current_animation) { + $current_time = $current_animation->GetTicksPerSecond() * current_time; + $current_time = fmod($current_time, $current_animation->GetDuration()); + CalculateBoneTransform(&$current_animation->GetRootNode(), glm::mat4(1.0f)); + } +} + +void Animator::PlayAnimation(Animation* animation) { + $current_animation = animation; + $current_time = 0.0f; +} + +void Animator::CalculateBoneTransform(const AssimpNodeData* node, glm::mat4 parentTransform) { + std::string node_name = node->name; + glm::mat4 node_transform = node->transformation; + + Bone *bone = $current_animation->FindBone(node_name); + + if(bone) { + bone->Update($current_time); + node_transform = bone->GetLocalTransform(); + } + + glm::mat4 global_transformation = parentTransform * node_transform; + + auto bone_map = $current_animation->GetBoneIDMap(); + + if(bone_map.contains(node_name)) { + auto& bone_info = bone_map[node_name]; + + $final_bone_matrices[bone_info.id] = global_transformation * bone_info.offset; + } + + for(int i = 0; i < node->children_count; i++) { + CalculateBoneTransform(&node->children[i], global_transformation); + } +} + +std::vector& Animator::GetFinalBoneMatrices() { + return $final_bone_matrices; +} diff --git a/45-animation/src/animator.hpp b/45-animation/src/animator.hpp index 8122a0c..094059a 100644 --- a/45-animation/src/animator.hpp +++ b/45-animation/src/animator.hpp @@ -1,72 +1,22 @@ #pragma once - #include #include #include -#include -#include #include "animation.hpp" -#include "bone.hpp" - -struct Bone; struct Animator { std::vector $final_bone_matrices; Animation* $current_animation = nullptr; float $current_time = 0.0f; - Animator(Animation* animation) : - $current_animation(animation) - { - $final_bone_matrices.reserve(MAX_BONES); + Animator(Animation* animation); - for(size_t i = 0; i < MAX_BONES; i++) { - $final_bone_matrices.push_back(glm::mat4(1.0f)); - } - } + void UpdateAnimation(float current_time); - void UpdateAnimation(float current_time) { - if($current_animation) { - $current_time = $current_animation->GetTicksPerSecond() * current_time; - $current_time = fmod($current_time, $current_animation->GetDuration()); - CalculateBoneTransform(&$current_animation->GetRootNode(), glm::mat4(1.0f)); - } - } + void PlayAnimation(Animation* animation); - void PlayAnimation(Animation* animation) { - $current_animation = animation; - $current_time = 0.0f; - } - - void CalculateBoneTransform(const AssimpNodeData* node, glm::mat4 parentTransform) { - std::string node_name = node->name; - glm::mat4 node_transform = node->transformation; - - Bone *bone = $current_animation->FindBone(node_name); - - if(bone) { - bone->Update($current_time); - node_transform = bone->GetLocalTransform(); - } - - glm::mat4 global_transformation = parentTransform * node_transform; - - auto bone_map = $current_animation->GetBoneIDMap(); - - if(bone_map.contains(node_name)) { - auto& bone_info = bone_map[node_name]; - - $final_bone_matrices[bone_info.id] = global_transformation * bone_info.offset; - } - - for(int i = 0; i < node->children_count; i++) { - CalculateBoneTransform(&node->children[i], global_transformation); - } - } - - std::vector& GetFinalBoneMatrices() { - return $final_bone_matrices; - } + void CalculateBoneTransform(const AssimpNodeData* node, glm::mat4 parentTransform); + std::vector& GetFinalBoneMatrices(); }; diff --git a/45-animation/src/bone.cpp b/45-animation/src/bone.cpp index 00c3c32..b3b332e 100644 --- a/45-animation/src/bone.cpp +++ b/45-animation/src/bone.cpp @@ -1 +1,144 @@ #include "bone.hpp" +#include "assimp_glm_helpers.hpp" + +Bone::Bone(const std::string& name, int ID, const aiNodeAnim* channel) : + $name(name), + $id(ID) +{ + $num_positions = channel->mNumPositionKeys; + + for(size_t pos_i = 0; pos_i < $num_positions; pos_i++) { + const auto& ai_position = channel->mPositionKeys[pos_i]; + auto position = AssimpGLMHelpers::GetGLMVec(ai_position.mValue); + $positions.emplace_back(position, ai_position.mTime); + } + + $num_rotations = channel->mNumRotationKeys; + for(size_t rot_i = 0; rot_i < $num_rotations; rot_i++) { + const auto& ai_orientation = channel->mRotationKeys[rot_i]; + auto orientation = AssimpGLMHelpers::GetGLMQuat(ai_orientation.mValue); + + $rotations.emplace_back(orientation, ai_orientation.mTime); + } + + $num_scalings = channel->mNumScalingKeys; + for(size_t key_i = 0; key_i < $num_scalings; key_i++) { + const auto& ai_scale = channel->mScalingKeys[key_i]; + auto scale = AssimpGLMHelpers::GetGLMVec(ai_scale.mValue); + $scales.emplace_back(scale, ai_scale.mTime); + } +} + +void Bone::Update(float animationTime) { + glm::mat4 translation = InterpolatPosition(animationTime); + glm::mat4 rotation = InterpolateRotation(animationTime); + glm::mat4 scale = InterpolateScaling(animationTime); + $local_transform = translation * rotation * scale; +} + +glm::mat4 Bone::GetLocalTransform() { + return $local_transform; +} + +std::string Bone::GetBoneName() const { + return $name; +} + +int Bone::GetBoneId() { + return $id; +} + +int Bone::GetPositionIndex(float animationTime) { + for(size_t index = 0; index < $num_positions - 1; ++index) { + auto ts = $positions[index + 1].timeStamp; + + if(animationTime < ts) { + return index; + } + } + + dbc::sentinel("Failed to find an animation position"); +} + +int Bone::GetRotationIndex(float animationTime) { + for(size_t index = 0; index < $num_rotations - 1; ++index) { + auto ts = $rotations[index + 1].timeStamp; + + if(animationTime < ts) { + return index; + } + } + dbc::sentinel("Failed to find an animation rotation"); +} + +int Bone::GetScaleIndex(float animationTime) { + for(size_t index = 0; index < $num_scalings - 1; ++index) { + auto ts = $scales[index + 1].timeStamp; + if(animationTime < ts) { + return index; + } + } + dbc::sentinel("Failed to find an animation scale"); +} + +float Bone::GetScaleFactor(float lastTimeStamp, float nextTimeStamp, float animationTime) { + float scaleFactor = 0.0f; + float midWayLength = animationTime - lastTimeStamp; + float framesDiff = nextTimeStamp - lastTimeStamp; + scaleFactor = midWayLength / framesDiff; + return scaleFactor; +} + +glm::mat4 Bone::InterpolatPosition(float animationTime) { + if($num_positions == 1) { + return glm::translate(glm::mat4(1.0f), $positions[0].position); + } + + int p0Index = GetPositionIndex(animationTime); + auto& p0 = $positions[p0Index]; + auto& p1 = $positions[p0Index + 1]; + + float scaleFactor = GetScaleFactor( + p0.timeStamp, p1.timeStamp, animationTime); + + glm::vec3 finalPosition = glm::mix(p0.position, + p1.position, scaleFactor); + + return glm::translate(glm::mat4(1.0f), finalPosition); +} + +glm::mat4 Bone::InterpolateRotation(float animationTime) { + if($num_rotations == 1) { + auto rotation = glm::normalize($rotations[0].orientation); + return glm::toMat4(rotation); + } + + int p0Index = GetRotationIndex(animationTime); + auto& p0 = $rotations[p0Index]; + auto& p1 = $rotations[p0Index + 1]; + + float scaleFactor = GetScaleFactor( + p0.timeStamp, p1.timeStamp, animationTime); + + glm::quat finalRotation = glm::slerp( + p0.orientation, p1.orientation, scaleFactor); + + return glm::toMat4(finalRotation); +} + +glm::mat4 Bone::InterpolateScaling(float animationTime) { + if($num_scalings == 1) { + return glm::scale(glm::mat4(1.0f), $scales[0].scale); + } + + int p0Index = GetScaleIndex(animationTime); + + auto& p0 = $scales[p0Index]; + auto& p1 = $scales[p0Index + 1]; + float scaleFactor = GetScaleFactor( + p0.timeStamp, p1.timeStamp, animationTime); + + glm::vec3 finalScale = glm::mix(p0.scale, p1.scale, scaleFactor); + + return glm::scale(glm::mat4(1.0f), finalScale); +} diff --git a/45-animation/src/bone.hpp b/45-animation/src/bone.hpp index 3e3ca34..852d0ef 100644 --- a/45-animation/src/bone.hpp +++ b/45-animation/src/bone.hpp @@ -6,7 +6,6 @@ #include #define GLM_ENABLE_EXPERIMENTAL #include -#include "assimp_glm_helpers.hpp" #include struct KeyPosition { @@ -40,145 +39,27 @@ struct Bone std::string $name{}; int $id = 0; - Bone(const std::string& name, int ID, const aiNodeAnim* channel) : - $name(name), - $id(ID) - { - $num_positions = channel->mNumPositionKeys; + Bone(const std::string& name, int ID, const aiNodeAnim* channel); - for(size_t pos_i = 0; pos_i < $num_positions; pos_i++) { - const auto& ai_position = channel->mPositionKeys[pos_i]; - auto position = AssimpGLMHelpers::GetGLMVec(ai_position.mValue); - $positions.emplace_back(position, ai_position.mTime); - } + void Update(float animationTime); - $num_rotations = channel->mNumRotationKeys; - for(size_t rot_i = 0; rot_i < $num_rotations; rot_i++) { - const auto& ai_orientation = channel->mRotationKeys[rot_i]; - auto orientation = AssimpGLMHelpers::GetGLMQuat(ai_orientation.mValue); + glm::mat4 GetLocalTransform(); - $rotations.emplace_back(orientation, ai_orientation.mTime); - } + std::string GetBoneName() const; - $num_scalings = channel->mNumScalingKeys; - for(size_t key_i = 0; key_i < $num_scalings; key_i++) { - const auto& ai_scale = channel->mScalingKeys[key_i]; - auto scale = AssimpGLMHelpers::GetGLMVec(ai_scale.mValue); - $scales.emplace_back(scale, ai_scale.mTime); - } - } + int GetBoneId(); - void Update(float animationTime) { - glm::mat4 translation = InterpolatPosition(animationTime); - glm::mat4 rotation = InterpolateRotation(animationTime); - glm::mat4 scale = InterpolateScaling(animationTime); - $local_transform = translation * rotation * scale; - } + int GetPositionIndex(float animationTime); - glm::mat4 GetLocalTransform() { - return $local_transform; - } + int GetRotationIndex(float animationTime); - std::string GetBoneName() const { - return $name; - } + int GetScaleIndex(float animationTime); - int GetBoneId() { - return $id; - } + float GetScaleFactor(float lastTimeStamp, float nextTimeStamp, float animationTime); - int GetPositionIndex(float animationTime) { - for(size_t index = 0; index < $num_positions - 1; ++index) { - auto ts = $positions[index + 1].timeStamp; + glm::mat4 InterpolatPosition(float animationTime); - if(animationTime < ts) { - return index; - } - } + glm::mat4 InterpolateRotation(float animationTime); - dbc::sentinel("Failed to find an animation position"); - } - - int GetRotationIndex(float animationTime) { - for(size_t index = 0; index < $num_rotations - 1; ++index) { - auto ts = $rotations[index + 1].timeStamp; - - if(animationTime < ts) { - return index; - } - } - dbc::sentinel("Failed to find an animation rotation"); - } - - int GetScaleIndex(float animationTime) { - for(size_t index = 0; index < $num_scalings - 1; ++index) { - auto ts = $scales[index + 1].timeStamp; - if(animationTime < ts) { - return index; - } - } - dbc::sentinel("Failed to find an animation scale"); - } - - float GetScaleFactor(float lastTimeStamp, float nextTimeStamp, float animationTime) { - float scaleFactor = 0.0f; - float midWayLength = animationTime - lastTimeStamp; - float framesDiff = nextTimeStamp - lastTimeStamp; - scaleFactor = midWayLength / framesDiff; - return scaleFactor; - } - - glm::mat4 InterpolatPosition(float animationTime) { - if($num_positions == 1) { - return glm::translate(glm::mat4(1.0f), $positions[0].position); - } - - int p0Index = GetPositionIndex(animationTime); - auto& p0 = $positions[p0Index]; - auto& p1 = $positions[p0Index + 1]; - - float scaleFactor = GetScaleFactor( - p0.timeStamp, p1.timeStamp, animationTime); - - glm::vec3 finalPosition = glm::mix(p0.position, - p1.position, scaleFactor); - - return glm::translate(glm::mat4(1.0f), finalPosition); - } - - glm::mat4 InterpolateRotation(float animationTime) { - if($num_rotations == 1) { - auto rotation = glm::normalize($rotations[0].orientation); - return glm::toMat4(rotation); - } - - int p0Index = GetRotationIndex(animationTime); - auto& p0 = $rotations[p0Index]; - auto& p1 = $rotations[p0Index + 1]; - - float scaleFactor = GetScaleFactor( - p0.timeStamp, p1.timeStamp, animationTime); - - glm::quat finalRotation = glm::slerp( - p0.orientation, p1.orientation, scaleFactor); - - return glm::toMat4(finalRotation); - } - - glm::mat4 InterpolateScaling(float animationTime) { - if($num_scalings == 1) { - return glm::scale(glm::mat4(1.0f), $scales[0].scale); - } - - int p0Index = GetScaleIndex(animationTime); - - auto& p0 = $scales[p0Index]; - auto& p1 = $scales[p0Index + 1]; - float scaleFactor = GetScaleFactor( - p0.timeStamp, p1.timeStamp, animationTime); - - glm::vec3 finalScale = glm::mix(p0.scale, p1.scale, scaleFactor); - - return glm::scale(glm::mat4(1.0f), finalScale); - } + glm::mat4 InterpolateScaling(float animationTime); };