diff --git a/FModel/Views/Snooper/Animations/Animation.cs b/FModel/Views/Snooper/Animations/Animation.cs index af4e7d0c..dc9204de 100644 --- a/FModel/Views/Snooper/Animations/Animation.cs +++ b/FModel/Views/Snooper/Animations/Animation.cs @@ -24,6 +24,8 @@ public class Animation : IDisposable public int CurrentSequence; public int FrameInSequence; // Current Sequence's Frame to Display + public int NextFrameInSequence; + public float LerpAmount; public string Label => $"Retarget: {TargetSkeleton}\nSequences: {CurrentSequence + 1}/{Sequences.Length}\nFrames: {FrameInSequence}/{Sequences[CurrentSequence].EndFrame}"; @@ -80,12 +82,17 @@ public class Animation : IDisposable for (int s = 0; s < CurrentSequence; s++) lastEndTime = Sequences[s].EndTime; - FrameInSequence = Math.Min(((elapsedTime - lastEndTime) / Sequences[CurrentSequence].TimePerFrame).FloorToInt(), Sequences[CurrentSequence].EndFrame); + var exactFrameAtThisTime = (elapsedTime - lastEndTime) / Sequences[CurrentSequence].TimePerFrame; + FrameInSequence = Math.Min(exactFrameAtThisTime.FloorToInt(), Sequences[CurrentSequence].EndFrame); + NextFrameInSequence = Math.Min(FrameInSequence + 1, Sequences[CurrentSequence].EndFrame); + LerpAmount = Math.Clamp(exactFrameAtThisTime - FrameInSequence, 0, 1); } private void Reset() { FrameInSequence = 0; + NextFrameInSequence = 0; + LerpAmount = 0.0f; CurrentSequence = 0; } diff --git a/FModel/Views/Snooper/Animations/Skeleton.cs b/FModel/Views/Snooper/Animations/Skeleton.cs index d79b99f5..a1914d62 100644 --- a/FModel/Views/Snooper/Animations/Skeleton.cs +++ b/FModel/Views/Snooper/Animations/Skeleton.cs @@ -18,8 +18,6 @@ public class Skeleton : IDisposable public string Name; public readonly Dictionary BonesByLoweredName; - private int _previousAnimationSequence; - private int _previousSequenceFrame; private Transform[][][] _animatedBonesTransform; // [sequence][bone][frame] private readonly Matrix4x4[] _invertedBonesMatrix; public int BoneCount => _invertedBonesMatrix.Length; @@ -210,26 +208,23 @@ public class Skeleton : IDisposable _ssbo.UpdateRange(BoneCount, Matrix4x4.Identity); } - public void UpdateAnimationMatrices(int currentSequence, int frameInSequence) + public void UpdateAnimationMatrices(int currentSequence, int frameInSequence, int nextFrameInSequence, float lerp) { if (!IsAnimated) return; - _previousAnimationSequence = currentSequence; - if (_previousSequenceFrame == frameInSequence) return; - _previousSequenceFrame = frameInSequence; - _ssbo.Bind(); - for (int boneIndex = 0; boneIndex < BoneCount; boneIndex++) // interpolate here - _ssbo.Update(boneIndex, _invertedBonesMatrix[boneIndex] * _animatedBonesTransform[_previousAnimationSequence][boneIndex][_previousSequenceFrame].Matrix); + for (int boneIndex = 0; boneIndex < BoneCount; boneIndex++) + { + var matrix = Matrix4x4.Lerp( + _animatedBonesTransform[currentSequence][boneIndex][frameInSequence].Matrix, + _animatedBonesTransform[currentSequence][boneIndex][nextFrameInSequence].Matrix, + lerp); + _ssbo.Update(boneIndex, _invertedBonesMatrix[boneIndex] * matrix); + } _ssbo.Unbind(); } - public Matrix4x4 GetBoneMatrix(Bone bone) - { - return IsAnimated - ? _animatedBonesTransform[_previousAnimationSequence][bone.Index][_previousSequenceFrame].Matrix - : bone.Rest.Matrix; - } + public Matrix4x4 GetBoneMatrix(Bone bone) => IsAnimated ? bone.Rest.Matrix * _ssbo.Get(bone.Index) : bone.Rest.Matrix; public void Render() { diff --git a/FModel/Views/Snooper/Buffers/BufferObject.cs b/FModel/Views/Snooper/Buffers/BufferObject.cs index 14e86931..db8810b5 100644 --- a/FModel/Views/Snooper/Buffers/BufferObject.cs +++ b/FModel/Views/Snooper/Buffers/BufferObject.cs @@ -43,6 +43,17 @@ public class BufferObject : IDisposable where TDataType : unmanaged GL.BufferSubData(_bufferTarget, IntPtr.Zero, data.Length * sizeof(TDataType), data); } + public unsafe TDataType Get(int offset) + { + TDataType data = default; + + Bind(); + GL.GetBufferSubData(_bufferTarget, (IntPtr) (offset * sizeof(TDataType)), sizeof(TDataType), ref data); + Unbind(); + + return data; + } + public void Bind() { GL.BindBuffer(_bufferTarget, _handle); diff --git a/FModel/Views/Snooper/Models/Model.cs b/FModel/Views/Snooper/Models/Model.cs index 1bbdf26e..a931ccfc 100644 --- a/FModel/Views/Snooper/Models/Model.cs +++ b/FModel/Views/Snooper/Models/Model.cs @@ -370,9 +370,17 @@ public class Model : IDisposable _vao.Unbind(); } - for (int section = 0; section < Sections.Length; section++) + if (options.Models.Count == 1 && Sections.All(x => !x.Show)) { - if (!Show) Show = Sections[section].Show; + Show = true; + foreach (var section in Sections) + { + section.Show = true; + } + } + else foreach (var section in Sections) + { + if (!Show) Show = section.Show; } IsSetup = true; diff --git a/FModel/Views/Snooper/Renderer.cs b/FModel/Views/Snooper/Renderer.cs index 4a401e7f..0d7fc426 100644 --- a/FModel/Views/Snooper/Renderer.cs +++ b/FModel/Views/Snooper/Renderer.cs @@ -234,7 +234,9 @@ public class Renderer : IDisposable animation.TimeCalculation(Options.Tracker.ElapsedTime); foreach (var guid in animation.AttachedModels.Where(guid => Options.Models[guid].HasSkeleton)) { - Options.Models[guid].Skeleton.UpdateAnimationMatrices(animation.CurrentSequence, animation.FrameInSequence); + Options.Models[guid].Skeleton.UpdateAnimationMatrices( + animation.CurrentSequence, animation.FrameInSequence, + animation.NextFrameInSequence, animation.LerpAmount); } }