Skip to content

Commit

Permalink
rotation only animation
Browse files Browse the repository at this point in the history
  • Loading branch information
4sval committed Feb 5, 2023
1 parent f288791 commit 0b7ed2c
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 64 deletions.
7 changes: 7 additions & 0 deletions FModel/Settings/UserSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,13 @@ public bool ShowGrid
set => SetProperty(ref _showGrid, value);
}

private bool _animateWithRotationOnly;
public bool AnimateWithRotationOnly
{
get => _animateWithRotationOnly;
set => SetProperty(ref _animateWithRotationOnly, value);
}

private Camera.WorldMode _cameraMode = Camera.WorldMode.Arcball;
public Camera.WorldMode CameraMode
{
Expand Down
30 changes: 22 additions & 8 deletions FModel/Views/Snooper/Models/Animations/Animation.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
using System;
using System;
using System.Collections.Generic;
using System.Numerics;
using CUE4Parse_Conversion.Animations;
using CUE4Parse.Utils;
using ImGuiNET;

namespace FModel.Views.Snooper.Models.Animations;

Expand All @@ -15,9 +16,9 @@ public class Animation : IDisposable
public readonly Dictionary<int, int> TrackIndexByBoneIndex;
public readonly Transform[][] BoneTransforms;

public float TimePerFrame => 1.0f / FramesPerSecond;
private float TimePerFrame => 1.0f / FramesPerSecond;

public Animation(Skeleton skeleton, CAnimSet anim)
public Animation(Skeleton skeleton, CAnimSet anim, bool rotationOnly)
{
Frame = 0;
ElapsedTime = 0;
Expand All @@ -39,12 +40,13 @@ public Animation(Skeleton skeleton, CAnimSet anim)
throw new ArgumentNullException($"no transform for bone '{boneIndex}'");

TrackIndexByBoneIndex[boneIndex] = trackIndex;
var boneOrientation = originalTransform.Rotation;
var bonePosition = originalTransform.Position;
var boneScale = originalTransform.Scale;

for (var frame = 0; frame < BoneTransforms[trackIndex].Length; frame++)
{
var boneOrientation = originalTransform.Rotation;
var bonePosition = originalTransform.Position;
var boneScale = originalTransform.Scale;

sequence.Tracks[trackIndex].GetBonePosition(frame, MaxFrame, false, ref bonePosition, ref boneOrientation);
if (frame < sequence.Tracks[trackIndex].KeyScale.Length)
boneScale = sequence.Tracks[trackIndex].KeyScale[frame];
Expand All @@ -70,19 +72,31 @@ public Animation(Skeleton skeleton, CAnimSet anim)
{
Relation = bone.ParentIndex >= 0 ? BoneTransforms[bone.ParentIndex][frame].Matrix : originalTransform.Relation,
Rotation = boneOrientation,
Position = bonePosition,
Position = rotationOnly ? originalTransform.Position : bonePosition,
Scale = boneScale
};
}
}
}

public void Update(float deltaSeconds)
{
ElapsedTime += deltaSeconds / TimePerFrame;
Frame = ElapsedTime.FloorToInt() % MaxFrame;
}

public Matrix4x4 InterpolateBoneTransform(int trackIndex)
{
Frame = ElapsedTime.FloorToInt() % MaxFrame; // interpolate here
// interpolate here
return BoneTransforms[trackIndex][Frame].Matrix;
}

public void ImGuiTimeline()
{
ImGui.Text($"Frame: {Frame}/{MaxFrame}");
ImGui.Text($"FPS: {FramesPerSecond}");
}

public void Dispose()
{
TrackIndexByBoneIndex.Clear();
Expand Down
12 changes: 7 additions & 5 deletions FModel/Views/Snooper/Models/Animations/Skeleton.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public class Skeleton : IDisposable
public readonly bool IsLoaded;

public Animation Anim;
public bool HasAnim => Anim != null;

public Skeleton()
{
Expand Down Expand Up @@ -62,9 +63,9 @@ public Skeleton(FPackageIndex package, FReferenceSkeleton referenceSkeleton) : t
}
}

public void SetAnimation(CAnimSet anim)
public void SetAnimation(CAnimSet anim, bool rotationOnly)
{
Anim = new Animation(this, anim);
Anim = new Animation(this, anim, rotationOnly);
}

public void SetPoseUniform(Shader shader)
Expand All @@ -77,13 +78,14 @@ public void SetPoseUniform(Shader shader)
shader.SetUniform($"uFinalBonesMatrix[{boneIndex}]", Matrix4x4.Identity);
}
}
public void SetUniform(Shader shader, float deltaSeconds = 0f, bool updateElapsedTime = false)

public void SetUniform(Shader shader, float deltaSeconds = 0f, bool update = false)
{
if (!IsLoaded) return;
if (Anim == null) SetPoseUniform(shader);
if (!HasAnim) SetPoseUniform(shader);
else
{
if (!updateElapsedTime) Anim.ElapsedTime += deltaSeconds / Anim.TimePerFrame;
if (update) Anim.Update(deltaSeconds);
foreach (var boneIndex in BonesTransformByIndex.Keys)
{
if (boneIndex >= Constants.MAX_BONE_UNIFORM)
Expand Down
2 changes: 1 addition & 1 deletion FModel/Views/Snooper/Models/Model.cs
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ public void Render(float deltaSeconds, Shader shader, bool outline = false)

_vao.Bind();
shader.SetUniform("uMorphTime", MorphTime);
if (HasSkeleton) Skeleton.SetUniform(shader, deltaSeconds, outline);
if (HasSkeleton) Skeleton.SetUniform(shader, deltaSeconds, !outline);
if (!outline)
{
shader.SetUniform("uUvCount", UvCount);
Expand Down
5 changes: 4 additions & 1 deletion FModel/Views/Snooper/Renderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public class Renderer : IDisposable
public bool ShowSkybox;
public bool ShowGrid;
public bool ShowLights;
public bool AnimateWithRotationOnly;
public int VertexColor;

public Camera CameraOp { get; }
Expand All @@ -53,6 +54,7 @@ public Renderer(int width, int height)

ShowSkybox = UserSettings.Default.ShowSkybox;
ShowGrid = UserSettings.Default.ShowGrid;
AnimateWithRotationOnly = UserSettings.Default.AnimateWithRotationOnly;
VertexColor = 0; // default
}

Expand Down Expand Up @@ -93,7 +95,7 @@ public void Animate(UAnimSequence animSequence)
model.Skeleton?.UnrealSkeleton.ConvertAnims(animSequence) is not { } anim || anim.Sequences.Count == 0)
return;

model.Skeleton.SetAnimation(anim);
model.Skeleton.SetAnimation(anim, AnimateWithRotationOnly);
Options.AnimateMesh(false);
}

Expand Down Expand Up @@ -408,6 +410,7 @@ public void Save()
if (_saveCameraMode) UserSettings.Default.CameraMode = CameraOp.Mode;
UserSettings.Default.ShowSkybox = ShowSkybox;
UserSettings.Default.ShowGrid = ShowGrid;
UserSettings.Default.AnimateWithRotationOnly = AnimateWithRotationOnly;
}

public void Dispose()
Expand Down
15 changes: 9 additions & 6 deletions FModel/Views/Snooper/Shading/Material.cs
Original file line number Diff line number Diff line change
Expand Up @@ -341,12 +341,15 @@ public Vector2[] ImGuiTextureInspector(Texture fallback)
var texture = GetSelectedTexture() ?? fallback;
if (ImGui.BeginTable("texture_inspector", 2, ImGuiTableFlags.SizingStretchProp))
{
SnimGui.Layout("Type");ImGui.Text($" : ({texture.Format}) {texture.Name}");
SnimGui.TooltipCopy("(?) Click to Copy Path", texture.Path);
SnimGui.Layout("Guid");ImGui.Text($" : {texture.Guid.ToString(EGuidFormats.UniqueObjectGuid)}");
SnimGui.Layout("Import");ImGui.Text($" : {texture.ImportedWidth}x{texture.ImportedHeight}");
SnimGui.Layout("Export");ImGui.Text($" : {texture.Width}x{texture.Height}");
ImGui.EndTable();
SnimGui.NoFramePaddingOnY(() =>
{
SnimGui.Layout("Type");ImGui.Text($" : ({texture.Format}) {texture.Name}");
SnimGui.TooltipCopy("(?) Click to Copy Path", texture.Path);
SnimGui.Layout("Guid");ImGui.Text($" : {texture.Guid.ToString(EGuidFormats.UniqueObjectGuid)}");
SnimGui.Layout("Import");ImGui.Text($" : {texture.ImportedWidth}x{texture.ImportedHeight}");
SnimGui.Layout("Export");ImGui.Text($" : {texture.Width}x{texture.Height}");
ImGui.EndTable();
});
}

var largest = ImGui.GetContentRegionAvail();
Expand Down
111 changes: 69 additions & 42 deletions FModel/Views/Snooper/SnimGui.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using System.Text;
using FModel.Settings;
using FModel.Views.Snooper.Models;
using FModel.Views.Snooper.Models.Animations;
using FModel.Views.Snooper.Shading;
using OpenTK.Graphics.OpenGL4;

Expand Down Expand Up @@ -71,8 +72,8 @@ public void Render(Snooper s)
DrawDockSpace(s.Size);

SectionWindow("Material Inspector", s.Renderer, DrawMaterialInspector, false);
AnimationWindow("Timeline", s.Renderer, (icons, skeleton) => skeleton.Anim.ImGuiTimeline());

// Window("Timeline", () => {});
Window("World", () => DrawWorld(s), false);

DrawSockets(s);
Expand Down Expand Up @@ -138,7 +139,9 @@ private void DrawWorld(Snooper s)
ImGui.Checkbox("", ref s.Renderer.ShowGrid);
ImGui.PopID();Layout("Lights");ImGui.PushID(3);
ImGui.Checkbox("", ref s.Renderer.ShowLights);
ImGui.PopID();Layout("Vertex Colors");ImGui.PushID(4);
ImGui.PopID();Layout("Animate With Rotation Only");ImGui.PushID(4);
ImGui.Checkbox("", ref s.Renderer.AnimateWithRotationOnly);
ImGui.PopID();Layout("Vertex Colors");ImGui.PushID(5);
ImGui.Combo("vertex_colors", ref s.Renderer.VertexColor,
"Default\0Diffuse Only\0Colors\0Normals\0Texture Coordinates\0");
ImGui.PopID();
Expand Down Expand Up @@ -442,20 +445,23 @@ private void DrawDetails(Snooper s)
{
if (ImGui.BeginTable("model_details", 2, ImGuiTableFlags.SizingStretchProp))
{
Layout("Entity");ImGui.Text($" : ({model.Type}) {model.Name}");
Layout("Guid");ImGui.Text($" : {s.Renderer.Options.SelectedModel.ToString(EGuidFormats.UniqueObjectGuid)}");
if (model.HasSkeleton)
NoFramePaddingOnY(() =>
{
Layout("Skeleton");ImGui.Text($" : {model.Skeleton.UnrealSkeleton.Name}");
Layout("Bones");ImGui.Text($" : x{model.Skeleton.UnrealSkeleton.BoneTree.Length}");
}
else
{
Layout("Two Sided");ImGui.Text($" : {model.TwoSided}");
}
Layout("Sockets");ImGui.Text($" : x{model.Sockets.Length}");
Layout("Entity");ImGui.Text($" : ({model.Type}) {model.Name}");
Layout("Guid");ImGui.Text($" : {s.Renderer.Options.SelectedModel.ToString(EGuidFormats.UniqueObjectGuid)}");
if (model.HasSkeleton)
{
Layout("Skeleton");ImGui.Text($" : {model.Skeleton.UnrealSkeleton.Name}");
Layout("Bones");ImGui.Text($" : x{model.Skeleton.UnrealSkeleton.BoneTree.Length}");
}
else
{
Layout("Two Sided");ImGui.Text($" : {model.TwoSided}");
}
Layout("Sockets");ImGui.Text($" : x{model.Sockets.Length}");
ImGui.EndTable();
ImGui.EndTable();
});
}
if (ImGui.BeginTabBar("tabbar_details", ImGuiTabBarFlags.None))
{
Expand Down Expand Up @@ -609,36 +615,39 @@ private void DrawMaterialInspector(Dictionary<string, Texture> icons, Model mode
ImGui.SetNextItemOpen(true, ImGuiCond.Appearing);
if (ImGui.CollapsingHeader("Properties"))
{
ImGui.SetNextItemOpen(true, ImGuiCond.Appearing);
if (ImGui.TreeNode("Base"))
NoFramePaddingOnY(() =>
{
material.ImGuiBaseProperties("base");
ImGui.TreePop();
}
ImGui.SetNextItemOpen(true, ImGuiCond.Appearing);
if (ImGui.TreeNode("Base"))
{
material.ImGuiBaseProperties("base");
ImGui.TreePop();
}
ImGui.SetNextItemOpen(true, ImGuiCond.Appearing);
if (ImGui.TreeNode("Scalars"))
{
material.ImGuiDictionaries("scalars", material.Parameters.Scalars, true);
ImGui.TreePop();
}
ImGui.SetNextItemOpen(true, ImGuiCond.Appearing);
if (ImGui.TreeNode("Switchs"))
{
material.ImGuiDictionaries("switchs", material.Parameters.Switchs, true);
ImGui.TreePop();
}
ImGui.SetNextItemOpen(true, ImGuiCond.Appearing);
if (ImGui.TreeNode("Colors"))
{
material.ImGuiColors(material.Parameters.Colors);
ImGui.TreePop();
}
if (ImGui.TreeNode("All Textures"))
{
material.ImGuiDictionaries("textures", material.Parameters.Textures);
ImGui.TreePop();
}
ImGui.SetNextItemOpen(true, ImGuiCond.Appearing);
if (ImGui.TreeNode("Scalars"))
{
material.ImGuiDictionaries("scalars", material.Parameters.Scalars, true);
ImGui.TreePop();
}
ImGui.SetNextItemOpen(true, ImGuiCond.Appearing);
if (ImGui.TreeNode("Switchs"))
{
material.ImGuiDictionaries("switchs", material.Parameters.Switchs, true);
ImGui.TreePop();
}
ImGui.SetNextItemOpen(true, ImGuiCond.Appearing);
if (ImGui.TreeNode("Colors"))
{
material.ImGuiColors(material.Parameters.Colors);
ImGui.TreePop();
}
if (ImGui.TreeNode("All Textures"))
{
material.ImGuiDictionaries("textures", material.Parameters.Textures);
ImGui.TreePop();
}
});
}
}

Expand Down Expand Up @@ -772,13 +781,30 @@ private void SectionWindow(string name, Renderer renderer, Action<Dictionary<str
}, styled);
}

private void AnimationWindow(string name, Renderer renderer, Action<Dictionary<string, Texture>, Skeleton> content, bool styled = true)
{
MeshWindow(name, renderer, (icons, model) =>
{
if (!model.HasSkeleton) CenteredTextColored(_errorColor, "No Skeleton To Animate");
else if (!model.Skeleton.HasAnim) CenteredTextColored(_errorColor, "Mesh Not Animated");
else content(icons, model.Skeleton);
}, styled);
}

private void PopStyleCompact() => ImGui.PopStyleVar(2);
private void PushStyleCompact()
{
ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, new Vector2(8, 3));
ImGui.PushStyleVar(ImGuiStyleVar.CellPadding, new Vector2(0, 1));
}

public static void NoFramePaddingOnY(Action content)
{
ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, new Vector2(8, 0));
content();
ImGui.PopStyleVar();
}

private void NoMeshSelected() => CenteredTextColored(_errorColor, "No Mesh Selected");
private void NoSectionSelected() => CenteredTextColored(_errorColor, "No Section Selected");
private void CenteredTextColored(Vector4 color, string text)
Expand All @@ -797,6 +823,7 @@ public static void Layout(string name, bool tooltip = false)
{
ImGui.TableNextRow();
ImGui.TableSetColumnIndex(0);
ImGui.AlignTextToFramePadding();
ImGui.Spacing();ImGui.SameLine();ImGui.Text(name);
if (tooltip) TooltipCopy(name);
ImGui.TableSetColumnIndex(1);
Expand Down

0 comments on commit 0b7ed2c

Please sign in to comment.