Skip to content

Commit

Permalink
compute all bones transform
Browse files Browse the repository at this point in the history
  • Loading branch information
4sval committed Jan 6, 2023
1 parent 0221405 commit 51d334c
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 49 deletions.
31 changes: 15 additions & 16 deletions FModel/Views/Snooper/Models/Animations/Animation.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Numerics;
using CUE4Parse_Conversion.Animations;
using CUE4Parse.UE4.Objects.Core.Math;
Expand All @@ -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<string, int> nameToIndex, Dictionary<int, Transform> 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;
}
}

Expand All @@ -29,7 +37,7 @@ public void UpdateAnimation(float deltaTime)
DeltaTime = deltaTime;
if (CurrentAnimation != null)
{
CurrentTime = deltaTime;
// CurrentTime = deltaTime;
CalculateBoneTransform();
}
}
Expand All @@ -43,17 +51,8 @@ public void CalculateBoneTransform()
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;
}
}

Expand Down
77 changes: 51 additions & 26 deletions FModel/Views/Snooper/Models/Animations/Skeleton.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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<string, int> BonesIndexByName;
public readonly Dictionary<int, Transform> BonesTransformByIndex;
public readonly bool IsLoaded;

public readonly Socket[] Sockets;

public Animation Anim;

public Skeleton(FPackageIndex package)
{
RefSkel = package.Load<USkeleton>();
if (RefSkel == null) return;
UnrealSkeleton = package.Load<USkeleton>();
if (UnrealSkeleton == null) return;

IsLoaded = true;
Sockets = new Socket[RefSkel.Sockets.Length];
for (int i = 0; i < Sockets.Length; i++)
BonesIndexByName = UnrealSkeleton.ReferenceSkeleton.FinalNameToIndexMap;
BonesTransformByIndex = new Dictionary<int, Transform>();
foreach ((_, int boneIndex) in BonesIndexByName)
{
if (RefSkel.Sockets[i].Load<USkeletalMeshSocket>() is not { } socket) continue;

if (!RefSkel.ReferenceSkeleton.FinalNameToIndexMap.TryGetValue(socket.BoneName.Text, out var boneIndex))
{
Sockets[i] = new Socket(socket);
}
else
var transforms = new List<Transform>();
var parentBoneIndex = boneIndex;
while (parentBoneIndex > -1)
{
var transforms = new List<Transform>();
while (boneIndex > -1)
var parentFound = BonesTransformByIndex.TryGetValue(parentBoneIndex, out var boneTransform);
if (!parentFound)
{
var bone = RefSkel.ReferenceSkeleton.FinalRefBonePose[boneIndex];
boneIndex = RefSkel.ReferenceSkeleton.FinalRefBoneInfo[boneIndex].ParentIndex;

transforms.Add(new Transform
var bone = UnrealSkeleton.ReferenceSkeleton.FinalRefBonePose[parentBoneIndex];
boneTransform = 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;
}
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
}

Sockets[i] = new Socket(socket, transforms[0]);
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[UnrealSkeleton.Sockets.Length];
for (int i = 0; i < Sockets.Length; i++)
{
if (UnrealSkeleton.Sockets[i].Load<USkeletalMeshSocket>() is not { } socket) continue;

if (!BonesIndexByName.TryGetValue(socket.BoneName.Text, out var boneIndex) ||
!BonesTransformByIndex.TryGetValue(boneIndex, out var boneTransform))
{
Sockets[i] = new Socket(socket);
}
else
{
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);
}
}

Expand Down
2 changes: 1 addition & 1 deletion FModel/Views/Snooper/Models/Socket.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public Socket(USkeletalMeshSocket socket, Transform transform)
{
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;
Expand Down
4 changes: 2 additions & 2 deletions FModel/Views/Snooper/Renderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,10 @@ public void Swap(UMaterialInstance unrealMaterial)
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);
}

Expand Down
6 changes: 2 additions & 4 deletions FModel/Views/Snooper/SnimGui.cs
Original file line number Diff line number Diff line change
Expand Up @@ -338,15 +338,13 @@ private void DrawOuliner(Snooper s)
_saver.Value = model.TrySave(out _saver.Label, out _saver.Path);
s.WindowShouldFreeze(false);
}
ImGui.BeginDisabled(true);
// ImGui.BeginDisabled(!model.HasSkeleton);
if (ImGui.Selectable("Animate"))
{
s.Renderer.Options.AnimateMesh(true);
s.WindowShouldClose(true, false);
}
ImGui.EndDisabled();
if (ImGui.Selectable("Teleport To"))
{
Expand Down Expand Up @@ -432,8 +430,8 @@ private void DrawDetails(Snooper s)
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
Expand Down

0 comments on commit 51d334c

Please sign in to comment.