From a636c1ff84fb80963d696e518d0bbca417a24a39 Mon Sep 17 00:00:00 2001 From: 4sval Date: Sun, 5 Feb 2023 01:03:50 +0100 Subject: [PATCH] play anim at the right pace + fixed outliner --- FModel/Resources/outline.vert | 9 ++-- .../Snooper/Models/Animations/Animation.cs | 41 +++++++++++----- .../Snooper/Models/Animations/Skeleton.cs | 48 +++++++++---------- FModel/Views/Snooper/Models/Model.cs | 48 ++++++++----------- FModel/Views/Snooper/Models/Socket.cs | 12 +---- FModel/Views/Snooper/Renderer.cs | 6 +-- FModel/Views/Snooper/SnimGui.cs | 6 --- FModel/Views/Snooper/Snooper.cs | 6 ++- 8 files changed, 85 insertions(+), 91 deletions(-) diff --git a/FModel/Resources/outline.vert b/FModel/Resources/outline.vert index 645441b7..ec0811cb 100644 --- a/FModel/Resources/outline.vert +++ b/FModel/Resources/outline.vert @@ -32,10 +32,9 @@ void main() finalNormal += boneMatrix * bindNormal * weight; } - vec3 pos = vec3(vInstanceMatrix * finalPos); - vec3 nor = vec3(transpose(inverse(vInstanceMatrix)) * finalNormal); + float scaleFactor = distance(vec3(finalPos), uViewPos) * 0.0025; + vec4 nor = transpose(inverse(vInstanceMatrix)) * finalNormal * scaleFactor; + finalPos.xyz += nor.xyz; - float scaleFactor = distance(pos, uViewPos) * 0.0025; - vec3 scaleVertex = pos + nor * scaleFactor; - gl_Position = uProjection * uView * vec4(scaleVertex, 1.0); + gl_Position = uProjection * uView * vInstanceMatrix * finalPos; } diff --git a/FModel/Views/Snooper/Models/Animations/Animation.cs b/FModel/Views/Snooper/Models/Animations/Animation.cs index 3afb06dc..9efc953a 100644 --- a/FModel/Views/Snooper/Models/Animations/Animation.cs +++ b/FModel/Views/Snooper/Models/Animations/Animation.cs @@ -1,44 +1,53 @@ using System; +using System.Collections.Generic; using System.Numerics; using CUE4Parse_Conversion.Animations; -using CUE4Parse.UE4.Objects.Core.Math; +using CUE4Parse.Utils; namespace FModel.Views.Snooper.Models.Animations; public class Animation : IDisposable { - public int CurrentTime; - public readonly int MaxTime; + public int Frame; + public float ElapsedTime; + public readonly int MaxFrame; + public readonly float FramesPerSecond; + public readonly Dictionary TrackIndexByBoneIndex; public readonly Transform[][] BoneTransforms; + public float TimePerFrame => 1.0f / FramesPerSecond; + public Animation(Skeleton skeleton, CAnimSet anim) { - CurrentTime = 0; + Frame = 0; + ElapsedTime = 0; + TrackIndexByBoneIndex = new Dictionary(); var sequence = anim.Sequences[0]; - MaxTime = sequence.NumFrames - 1; + MaxFrame = sequence.NumFrames; + FramesPerSecond = sequence.Rate; + BoneTransforms = new Transform[skeleton.UnrealSkeleton.ReferenceSkeleton.FinalRefBoneInfo.Length][]; for (var trackIndex = 0; trackIndex < BoneTransforms.Length; trackIndex++) { + BoneTransforms[trackIndex] = new Transform[MaxFrame]; + var bone = skeleton.UnrealSkeleton.ReferenceSkeleton.FinalRefBoneInfo[trackIndex]; if (!skeleton.BonesIndexByLoweredName.TryGetValue(bone.Name.Text.ToLower(), out var boneIndex)) - { - BoneTransforms[trackIndex] = new Transform[sequence.NumFrames]; continue; - } if (!skeleton.BonesTransformByIndex.TryGetValue(boneIndex, out var originalTransform)) throw new ArgumentNullException($"no transform for bone '{boneIndex}'"); + TrackIndexByBoneIndex[boneIndex] = trackIndex; var boneOrientation = originalTransform.Rotation; var bonePosition = originalTransform.Position; var boneScale = originalTransform.Scale; - BoneTransforms[trackIndex] = new Transform[sequence.NumFrames]; for (var frame = 0; frame < BoneTransforms[trackIndex].Length; frame++) { - sequence.Tracks[trackIndex].GetBonePosition(frame, sequence.NumFrames, false, ref bonePosition, ref boneOrientation); - if (CurrentTime < sequence.Tracks[trackIndex].KeyScale.Length) - boneScale = sequence.Tracks[trackIndex].KeyScale[CurrentTime]; + sequence.Tracks[trackIndex].GetBonePosition(frame, MaxFrame, false, ref bonePosition, ref boneOrientation); + if (frame < sequence.Tracks[trackIndex].KeyScale.Length) + boneScale = sequence.Tracks[trackIndex].KeyScale[frame]; // revert FixRotationKeys if (trackIndex > 0) boneOrientation.Conjugate(); @@ -56,8 +65,14 @@ public Animation(Skeleton skeleton, CAnimSet anim) } } - public void Dispose() + public Matrix4x4 InterpolateBoneTransform(int trackIndex) { + Frame = ElapsedTime.FloorToInt() % MaxFrame; // interpolate here + return BoneTransforms[trackIndex][Frame].Matrix; + } + public void Dispose() + { + TrackIndexByBoneIndex.Clear(); } } diff --git a/FModel/Views/Snooper/Models/Animations/Skeleton.cs b/FModel/Views/Snooper/Models/Animations/Skeleton.cs index 689a2bcf..e37df2cf 100644 --- a/FModel/Views/Snooper/Models/Animations/Skeleton.cs +++ b/FModel/Views/Snooper/Models/Animations/Skeleton.cs @@ -26,7 +26,7 @@ public Skeleton() InvertedBonesMatrixByIndex = new Dictionary(); } - public Skeleton(FPackageIndex package, FReferenceSkeleton referenceSkeleton, Transform transform) : this() + public Skeleton(FPackageIndex package, FReferenceSkeleton referenceSkeleton) : this() { UnrealSkeleton = package.Load(); IsLoaded = UnrealSkeleton != null; @@ -36,17 +36,6 @@ public Skeleton(FPackageIndex package, FReferenceSkeleton referenceSkeleton, Tra foreach ((var name, var boneIndex) in referenceSkeleton.FinalNameToIndexMap) BonesIndexByLoweredName[name.ToLower()] = boneIndex; - UpdateBoneMatrices(transform.Matrix); - } - - public void SetAnimation(CAnimSet anim) - { - Anim = new Animation(this, anim); - } - - public void UpdateBoneMatrices(Matrix4x4 matrix) - { - if (!IsLoaded) return; foreach (var boneIndex in BonesIndexByLoweredName.Values) { var bone = ReferenceSkeleton.FinalRefBonePose[boneIndex]; @@ -63,7 +52,7 @@ public void UpdateBoneMatrices(Matrix4x4 matrix) } if (!BonesTransformByIndex.TryGetValue(parentIndex, out var parentTransform)) - parentTransform = new Transform { Relation = matrix }; + parentTransform = new Transform { Relation = Matrix4x4.Identity }; boneTransform.Relation = parentTransform.Matrix; Matrix4x4.Invert(boneTransform.Matrix, out var inverted); @@ -73,31 +62,40 @@ public void UpdateBoneMatrices(Matrix4x4 matrix) } } + public void SetAnimation(CAnimSet anim) + { + Anim = new Animation(this, anim); + } + public void SetPoseUniform(Shader shader) { if (!IsLoaded) return; - foreach ((var boneIndex, var transform) in BonesTransformByIndex) + foreach (var boneIndex in BonesTransformByIndex.Keys) { if (boneIndex >= Constants.MAX_BONE_UNIFORM) break; - shader.SetUniform($"uFinalBonesMatrix[{boneIndex}]", InvertedBonesMatrixByIndex[boneIndex] * transform.Matrix); + shader.SetUniform($"uFinalBonesMatrix[{boneIndex}]", Matrix4x4.Identity); } } - public void SetUniform(Shader shader) + public void SetUniform(float deltaSeconds, bool outline, Shader shader) { if (!IsLoaded) return; if (Anim == null) SetPoseUniform(shader); - else foreach ((var boneName, var trackIndex) in UnrealSkeleton.ReferenceSkeleton.FinalNameToIndexMap) + else { - if (!BonesIndexByLoweredName.TryGetValue(boneName.ToLower(), out var boneIndex)) - continue; - if (!InvertedBonesMatrixByIndex.TryGetValue(boneIndex, out var invertMatrix)) - throw new ArgumentNullException($"no inverse matrix for bone '{boneIndex}'"); - if (boneIndex >= Constants.MAX_BONE_UNIFORM) - break; - - shader.SetUniform($"uFinalBonesMatrix[{boneIndex}]", invertMatrix * Anim.BoneTransforms[trackIndex][Anim.CurrentTime].Matrix); + if (!outline) Anim.ElapsedTime += deltaSeconds / Anim.TimePerFrame; + foreach ((var boneName, var trackIndex) in UnrealSkeleton.ReferenceSkeleton.FinalNameToIndexMap) + { + if (!BonesIndexByLoweredName.TryGetValue(boneName.ToLower(), out var boneIndex)) + continue; + if (!InvertedBonesMatrixByIndex.TryGetValue(boneIndex, out var invertMatrix)) + throw new ArgumentNullException($"no inverse matrix for bone '{boneIndex}'"); + if (boneIndex >= Constants.MAX_BONE_UNIFORM) + break; + + shader.SetUniform($"uFinalBonesMatrix[{boneIndex}]", invertMatrix * Anim.InterpolateBoneTransform(trackIndex)); + } } } diff --git a/FModel/Views/Snooper/Models/Model.cs b/FModel/Views/Snooper/Models/Model.cs index 94f760eb..50e3fd3e 100644 --- a/FModel/Views/Snooper/Models/Model.cs +++ b/FModel/Views/Snooper/Models/Model.cs @@ -129,16 +129,15 @@ public Model(UStaticMesh export, CStaticMesh staticMesh, Transform transform) : for (int i = 0; i < Sockets.Length; i++) { if (export.Sockets[i].Load() is not { } socket) continue; - Sockets[i] = new Socket(socket, Transforms[0]); + Sockets[i] = new Socket(socket); } } public Model(USkeletalMesh export, CSkeletalMesh skeletalMesh) : this(export, skeletalMesh, Transform.Identity) {} private Model(USkeletalMesh export, CSkeletalMesh skeletalMesh, Transform transform) : this(export, export.Materials, skeletalMesh.LODs, transform) { - var t = Transforms[0]; Box = skeletalMesh.BoundingBox * Constants.SCALE_DOWN_RATIO; - Skeleton = new Skeleton(export.Skeleton, export.ReferenceSkeleton, t); + Skeleton = new Skeleton(export.Skeleton, export.ReferenceSkeleton); var sockets = new List(); sockets.AddRange(export.Sockets); @@ -148,12 +147,7 @@ private Model(USkeletalMesh export, CSkeletalMesh skeletalMesh, Transform transf for (int i = 0; i < Sockets.Length; i++) { if (sockets[i].Load() is not { } socket) continue; - - if (!Skeleton.BonesIndexByLoweredName.TryGetValue(socket.BoneName.Text, out var boneIndex) || - !Skeleton.BonesTransformByIndex.TryGetValue(boneIndex, out var boneTransform)) - boneTransform = t; - - Sockets[i] = new Socket(socket, boneTransform); + Sockets[i] = new Socket(socket); } Morphs = new Morph[export.MorphTargets.Length]; @@ -254,40 +248,40 @@ public void AddInstance(Transform transform) public void UpdateMatrices(Options options) { - UpdateMatrices(); + var worldMatrix = UpdateMatrices(); foreach (var socket in Sockets) { + var boneMatrix = Matrix4x4.Identity; + if (HasSkeleton && Skeleton.BonesIndexByLoweredName.TryGetValue(socket.BoneName.Text.ToLower(), out var boneIndex)) + { + if (Skeleton.Anim?.TrackIndexByBoneIndex.TryGetValue(boneIndex, out var trackIndex) ?? false) + boneMatrix = Skeleton.Anim.InterpolateBoneTransform(trackIndex); + else if (Skeleton.BonesTransformByIndex.TryGetValue(boneIndex, out var boneTransform)) + boneMatrix = boneTransform.Matrix; + } + + var socketRelation = boneMatrix * worldMatrix; foreach (var attached in socket.AttachedModels) { if (!options.TryGetModel(attached, out var attachedModel)) continue; - attachedModel.Transforms[attachedModel.SelectedInstance].Relation = socket.Transform.Matrix; - attachedModel.UpdateMatrices(); + attachedModel.Transforms[attachedModel.SelectedInstance].Relation = socket.Transform.Matrix * socketRelation; + attachedModel.UpdateMatrices(options); } } } - private void UpdateMatrices() + private Matrix4x4 UpdateMatrices() { var matrix = Transforms[SelectedInstance].Matrix; - if (matrix == _previousMatrix) return; + if (matrix == _previousMatrix) return matrix; _matrixVbo.Bind(); _matrixVbo.Update(SelectedInstance, matrix); _matrixVbo.Unbind(); - if (HasSkeleton) Skeleton.UpdateBoneMatrices(matrix); - foreach (var socket in Sockets) - { - if (!HasSkeleton || - !Skeleton.BonesIndexByLoweredName.TryGetValue(socket.BoneName.Text, out var boneIndex) || - !Skeleton.BonesTransformByIndex.TryGetValue(boneIndex, out var boneTransform)) - boneTransform = Transforms[SelectedInstance]; - - socket.UpdateSocketMatrix(boneTransform.Matrix); - } - _previousMatrix = matrix; + return matrix; } public void UpdateMorph(int index) @@ -376,7 +370,7 @@ public void Setup(Options options) IsSetup = true; } - public void Render(Shader shader, bool outline = false) + public void Render(float deltaSeconds, Shader shader, bool outline = false) { if (outline) GL.Disable(EnableCap.DepthTest); if (TwoSided) GL.Disable(EnableCap.CullFace); @@ -388,7 +382,7 @@ public void Render(Shader shader, bool outline = false) _vao.Bind(); shader.SetUniform("uMorphTime", MorphTime); - if (HasSkeleton) Skeleton.SetUniform(shader); + if (HasSkeleton) Skeleton.SetUniform(deltaSeconds, outline, shader); if (!outline) { shader.SetUniform("uUvCount", UvCount); diff --git a/FModel/Views/Snooper/Models/Socket.cs b/FModel/Views/Snooper/Models/Socket.cs index 6a0db823..b9f6c1d0 100644 --- a/FModel/Views/Snooper/Models/Socket.cs +++ b/FModel/Views/Snooper/Models/Socket.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Numerics; using CUE4Parse.UE4.Assets.Exports.SkeletalMesh; using CUE4Parse.UE4.Assets.Exports.StaticMesh; using CUE4Parse.UE4.Objects.Core.Misc; @@ -22,30 +21,23 @@ private Socket() AttachedModels = new List(); } - public Socket(UStaticMeshSocket socket, Transform transform) : this() + public Socket(UStaticMeshSocket socket) : this() { Name = socket.SocketName.Text; - Transform.Relation = transform.Matrix; Transform.Rotation = socket.RelativeRotation.Quaternion(); Transform.Position = socket.RelativeLocation * Constants.SCALE_DOWN_RATIO; Transform.Scale = socket.RelativeScale; } - public Socket(USkeletalMeshSocket socket, Transform transform) : this() + public Socket(USkeletalMeshSocket socket) : this() { Name = socket.SocketName.Text; BoneName = socket.BoneName; - Transform.Relation = transform.Matrix; Transform.Rotation = socket.RelativeRotation.Quaternion(); Transform.Position = socket.RelativeLocation * Constants.SCALE_DOWN_RATIO; Transform.Scale = socket.RelativeScale; } - public void UpdateSocketMatrix(Matrix4x4 matrix) - { - Transform.Relation = matrix; - } - public void Dispose() { AttachedModels.Clear(); diff --git a/FModel/Views/Snooper/Renderer.cs b/FModel/Views/Snooper/Renderer.cs index f1019c59..9e5b4aaa 100644 --- a/FModel/Views/Snooper/Renderer.cs +++ b/FModel/Views/Snooper/Renderer.cs @@ -110,7 +110,7 @@ public void Setup() Options.SetupModelsAndLights(); } - public void Render() + public void Render(float deltaSeconds) { var viewMatrix = CameraOp.GetViewMatrix(); var projMatrix = CameraOp.GetProjectionMatrix(); @@ -127,7 +127,7 @@ public void Render() { model.UpdateMatrices(Options); if (!model.Show) continue; - model.Render(_shader); + model.Render(deltaSeconds, _shader); } { // light pass @@ -147,7 +147,7 @@ public void Render() if (Options.TryGetModel(out var selected) && selected.Show) { _outline.Render(viewMatrix, CameraOp.Position, projMatrix); - selected.Render(_outline, true); + selected.Render(deltaSeconds, _outline, true); } // picking pass (dedicated FBO, binding to 0 afterward) diff --git a/FModel/Views/Snooper/SnimGui.cs b/FModel/Views/Snooper/SnimGui.cs index fa4b2960..7bca4ab6 100644 --- a/FModel/Views/Snooper/SnimGui.cs +++ b/FModel/Views/Snooper/SnimGui.cs @@ -446,12 +446,6 @@ private void DrawDetails(Snooper s) Layout("Guid");ImGui.Text($" : {s.Renderer.Options.SelectedModel.ToString(EGuidFormats.UniqueObjectGuid)}"); if (model.HasSkeleton) { - if (model.Skeleton.Anim != null) - { - ImGui.BeginDisabled(model.Skeleton.Anim.MaxTime == 0); - ImGui.DragInt("Time", ref model.Skeleton.Anim.CurrentTime, 1, 0, model.Skeleton.Anim.MaxTime); - ImGui.EndDisabled(); - } Layout("Skeleton");ImGui.Text($" : {model.Skeleton.UnrealSkeleton.Name}"); Layout("Bones");ImGui.Text($" : x{model.Skeleton.UnrealSkeleton.BoneTree.Length}"); } diff --git a/FModel/Views/Snooper/Snooper.cs b/FModel/Views/Snooper/Snooper.cs index 33c742ba..e812f226 100644 --- a/FModel/Views/Snooper/Snooper.cs +++ b/FModel/Views/Snooper/Snooper.cs @@ -116,14 +116,16 @@ protected override void OnRenderFrame(FrameEventArgs args) if (!IsVisible) return; + var delta = (float) args.Time; + ClearWhatHasBeenDrawn(); // clear window background - _gui.Controller.Update(this, (float)args.Time); + _gui.Controller.Update(this, delta); _gui.Render(this); Framebuffer.Bind(); // switch to viewport background ClearWhatHasBeenDrawn(); // clear viewport background - Renderer.Render(); + Renderer.Render(delta); Framebuffer.BindMsaa(); Framebuffer.Bind(0); // switch to window background