diff --git a/include/Engine/Rendering/Skeleton.h b/include/Engine/Rendering/Skeleton.h index ccf3e2b4..28a5ef6a 100644 --- a/include/Engine/Rendering/Skeleton.h +++ b/include/Engine/Rendering/Skeleton.h @@ -113,6 +113,8 @@ public: std::map Animations; glm::mat4 GetBoneTransform(const Bone* bone, const Animation* animation, float time, glm::mat4 childMatrix); + glm::mat4 GetBoneTransform(bool noRootMotion, const Bone* bone, std::vector animations, AnimationOffset animationOffset, glm::mat4 childMatrix); + glm::mat4 GetBoneTransform(bool noRootMotion, const Bone* bone, std::vector animations, glm::mat4 childMatrix); int GetKeyframe(const Animation& animation, double time); private: diff --git a/resources/Schema/Entities/AnimationTests2.xml b/resources/Schema/Entities/AnimationTests2.xml index f027dd1d..413c7e67 100644 --- a/resources/Schema/Entities/AnimationTests2.xml +++ b/resources/Schema/Entities/AnimationTests2.xml @@ -15,9 +15,7 @@ - - - + Models/Widgets/Lights/DirectionalLightWidget.mesh @@ -33,7 +31,7 @@ Run 0.5 - 0.99150007800799234 + 0.60188997954429357 -1 1 0.5 @@ -43,6 +41,7 @@ AimRifle + Models/Characters/Assault/AssaultAnimations.mesh @@ -62,8 +61,8 @@ Models/Weapons/Red/AssaultWeaponRed.mesh - - + + @@ -110,21 +109,17 @@ ShootFastRifle - 0.068159934509623099 + 0.056234247235838808 1 1 - Run + Idl 0.5 - 0.19240865965109588 - StrafeRight + 1.8308673495784191 + StrafeRigh 0.5 - 0.12533627444542628 + 0.32167823998061529 1 - - AimRifle - - Models/Characters/Assault/AssaultAnimations.mesh @@ -140,8 +135,7 @@ Models/Weapons/Red/AssaultWeaponRed.mesh - - + diff --git a/src/Engine/Rendering/BoneAttachmentSystem.cpp b/src/Engine/Rendering/BoneAttachmentSystem.cpp index c0c2b8de..3effaf2c 100644 --- a/src/Engine/Rendering/BoneAttachmentSystem.cpp +++ b/src/Engine/Rendering/BoneAttachmentSystem.cpp @@ -19,6 +19,9 @@ void BoneAttachmentSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapp return; } + if (!model->IsSkinned()) { + return; + } Skeleton* skeleton = model->m_RawModel->m_Skeleton; @@ -26,19 +29,46 @@ void BoneAttachmentSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapp return; } - const Skeleton::Animation* animation = skeleton->GetAnimation(parent["Animation"]["AnimationName1"]); - - if (!animation) { - return; - } - int id = skeleton->GetBoneID(entity["BoneAttachment"]["BoneName"]); - if(id == -1) { + if (id == -1) { return; } - glm::mat4 boneTransform = skeleton->GetBoneTransform(skeleton->Bones[id], animation, (double)parent["Animation"]["Time1"], glm::mat4(1)); + std::vector<::Skeleton::AnimationData> Animations; + ::Skeleton::AnimationOffset AnimationOffset; + glm::mat4 boneTransform; + + if (parent.HasComponent("Animation")) { + for (int i = 1; i <= 3; i++) { + ::Skeleton::AnimationData animationData; + animationData.animation = model->m_RawModel->m_Skeleton->GetAnimation(parent["Animation"]["AnimationName" + std::to_string(i)]); + if (animationData.animation == nullptr) { + continue; + } + animationData.time = (double)parent["Animation"]["Time" + std::to_string(i)]; + animationData.weight = (double)parent["Animation"]["Weight" + std::to_string(i)]; + + Animations.push_back(animationData); + } + } + + if (parent.HasComponent("AnimationOffset")) { + AnimationOffset.animation = model->m_RawModel->m_Skeleton->GetAnimation(parent["AnimationOffset"]["AnimationName"]); + AnimationOffset.time = (double)parent["AnimationOffset"]["Time"]; + + if(AnimationOffset.animation != nullptr) { + boneTransform = skeleton->GetBoneTransform(false, skeleton->Bones.at(id), Animations, AnimationOffset, glm::mat4(1)); + } else { + boneTransform = skeleton->GetBoneTransform(false, skeleton->Bones.at(id), Animations, glm::mat4(1)); + } + + } else { + boneTransform = skeleton->GetBoneTransform(false, skeleton->Bones.at(id), Animations, glm::mat4(1)); + } + + + glm::vec3 scale; glm::quat rotation; glm::vec3 translation; diff --git a/src/Engine/Rendering/Skeleton.cpp b/src/Engine/Rendering/Skeleton.cpp index f85efd17..e390d694 100644 --- a/src/Engine/Rendering/Skeleton.cpp +++ b/src/Engine/Rendering/Skeleton.cpp @@ -448,6 +448,249 @@ glm::mat4 Skeleton::GetBoneTransform(const Bone* bone, const Animation* animatio } } + +glm::mat4 Skeleton::GetBoneTransform(bool noRootMotion, const Bone* bone, std::vector animations, AnimationOffset animationOffset, glm::mat4 childMatrix) +{ + glm::mat4 boneMatrix; + + std::vector JointTransforms; + + for (const AnimationData animationData : animations) { + const Animation* animation = animationData.animation; + const float time = animationData.time; + + JointFrameTransform jointTransform; + jointTransform.Weight = animationData.weight;; + + if (animation->JointAnimations.find(bone->ID) != animation->JointAnimations.end()) { + std::vector boneKeyFrames = animation->JointAnimations.at(bone->ID); + + Animation::Keyframe currentFrame; + Animation::Keyframe nextFrame; + + if (boneKeyFrames.size() > 1) { // 2+ keyframes for the current bone + for (int index = boneKeyFrames.size()-1; index >= 0; index--) { // find the bone keyframes that surrounds the current frame + if (time >= boneKeyFrames.at(index).Time) { + currentFrame = boneKeyFrames.at(index); + nextFrame = boneKeyFrames.at((index + 1) % boneKeyFrames.size()); + break; + } + } + + float progress; + + if (nextFrame.Index == 0) { + nextFrame = currentFrame; + progress = (time - currentFrame.Time) / (animation->Duration - currentFrame.Time); + } else { + progress = (time - currentFrame.Time) / (nextFrame.Time - currentFrame.Time); + + } + + + if (progress > 1.0f || progress < 0.0f) { + LOG_INFO("Progress: %f", progress); + progress = glm::clamp(progress, 0.0f, 1.0f); + } + Animation::Keyframe::BoneProperty currentBoneProperty = currentFrame.BoneProperties; + Animation::Keyframe::BoneProperty nextBoneProperty = nextFrame.BoneProperties; + + jointTransform.PositionInterp = currentBoneProperty.Position * (1.f - progress) + nextBoneProperty.Position * progress; + jointTransform.RotationInterp = glm::slerp(currentBoneProperty.Rotation, nextBoneProperty.Rotation, progress); + jointTransform.ScaleInterp = currentBoneProperty.Scale * (1.f - progress) + nextBoneProperty.Scale * progress; + + // Flag for no root motion + if (bone == RootBone && noRootMotion) { + jointTransform.PositionInterp.x = 0; + jointTransform.PositionInterp.z = 0; + } + + JointTransforms.push_back(jointTransform); + + } else { // 1 keyframes for the current bone + currentFrame = boneKeyFrames.at(0); + jointTransform.PositionInterp = currentFrame.BoneProperties.Position; + jointTransform.RotationInterp = currentFrame.BoneProperties.Rotation; + jointTransform.ScaleInterp = currentFrame.BoneProperties.Scale; + JointTransforms.push_back(jointTransform); + + } + } else { // 0 keyframes for the current bone + + } + + } + + + glm::mat4 offset = GetOffsetTransform(bone, animationOffset); + + if (JointTransforms.size() == 0) { + if (bone->Parent) { + if (offset != glm::mat4(1)) { + boneMatrix = offset * childMatrix;// *((glm::inverse(bone->OffsetMatrix) * bone->Parent->OffsetMatrix)); + } else { + boneMatrix = ((glm::inverse(bone->OffsetMatrix) * bone->Parent->OffsetMatrix)) * childMatrix; + } + } else { + boneMatrix = offset * glm::inverse(bone->OffsetMatrix); + } + } else { + + glm::vec3 finalPosInterp; + glm::quat finalRotInterp; + glm::vec3 finalScaleInterp; + float totalWeight = 0; + + for (JointFrameTransform jointTransform : JointTransforms) { + totalWeight += jointTransform.Weight; + } + + + for (JointFrameTransform jointTransform : JointTransforms) { + if (jointTransform.Weight == 1.0f) { + finalPosInterp = jointTransform.PositionInterp; + finalRotInterp = jointTransform.RotationInterp; + finalScaleInterp = jointTransform.ScaleInterp; + break; + } else { + finalPosInterp += jointTransform.PositionInterp * (jointTransform.Weight/totalWeight); + finalRotInterp *= glm::slerp(glm::quat(), jointTransform.RotationInterp, (jointTransform.Weight/totalWeight)); + finalScaleInterp += jointTransform.ScaleInterp * (jointTransform.Weight/totalWeight); + } + + } + + if (offset != glm::mat4(1)) { + boneMatrix = ((glm::translate(finalPosInterp) * glm::toMat4(finalRotInterp) * glm::scale(finalScaleInterp)) + offset) * childMatrix; + } else { + boneMatrix = (glm::translate(finalPosInterp) * glm::toMat4(finalRotInterp) * glm::scale(finalScaleInterp)) * childMatrix; + } + } + + if (bone->Parent != nullptr) { + return GetBoneTransform(noRootMotion, bone->Parent, animations, animationOffset, boneMatrix); + } else { + return boneMatrix; + } +} + + +glm::mat4 Skeleton::GetBoneTransform(bool noRootMotion, const Bone* bone, std::vector animations, glm::mat4 childMatrix) +{ + glm::mat4 boneMatrix; + std::vector JointTransforms; + + for (const AnimationData animationData : animations) { + const Animation* animation = animationData.animation; + const float time = animationData.time; + + JointFrameTransform jointTransform; + jointTransform.Weight = animationData.weight;; + + if (animation->JointAnimations.find(bone->ID) != animation->JointAnimations.end()) { + std::vector boneKeyFrames = animation->JointAnimations.at(bone->ID); + + Animation::Keyframe currentFrame; + Animation::Keyframe nextFrame; + + if (boneKeyFrames.size() > 1) { // 2+ keyframes for the current bone + for (int index = boneKeyFrames.size()-1; index >= 0; index--) { // find the bone keyframes that surrounds the current frame + if (time >= boneKeyFrames.at(index).Time) { + currentFrame = boneKeyFrames.at(index); + nextFrame = boneKeyFrames.at((index + 1) % boneKeyFrames.size()); + break; + } + } + + float progress; + + if (nextFrame.Index == 0) { + nextFrame = currentFrame; + progress = (time - currentFrame.Time) / (animation->Duration - currentFrame.Time); + } else { + progress = (time - currentFrame.Time) / (nextFrame.Time - currentFrame.Time); + + } + + + if (progress > 1.0f || progress < 0.0f) { + LOG_INFO("Progress: %f", progress); + progress = glm::clamp(progress, 0.0f, 1.0f); + } + Animation::Keyframe::BoneProperty currentBoneProperty = currentFrame.BoneProperties; + Animation::Keyframe::BoneProperty nextBoneProperty = nextFrame.BoneProperties; + + jointTransform.PositionInterp = currentBoneProperty.Position * (1.f - progress) + nextBoneProperty.Position * progress; + jointTransform.RotationInterp = glm::slerp(currentBoneProperty.Rotation, nextBoneProperty.Rotation, progress); + jointTransform.ScaleInterp = currentBoneProperty.Scale * (1.f - progress) + nextBoneProperty.Scale * progress; + + // Flag for no root motion + if (bone == RootBone && noRootMotion) { + jointTransform.PositionInterp.x = 0; + jointTransform.PositionInterp.z = 0; + } + + JointTransforms.push_back(jointTransform); + + } else { // 1 keyframes for the current bone + currentFrame = boneKeyFrames.at(0); + jointTransform.PositionInterp = currentFrame.BoneProperties.Position; + jointTransform.RotationInterp = currentFrame.BoneProperties.Rotation; + jointTransform.ScaleInterp = currentFrame.BoneProperties.Scale; + JointTransforms.push_back(jointTransform); + + } + } else { // 0 keyframes for the current bone + + } + + } + + if (JointTransforms.size() <= 0) { + if (bone->Parent) { + boneMatrix = glm::inverse(bone->OffsetMatrix) * bone->Parent->OffsetMatrix * childMatrix; + } else { + boneMatrix = glm::inverse(bone->OffsetMatrix) * childMatrix; + } + } else if (JointTransforms.size() == 1) { + boneMatrix = (glm::translate(JointTransforms.at(0).PositionInterp) * glm::toMat4(JointTransforms.at(0).RotationInterp) * glm::scale(JointTransforms.at(0).ScaleInterp)) * childMatrix; + } else { + + glm::vec3 finalPosInterp; + glm::quat finalRotInterp; + glm::vec3 finalScaleInterp; + float totalWeight = 0; + + for (JointFrameTransform jointTransform : JointTransforms) { + totalWeight += jointTransform.Weight; + } + + + for (JointFrameTransform jointTransform : JointTransforms) { + if (jointTransform.Weight == 1.0f) { + finalPosInterp = jointTransform.PositionInterp; + finalRotInterp = jointTransform.RotationInterp; + finalScaleInterp = jointTransform.ScaleInterp; + break; + } else { + finalPosInterp += jointTransform.PositionInterp * (jointTransform.Weight/totalWeight); + finalRotInterp *= glm::slerp(glm::quat(), jointTransform.RotationInterp, (jointTransform.Weight/totalWeight)); + finalScaleInterp += jointTransform.ScaleInterp * (jointTransform.Weight/totalWeight); + } + } + + boneMatrix = (glm::translate(finalPosInterp) * glm::toMat4(finalRotInterp) * glm::scale(finalScaleInterp)) * childMatrix; + } + + + + if (bone->Parent != nullptr) { + return GetBoneTransform(noRootMotion, bone->Parent, animations, boneMatrix); + } else { + return boneMatrix; + } +} + int Skeleton::GetBoneID(std::string name) { if (m_BonesByName.find(name) == m_BonesByName.end()) {