From 51d334cb60fa8479ab06c46ec797765e0c5895ab Mon Sep 17 00:00:00 2001 From: 4sval Date: Fri, 6 Jan 2023 16:48:39 +0100 Subject: [PATCH] compute all bones transform --- .../Snooper/Models/Animations/Animation.cs | 31 ++++---- .../Snooper/Models/Animations/Skeleton.cs | 79 ++++++++++++------- FModel/Views/Snooper/Models/Socket.cs | 2 +- FModel/Views/Snooper/Renderer.cs | 4 +- FModel/Views/Snooper/SnimGui.cs | 6 +- 5 files changed, 72 insertions(+), 50 deletions(-) diff --git a/FModel/Views/Snooper/Models/Animations/Animation.cs b/FModel/Views/Snooper/Models/Animations/Animation.cs index fc540fc1..6cd4ee78 100644 --- a/FModel/Views/Snooper/Models/Animations/Animation.cs +++ b/FModel/Views/Snooper/Models/Animations/Animation.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Numerics; using CUE4Parse_Conversion.Animations; using CUE4Parse.UE4.Objects.Core.Math; @@ -10,17 +11,24 @@ public class Animation : IDisposable public float CurrentTime; public float DeltaTime; public CAnimSet CurrentAnimation; - public Matrix4x4[] FinalBonesMatrix; + public Transform[] FinalBonesMatrix; - public Animation(CAnimSet anim) + public Animation(CAnimSet anim, Dictionary nameToIndex, Dictionary indexToTransform) { CurrentTime = 0f; CurrentAnimation = anim; - FinalBonesMatrix = new Matrix4x4[anim.TrackBoneNames.Length]; + FinalBonesMatrix = new Transform[anim.TrackBoneNames.Length]; for (int i = 0; i < FinalBonesMatrix.Length; i++) { - FinalBonesMatrix[i] = Matrix4x4.Identity; + if (!nameToIndex.TryGetValue(anim.TrackBoneNames[i].Text, out var boneIndex) || + !indexToTransform.TryGetValue(boneIndex, out var boneTransform)) + { + boneTransform = Transform.Identity; + } + + FinalBonesMatrix[i] = Transform.Identity; + FinalBonesMatrix[i].Relation = boneTransform.Matrix; } } @@ -29,7 +37,7 @@ public class Animation : IDisposable DeltaTime = deltaTime; if (CurrentAnimation != null) { - CurrentTime = deltaTime; + // CurrentTime = deltaTime; CalculateBoneTransform(); } } @@ -43,17 +51,8 @@ public class Animation : IDisposable var bonePosition = FVector.ZeroVector; sequence.Tracks[boneIndex].GetBonePosition(CurrentTime, sequence.NumFrames, false, ref bonePosition, ref boneOrientation); - boneOrientation *= CurrentAnimation.BonePositions[boneIndex].Orientation; - bonePosition = boneOrientation.RotateVector(bonePosition); - bonePosition *= Constants.SCALE_DOWN_RATIO; - if (CurrentAnimation.TrackBoneNames[boneIndex].Text == "pelvis") - { - - } - - FinalBonesMatrix[boneIndex] = - Matrix4x4.CreateFromQuaternion(boneOrientation) * - Matrix4x4.CreateTranslation(bonePosition); + FinalBonesMatrix[boneIndex].Rotation = boneOrientation; + FinalBonesMatrix[boneIndex].Position = bonePosition * Constants.SCALE_DOWN_RATIO; } } diff --git a/FModel/Views/Snooper/Models/Animations/Skeleton.cs b/FModel/Views/Snooper/Models/Animations/Skeleton.cs index 2737c7e2..79932ac9 100644 --- a/FModel/Views/Snooper/Models/Animations/Skeleton.cs +++ b/FModel/Views/Snooper/Models/Animations/Skeleton.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using CUE4Parse_Conversion.Animations; using CUE4Parse.UE4.Assets.Exports.Animation; using CUE4Parse.UE4.Assets.Exports.SkeletalMesh; using CUE4Parse.UE4.Objects.UObject; @@ -9,59 +10,83 @@ namespace FModel.Views.Snooper.Models.Animations; public class Skeleton : IDisposable { - public readonly USkeleton RefSkel; + public readonly USkeleton UnrealSkeleton; + public readonly Dictionary BonesIndexByName; + public readonly Dictionary BonesTransformByIndex; public readonly bool IsLoaded; + public readonly Socket[] Sockets; public Animation Anim; public Skeleton(FPackageIndex package) { - RefSkel = package.Load(); - if (RefSkel == null) return; + UnrealSkeleton = package.Load(); + if (UnrealSkeleton == null) return; + BonesIndexByName = UnrealSkeleton.ReferenceSkeleton.FinalNameToIndexMap; + BonesTransformByIndex = new Dictionary(); + foreach ((_, int boneIndex) in BonesIndexByName) + { + var transforms = new List(); + var parentBoneIndex = boneIndex; + while (parentBoneIndex > -1) + { + var parentFound = BonesTransformByIndex.TryGetValue(parentBoneIndex, out var boneTransform); + if (!parentFound) + { + var bone = UnrealSkeleton.ReferenceSkeleton.FinalRefBonePose[parentBoneIndex]; + boneTransform = new Transform + { + Rotation = bone.Rotation, + Position = bone.Translation * Constants.SCALE_DOWN_RATIO, + Scale = bone.Scale3D + }; + } + + parentBoneIndex = UnrealSkeleton.ReferenceSkeleton.FinalRefBoneInfo[parentBoneIndex].ParentIndex; + transforms.Add(boneTransform); + if (parentFound) parentBoneIndex = -1; // the parent transform is already relative to all its parent so we can just skip + } + + for (int j = transforms.Count - 2; j > -1; j--) + { + transforms[j].Relation *= transforms[j + 1].Matrix; + } + + BonesTransformByIndex[boneIndex] = transforms[0]; + transforms.Clear(); + } IsLoaded = true; - Sockets = new Socket[RefSkel.Sockets.Length]; + + Sockets = new Socket[UnrealSkeleton.Sockets.Length]; for (int i = 0; i < Sockets.Length; i++) { - if (RefSkel.Sockets[i].Load() is not { } socket) continue; + if (UnrealSkeleton.Sockets[i].Load() is not { } socket) continue; - if (!RefSkel.ReferenceSkeleton.FinalNameToIndexMap.TryGetValue(socket.BoneName.Text, out var boneIndex)) + if (!BonesIndexByName.TryGetValue(socket.BoneName.Text, out var boneIndex) || + !BonesTransformByIndex.TryGetValue(boneIndex, out var boneTransform)) { Sockets[i] = new Socket(socket); } else { - var transforms = new List(); - while (boneIndex > -1) - { - var bone = RefSkel.ReferenceSkeleton.FinalRefBonePose[boneIndex]; - boneIndex = RefSkel.ReferenceSkeleton.FinalRefBoneInfo[boneIndex].ParentIndex; - - transforms.Add(new Transform - { - Rotation = bone.Rotation, - Position = bone.Translation * Constants.SCALE_DOWN_RATIO, - Scale = bone.Scale3D - }); - } - - for (int j = transforms.Count - 2; j > -1; j--) - { - transforms[j].Relation *= transforms[j + 1].Matrix; - } - - Sockets[i] = new Socket(socket, transforms[0]); + Sockets[i] = new Socket(socket, boneTransform); } } } + public void SetAnimation(CAnimSet anim) + { + Anim = new Animation(anim, BonesIndexByName, BonesTransformByIndex); + } + public void SetUniform(Shader shader) { if (!IsLoaded) return; for (var i = 0; i < Anim?.FinalBonesMatrix.Length; i++) { - shader.SetUniform($"uFinalBonesMatrix[{i}]", Anim.FinalBonesMatrix[i]); + shader.SetUniform($"uFinalBonesMatrix[{i}]", Anim.FinalBonesMatrix[i].Matrix); } } diff --git a/FModel/Views/Snooper/Models/Socket.cs b/FModel/Views/Snooper/Models/Socket.cs index f65b5134..9b6b3022 100644 --- a/FModel/Views/Snooper/Models/Socket.cs +++ b/FModel/Views/Snooper/Models/Socket.cs @@ -23,7 +23,7 @@ public class Socket : IDisposable { Name = socket.SocketName.Text; Bone = socket.BoneName.Text; - Transform = transform; + Transform = Transform.Identity; Transform.Relation = transform.Matrix; Transform.Rotation = socket.RelativeRotation.Quaternion(); Transform.Position = socket.RelativeLocation * Constants.SCALE_DOWN_RATIO; diff --git a/FModel/Views/Snooper/Renderer.cs b/FModel/Views/Snooper/Renderer.cs index 016054c2..c23d2e3f 100644 --- a/FModel/Views/Snooper/Renderer.cs +++ b/FModel/Views/Snooper/Renderer.cs @@ -89,10 +89,10 @@ public class Renderer : IDisposable public void Animate(UAnimSequence animSequence) { if (!Options.TryGetModel(out var model) || !model.Skeleton.IsLoaded || - model.Skeleton?.RefSkel.ConvertAnims(animSequence) is not { } anim || anim.Sequences.Count == 0) + model.Skeleton?.UnrealSkeleton.ConvertAnims(animSequence) is not { } anim || anim.Sequences.Count == 0) return; - model.Skeleton.Anim = new Animation(anim); + model.Skeleton.SetAnimation(anim); Options.AnimateMesh(false); } diff --git a/FModel/Views/Snooper/SnimGui.cs b/FModel/Views/Snooper/SnimGui.cs index 7845fa9e..4193ee76 100644 --- a/FModel/Views/Snooper/SnimGui.cs +++ b/FModel/Views/Snooper/SnimGui.cs @@ -338,7 +338,6 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio _saver.Value = model.TrySave(out _saver.Label, out _saver.Path); s.WindowShouldFreeze(false); } - ImGui.BeginDisabled(true); // ImGui.BeginDisabled(!model.HasSkeleton); if (ImGui.Selectable("Animate")) @@ -346,7 +345,6 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio s.Renderer.Options.AnimateMesh(true); s.WindowShouldClose(true, false); } - ImGui.EndDisabled(); if (ImGui.Selectable("Teleport To")) { @@ -432,8 +430,8 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio Layout("Guid");ImGui.Text($" : {s.Renderer.Options.SelectedModel.ToString(EGuidFormats.UniqueObjectGuid)}"); if (model.HasSkeleton) { - Layout("Skeleton");ImGui.Text($" : {model.Skeleton.RefSkel.Name}"); - Layout("Bones");ImGui.Text($" : x{model.Skeleton.RefSkel.BoneTree.Length}"); + Layout("Skeleton");ImGui.Text($" : {model.Skeleton.UnrealSkeleton.Name}"); + Layout("Bones");ImGui.Text($" : x{model.Skeleton.UnrealSkeleton.BoneTree.Length}"); Layout("Sockets");ImGui.Text($" : x{model.Skeleton.Sockets.Length}"); } else