Skip to content

Commit

Permalink
socket backend
Browse files Browse the repository at this point in the history
  • Loading branch information
4sval committed Jan 9, 2023
1 parent ac0e11e commit bf171b2
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 62 deletions.
43 changes: 11 additions & 32 deletions FModel/Views/Snooper/Models/Animations/Skeleton.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ public class Skeleton : IDisposable
public readonly Dictionary<int, Transform> BonesTransformByIndex;
public readonly bool IsLoaded;

public readonly Socket[] Sockets;

public Animation Anim;

private FVector _previousMatrix;
public Skeleton()
{
BonesIndexByName = new Dictionary<string, int>();
BonesTransformByIndex = new Dictionary<int, Transform>();
}

public Skeleton(FPackageIndex package, Transform transform)
public Skeleton(FPackageIndex package, Transform transform) : this()
{
UnrealSkeleton = package.Load<USkeleton>();
if (UnrealSkeleton == null) return;
Expand Down Expand Up @@ -64,43 +66,20 @@ public Skeleton(FPackageIndex package, Transform transform)
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 UpdateSocketsMatrix(Transform t)
public void UpdateRootBoneMatrix(Matrix4x4 delta)
{
var m = t.Position;
if (m == _previousMatrix) return;
// Matrix4x4.Decompose(delta, out var scale, out var rotation, out var position);
// Log.Logger.Information("Update");

var delta = _previousMatrix - m;
Log.Logger.Information("Update {0}", delta);

// BonesTransformByIndex[0].Relation.Translation += delta;
foreach (var socket in Sockets)
{
socket.Transform.Relation.Translation += delta;
}
_previousMatrix = m;
// TODO: support for rotation and scale
BonesTransformByIndex[0].Relation.Translation += delta.Translation;
}

public void SetUniform(Shader shader)
Expand Down
70 changes: 62 additions & 8 deletions FModel/Views/Snooper/Models/Model.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,12 @@ public class Model : IDisposable
public bool HasSkeleton => Skeleton is { IsLoaded: true };
public readonly Skeleton Skeleton;

public bool HasSockets => Sockets.Length > 0;
public readonly Socket[] Sockets;

public int TransformsCount;
public readonly List<Transform> Transforms;
private Matrix4x4 _previousMatrix;

public readonly Morph[] Morphs;

Expand All @@ -76,14 +80,40 @@ protected Model(UObject export)
}

public Model(UStaticMesh export, CStaticMesh staticMesh) : this(export, staticMesh, Transform.Identity) {}

public Model(UStaticMesh export, CStaticMesh staticMesh, Transform transform) : this(export, export.Materials, null, staticMesh.LODs.Count, staticMesh.LODs[0], staticMesh.LODs[0].Verts, transform)
{
Box = staticMesh.BoundingBox * Constants.SCALE_DOWN_RATIO;

Sockets = new Socket[export.Sockets.Length];
for (int i = 0; i < Sockets.Length; i++)
{
if (export.Sockets[i].Load<UStaticMeshSocket>() is not { } socket) continue;
Sockets[i] = new Socket(socket);
}
}
private Model(USkeletalMesh export, CSkeletalMesh skeletalMesh, Transform transform) : this(export, export.Materials, export.Skeleton, skeletalMesh.LODs.Count, skeletalMesh.LODs[0], skeletalMesh.LODs[0].Verts, transform)
{
Box = skeletalMesh.BoundingBox * Constants.SCALE_DOWN_RATIO;

var sockets = new List<FPackageIndex>();
sockets.AddRange(export.Sockets);
if (HasSkeleton) sockets.AddRange(Skeleton.UnrealSkeleton.Sockets);

Sockets = new Socket[sockets.Count];
for (int i = 0; i < Sockets.Length; i++)
{
if (sockets[i].Load<USkeletalMeshSocket>() is not { } socket) continue;

if (!Skeleton.BonesIndexByName.TryGetValue(socket.BoneName.Text, out var boneIndex) ||
!Skeleton.BonesTransformByIndex.TryGetValue(boneIndex, out var boneTransform))
{
Sockets[i] = new Socket(socket);
}
else
{
Sockets[i] = new Socket(socket, boneTransform);
}
}
}
public Model(USkeletalMesh export, CSkeletalMesh skeletalMesh) : this(export, skeletalMesh, Transform.Identity)
{
Expand Down Expand Up @@ -194,20 +224,44 @@ public void AddInstance(Transform transform)
{
TransformsCount++;
Transforms.Add(transform);
_previousMatrix = transform.Matrix;
}

public void UpdateMatrix() => UpdateMatrix(SelectedInstance);
public void UpdateMatrix(Transform transform) => UpdateMatrix(SelectedInstance, transform);
public void UpdateMatrix(int instance, Transform transform)
public void UpdateMatrices(Options options)
{
Transforms[instance] = transform;
UpdateMatrix(instance);
UpdateMatrices();
if (!HasSkeleton)
return;

for (int s = 0; s < Sockets.Length; s++)
{
for (int g = 0; g < Sockets[s].AttachedModels.Count; g++)
{
if (!options.TryGetModel(Sockets[s].AttachedModels[g], out var attachedModel))
continue;

attachedModel.Transforms[attachedModel.SelectedInstance].Relation = Sockets[s].Transform.Matrix;
attachedModel.UpdateMatrices();
}
}
}
public void UpdateMatrix(int instance)
private void UpdateMatrices()
{
var matrix = Transforms[SelectedInstance].Matrix;
if (matrix == _previousMatrix) return;

_matrixVbo.Bind();
_matrixVbo.Update(instance, Transforms[instance].Matrix);
_matrixVbo.Update(SelectedInstance, matrix);
_matrixVbo.Unbind();

var delta = matrix - _previousMatrix;
foreach (var socket in Sockets)
{
socket.UpdateSocketMatrix(delta);
}
if (HasSkeleton) Skeleton.UpdateRootBoneMatrix(delta);

_previousMatrix = matrix;
}

public void UpdateMorph(int index)
Expand Down
32 changes: 27 additions & 5 deletions FModel/Views/Snooper/Models/Socket.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
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;

namespace FModel.Views.Snooper.Models;
Expand All @@ -10,29 +13,48 @@ public class Socket : IDisposable
public readonly string Bone;
public readonly Transform Transform;

public FGuid AttachedModel;
public readonly List<FGuid> AttachedModels;

public Socket(USkeletalMeshSocket socket)
private Socket()
{
Bone = "None";
Transform = Transform.Identity;
AttachedModels = new List<FGuid>();
}

public Socket(UStaticMeshSocket socket) : this()
{
Name = socket.SocketName.Text;
Transform.Rotation = socket.RelativeRotation.Quaternion();
Transform.Position = socket.RelativeLocation * Constants.SCALE_DOWN_RATIO;
Transform.Scale = socket.RelativeScale;
}

public Socket(USkeletalMeshSocket socket) : this()
{
Name = socket.SocketName.Text;
Bone = socket.BoneName.Text;
Transform = Transform.Identity;
Transform.Rotation = socket.RelativeRotation.Quaternion();
Transform.Position = socket.RelativeLocation * Constants.SCALE_DOWN_RATIO;
Transform.Scale = socket.RelativeScale;
}

public Socket(USkeletalMeshSocket socket, Transform transform)
public Socket(USkeletalMeshSocket socket, Transform transform) : this()
{
Name = socket.SocketName.Text;
Bone = socket.BoneName.Text;
Transform = Transform.Identity;
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 delta)
{
// TODO: support for rotation and scale
Transform.Relation.Translation += delta.Translation;
}

public void Dispose()
{
throw new NotImplementedException();
Expand Down
1 change: 1 addition & 0 deletions FModel/Views/Snooper/Renderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ public void Render()
// render model pass
foreach (var model in Options.Models.Values)
{
model.UpdateMatrices(Options);
if (!model.Show) continue;
model.Render(_shader);
}
Expand Down
51 changes: 35 additions & 16 deletions FModel/Views/Snooper/SnimGui.cs
Original file line number Diff line number Diff line change
Expand Up @@ -394,34 +394,54 @@ private void DrawOuliner(Snooper s)

private void DrawSockets(Snooper s)
{
var selectedGuid = s.Renderer.Options.SelectedModel;
if (!s.Renderer.Options.TryGetModel(out var selectedModel))
return;

foreach (var model in s.Renderer.Options.Models.Values)
{
if (!model.HasSkeleton || model.IsSelected) return;
if (ImGui.TreeNode($"{model.Name} [{model.Skeleton.Sockets.Length}]"))
if (!model.HasSockets || model.IsSelected) continue;
if (ImGui.TreeNode($"{model.Name} [{model.Sockets.Length}]"))
{
var i = 0;
foreach (var socket in model.Skeleton.Sockets)
foreach (var socket in model.Sockets)
{
ImGui.PushID(i);
ImGui.Text($"'{socket.Name}' attached to '{socket.Bone}'");
ImGui.Text($"P: {socket.Transform.Matrix.Translation.X} | {socket.Transform.Matrix.Translation.Y} | {socket.Transform.Matrix.Translation.Z}");
if (ImGui.Button("Attach") && s.Renderer.Options.TryGetModel(out var selected))
switch (socket.AttachedModels.Contains(selectedGuid))
{
socket.AttachedModel = s.Renderer.Options.SelectedModel;
selected.UpdateMatrix(new Transform
{
Relation = socket.Transform.Matrix,
Position = FVector.ZeroVector,
Rotation = new FQuat(0),
Scale = FVector.OneVector
});
case false when ImGui.Button($"Attach to '{socket.Name}'"):
socket.AttachedModels.Add(selectedGuid);
// reset PRS to 0 so it's attached to the actual position (can be transformed relative to the socket later by the user)
selectedModel.Transforms[selectedModel.SelectedInstance].Position = FVector.ZeroVector;
selectedModel.Transforms[selectedModel.SelectedInstance].Rotation = FQuat.Identity;
selectedModel.Transforms[selectedModel.SelectedInstance].Scale = FVector.OneVector;
break;
case true when ImGui.Button($"Detach from '{socket.Name}'"):
socket.AttachedModels.Remove(selectedGuid);
// reset PRS relation to O
selectedModel.Transforms[selectedModel.SelectedInstance].Relation = Matrix4x4.Identity;
break;
}
ImGui.PopID();
i++;
}
ImGui.TreePop();
}
}

// if (ImGui.BeginTable("socket_editor", 2))
// {
// Layout("Models");
// ImGui.PushID(1);
// ImGui.Combo("", ref m, "Fly Cam\0Arcball\0");
// ImGui.PopID();
//
// Layout("Attach To");ImGui.PushID(2);
// ImGui.Combo("world_mode", ref m, "Fly Cam\0Arcball\0");
// ImGui.PopID();
//
// ImGui.EndTable();
// }
}

private void DrawDetails(Snooper s)
Expand All @@ -437,12 +457,12 @@ private void DrawDetails(Snooper s)
{
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
{
Layout("Two Sided");ImGui.Text($" : {model.TwoSided}");
}
Layout("Sockets");ImGui.Text($" : x{model.Sockets.Length}");
ImGui.EndTable();
}
Expand Down Expand Up @@ -532,7 +552,6 @@ private void DrawDetails(Snooper s)
ImGui.EndDisabled(); ImGui.PopID();
model.Transforms[model.SelectedInstance].ImGuiTransform(s.Renderer.CameraOp.Speed / 100f);
model.UpdateMatrix();
ImGui.EndTabItem();
}
Expand Down
1 change: 1 addition & 0 deletions FModel/Views/Snooper/Transform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public void ImGuiTransform(float speed)
ImGui.TreePop();
}

ImGui.SetNextItemOpen(true, ImGuiCond.Appearing);
if (ImGui.TreeNode("Scale"))
{
ImGui.SetNextItemWidth(width);
Expand Down

0 comments on commit bf171b2

Please sign in to comment.