diff --git a/GlitchyEngine/src/Renderer/Animation/Skeleton.bf b/GlitchyEngine/src/Renderer/Animation/Skeleton.bf index 10128bf..a2e189d 100644 --- a/GlitchyEngine/src/Renderer/Animation/Skeleton.bf +++ b/GlitchyEngine/src/Renderer/Animation/Skeleton.bf @@ -29,6 +29,9 @@ namespace GlitchyEngine.Renderer.Animation private Skeleton _skeleton ~ _.ReleaseRef(); public JointPose[] LocalPose ~ delete _; public Matrix[] GlobalPose ~ delete _; + + public Matrix[] SkinningMatricies ~ delete _; + public Matrix3x3[] InvTransSkinningMatricies ~ delete _; public Skeleton Skeleton => _skeleton; @@ -40,6 +43,9 @@ namespace GlitchyEngine.Renderer.Animation LocalPose = new JointPose[jointCount]; GlobalPose = new Matrix[jointCount]; + + SkinningMatricies = new Matrix[jointCount]; + InvTransSkinningMatricies = new Matrix3x3[jointCount]; } } } diff --git a/GlitchyEngine/src/World/AnimationComponent.bf b/GlitchyEngine/src/World/AnimationComponent.bf index e656144..3b42ffa 100644 --- a/GlitchyEngine/src/World/AnimationComponent.bf +++ b/GlitchyEngine/src/World/AnimationComponent.bf @@ -6,6 +6,8 @@ namespace GlitchyEngine.World { private AnimationClip _animationClip; + private SkeletonPose _pose; + public AnimationClip AnimationClip { get => _animationClip; @@ -20,11 +22,20 @@ namespace GlitchyEngine.World } } + public float TimeIndex; + + public float TimeScale; + + public bool IsPlaying; + + public SkeletonPose Pose => _pose; + public static void DisposeComponent(void* component) { Self* animationComponent = (Self*)component; animationComponent._animationClip?.ReleaseRef(); + delete animationComponent._pose; } } } diff --git a/Sandbox/src/SandboxApp.bf b/Sandbox/src/SandboxApp.bf index c5bb686..edfa4f3 100644 --- a/Sandbox/src/SandboxApp.bf +++ b/Sandbox/src/SandboxApp.bf @@ -222,7 +222,6 @@ namespace Sandbox Skeleton Skeleton; List Clips ~ delete _; - AnimationPlayer AnimationPlayer ~ delete _; Material animationMat; mixin UnloadModelTest() @@ -267,14 +266,14 @@ namespace Sandbox materialTestMaterial.ReleaseRef(); testEffect.ReleaseRef(); - if(Clips != null && Clips.Count > 0) - AnimationPlayer = new AnimationPlayer(Skeleton, Clips.Back); - for(var (entity, transform, mesh, meshRenderer) in _world.Enumerate()) { var animation = _world.AssignComponent(entity); animation.AnimationClip = Clips[0]; + animation.TimeScale = 1.0f; + animation.IsPlaying = true; + animation.[Friend]_pose = new SkeletonPose(meshRenderer.Skeleton); } /* @@ -417,65 +416,92 @@ namespace Sandbox { var material = meshRenderer.Material; - //var testEffect = Application.Get().EffectLibrary.Get("testShader"); + var timeIndex = ref animation.TimeIndex; + var currentClip = animation.AnimationClip; + var pose = animation.Pose; - if(AnimationPlayer == null) + // Only advance time index if animation is playing + if(animation.IsPlaying) { - AnimationPlayer = new AnimationPlayer(meshRenderer.Skeleton, Clips[0]); + timeIndex += (float)gameTime.FrameTime.TotalSeconds * animation.TimeScale; + + if(currentClip.IsLooping && currentClip.Duration != 0) + { + timeIndex %= currentClip.Duration; + + // modulo can result in negative numbers + if(timeIndex < 0) + timeIndex += currentClip.Duration; + } } - if(AnimationPlayer != null) + // Update joints + for(int i < Skeleton.Joints.Count) { - if(playAnimation) - AnimationPlayer.Update(gameTime); + ref JointPose localPose = ref pose.LocalPose[i]; + + localPose = currentClip.JointAnimations[i].GetCurrentPose(timeIndex); + + Matrix jointToParent = + Matrix.Translation(localPose.Translation) * + Matrix.RotationQuaternion(localPose.Rotation) * + Matrix.Scaling(localPose.Scale); + + uint8 parentIndex = Skeleton.Joints[i].ParentID; + + ref Matrix globalPose = ref pose.GlobalPose[i]; + + if(parentIndex == uint8.MaxValue) + { + globalPose = jointToParent; + } else { - GameTime gt = new GameTime(); - AnimationPlayer.Update(gt); - delete gt; + globalPose = pose.GlobalPose[parentIndex] * jointToParent; } - //_context.SetRasterizerState(_rasterizerStateClockWise); - - int i = 0; - for(var globalPose in AnimationPlayer.Pose.GlobalPose) - { - Joint currentJoint = AnimationPlayer.Skeleton.Joints[i]; - - Matrix bindPose = currentJoint.InverseBindPose.Invert(); - - // Draw skeleton - Matrix mat = AnimationPlayer.SkinningMatricies[i] * bindPose; - - uint8 parentId = currentJoint.ParentID; - - if(parentId != uint8.MaxValue) - { - Vector3 start = mat.Translation; - - Joint parent = AnimationPlayer.Skeleton.Joints[parentId]; - - Matrix parentBindPose = parent.InverseBindPose.Invert(); - - Matrix parentMatrix = AnimationPlayer.SkinningMatricies[parentId] * parentBindPose; - - Vector3 end = parentMatrix.Translation; - - Renderer.DrawLine(start, end, .Black, transform.WorldTransform); - } - - DebugRenderer.DrawCoordinateCross(transform.WorldTransform * mat, 2.0f); - - i++; - } - - material.SetVariable("SkinningMatrices", AnimationPlayer.SkinningMatricies); - material.SetVariable("InvTransSkinningMatrices", AnimationPlayer.InvTransSkinningMatricies); - - // TODO: non engine - material.SetVariable("BaseColor", Color.White); - material.SetVariable("LightDir", Vector3(1, 1, -0.5f).Normalized()); + pose.SkinningMatricies[i] = globalPose * Skeleton.Joints[i].InverseBindPose; + pose.InvTransSkinningMatricies[i] = ((Matrix3x3)pose.SkinningMatricies[i]).Inverse().Transpose(); } + + int i = 0; + for(var globalPose in pose.GlobalPose) + { + Joint currentJoint = meshRenderer.Skeleton.Joints[i]; + + Matrix bindPose = currentJoint.InverseBindPose.Invert(); + + // Draw skeleton + Matrix mat = pose.SkinningMatricies[i] * bindPose; + + uint8 parentId = currentJoint.ParentID; + + if(parentId != uint8.MaxValue) + { + Vector3 start = mat.Translation; + + Joint parent = meshRenderer.Skeleton.Joints[parentId]; + + Matrix parentBindPose = parent.InverseBindPose.Invert(); + + Matrix parentMatrix = pose.SkinningMatricies[parentId] * parentBindPose; + + Vector3 end = parentMatrix.Translation; + + Renderer.DrawLine(start, end, .Black, transform.WorldTransform); + } + + DebugRenderer.DrawCoordinateCross(transform.WorldTransform * mat, 0.5f); + + i++; + } + + material.SetVariable("SkinningMatrices", pose.SkinningMatricies); + material.SetVariable("InvTransSkinningMatrices", pose.InvTransSkinningMatricies); + + // non engine + material.SetVariable("BaseColor", Color.White); + material.SetVariable("LightDir", Vector3(1, 1, -0.5f).Normalized()); Renderer.Submit(mesh.Mesh, material, transform.WorldTransform); } @@ -515,7 +541,7 @@ namespace Sandbox private bool OnImGuiRender(ImGuiRenderEvent e) { ImGui.Begin("Animation"); - + /* if(AnimationPlayer != null) { ImGui.DragFloat("Timestamp", &AnimationPlayer.TimeStamp, 0.01f, -AnimationPlayer.CurrentClip.Duration, AnimationPlayer.CurrentClip.Duration); @@ -527,7 +553,7 @@ namespace Sandbox ImGui.Checkbox("Play", &playAnimation); } - + */ ImGui.End(); ImGui.Begin("Test");