Skip to content

Commit

Permalink
play anim at the right pace + fixed outliner
Browse files Browse the repository at this point in the history
  • Loading branch information
4sval committed Feb 5, 2023
1 parent f36a7b7 commit a636c1f
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 91 deletions.
9 changes: 4 additions & 5 deletions FModel/Resources/outline.vert
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
41 changes: 28 additions & 13 deletions FModel/Views/Snooper/Models/Animations/Animation.cs
Original file line number Diff line number Diff line change
@@ -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<int, int> 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<int, int>();

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();
Expand All @@ -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();
}
}
48 changes: 23 additions & 25 deletions FModel/Views/Snooper/Models/Animations/Skeleton.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public Skeleton()
InvertedBonesMatrixByIndex = new Dictionary<int, Matrix4x4>();
}

public Skeleton(FPackageIndex package, FReferenceSkeleton referenceSkeleton, Transform transform) : this()
public Skeleton(FPackageIndex package, FReferenceSkeleton referenceSkeleton) : this()
{
UnrealSkeleton = package.Load<USkeleton>();
IsLoaded = UnrealSkeleton != null;
Expand All @@ -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];
Expand All @@ -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);
Expand All @@ -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));
}
}
}

Expand Down
48 changes: 21 additions & 27 deletions FModel/Views/Snooper/Models/Model.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<UStaticMeshSocket>() 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<FPackageIndex>();
sockets.AddRange(export.Sockets);
Expand All @@ -148,12 +147,7 @@ private Model(USkeletalMesh export, CSkeletalMesh skeletalMesh, Transform transf
for (int i = 0; i < Sockets.Length; i++)
{
if (sockets[i].Load<USkeletalMeshSocket>() 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];
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down
12 changes: 2 additions & 10 deletions FModel/Views/Snooper/Models/Socket.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -22,30 +21,23 @@ private Socket()
AttachedModels = new List<FGuid>();
}

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();
Expand Down
6 changes: 3 additions & 3 deletions FModel/Views/Snooper/Renderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -127,7 +127,7 @@ public void Render()
{
model.UpdateMatrices(Options);
if (!model.Show) continue;
model.Render(_shader);
model.Render(deltaSeconds, _shader);
}

{ // light pass
Expand All @@ -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)
Expand Down
6 changes: 0 additions & 6 deletions FModel/Views/Snooper/SnimGui.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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}");
}
Expand Down
6 changes: 4 additions & 2 deletions FModel/Views/Snooper/Snooper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit a636c1f

Please sign in to comment.