mirror of
https://github.com/4sval/FModel.git
synced 2026-06-30 20:00:35 -05:00
better skeleton tree
This commit is contained in:
parent
3c2795cded
commit
b1be4da9b5
|
|
@ -1,10 +1,11 @@
|
|||
#version 460 core
|
||||
|
||||
in vec3 fPos;
|
||||
in vec3 fColor;
|
||||
|
||||
out vec4 FragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
FragColor = vec4(fColor, 1.0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,19 @@
|
|||
#version 460 core
|
||||
|
||||
layout (location = 0) in vec3 vPos;
|
||||
layout (location = 1) in vec3 vColor;
|
||||
|
||||
uniform mat4 uView;
|
||||
uniform mat4 uProjection;
|
||||
uniform mat4 uInstanceMatrix;
|
||||
|
||||
out vec3 fPos;
|
||||
out vec3 fColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_PointSize = 7.5f;
|
||||
gl_Position = uProjection * uView * uInstanceMatrix * vec4(vPos, 1.0);
|
||||
fPos = vec3(uInstanceMatrix * vec4(vPos, 1.0));
|
||||
fColor = vColor;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,10 +30,9 @@ public class Skeleton : IDisposable
|
|||
public bool IsAnimated { get; private set; }
|
||||
public string SelectedBone;
|
||||
|
||||
private const int _vertexSize = 6;
|
||||
private const int _vertexSize = 12;
|
||||
private BufferObject<float> _vbo;
|
||||
private int vaoHandle;
|
||||
private float[] _vertices;
|
||||
private int _vaoHandle;
|
||||
|
||||
public Skeleton()
|
||||
{
|
||||
|
|
@ -44,7 +43,6 @@ public class Skeleton : IDisposable
|
|||
public Skeleton(FReferenceSkeleton referenceSkeleton) : this()
|
||||
{
|
||||
BoneCount = referenceSkeleton.FinalRefBoneInfo.Length;
|
||||
_vertices = new float[_vertexSize * BoneCount];
|
||||
for (int boneIndex = 0; boneIndex < BoneCount; boneIndex++)
|
||||
{
|
||||
var info = referenceSkeleton.FinalRefBoneInfo[boneIndex];
|
||||
|
|
@ -63,14 +61,6 @@ public class Skeleton : IDisposable
|
|||
|
||||
bone.Rest.Relation = parentBone.Rest.Matrix;
|
||||
parentBone.LoweredChildNames.Add(boneName);
|
||||
|
||||
var baseIndex = boneIndex * _vertexSize;
|
||||
_vertices[baseIndex + 0] = bone.Rest.Matrix.Translation.X;
|
||||
_vertices[baseIndex + 1] = bone.Rest.Matrix.Translation.Y;
|
||||
_vertices[baseIndex + 2] = bone.Rest.Matrix.Translation.Z;
|
||||
_vertices[baseIndex + 3] = parentBone.Rest.Matrix.Translation.X;
|
||||
_vertices[baseIndex + 4] = parentBone.Rest.Matrix.Translation.Y;
|
||||
_vertices[baseIndex + 5] = parentBone.Rest.Matrix.Translation.Z;
|
||||
}
|
||||
|
||||
if (boneIndex == 0) SelectedBone = boneName;
|
||||
|
|
@ -117,14 +107,18 @@ public class Skeleton : IDisposable
|
|||
{
|
||||
_handle = GL.CreateProgram();
|
||||
|
||||
_vbo = new BufferObject<float>(_vertices, BufferTarget.ArrayBuffer);
|
||||
_vaoHandle = GL.GenVertexArray();
|
||||
GL.BindVertexArray(_vaoHandle);
|
||||
|
||||
vaoHandle = GL.GenVertexArray();
|
||||
GL.BindVertexArray(vaoHandle);
|
||||
_vbo.Bind();
|
||||
|
||||
_vbo = new BufferObject<float>(_vertexSize * BoneCount, BufferTarget.ArrayBuffer);
|
||||
|
||||
var sf = sizeof(float);
|
||||
var half = _vertexSize / 2;
|
||||
GL.EnableVertexAttribArray(0);
|
||||
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, sizeof(float) * 3, 0);
|
||||
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, sf * half, sf * 0);
|
||||
GL.EnableVertexAttribArray(1);
|
||||
GL.VertexAttribPointer(1, 3, VertexAttribPointerType.Float, false, sf * half, sf * 3);
|
||||
|
||||
GL.BindVertexArray(0);
|
||||
|
||||
|
|
@ -223,20 +217,40 @@ public class Skeleton : IDisposable
|
|||
_boneMatriceAtFrame[bone.Index] = boneMatrix;
|
||||
}
|
||||
_ssbo.Unbind();
|
||||
}
|
||||
|
||||
public void UpdateVertices()
|
||||
{
|
||||
_vbo.Bind();
|
||||
foreach (var bone in BonesByLoweredName.Values)
|
||||
foreach (var (boneName, bone) in BonesByLoweredName)
|
||||
{
|
||||
var baseIndex = bone.Index * _vertexSize;
|
||||
var boneMatrix = bone.IsRoot ? bone.Rest.Relation : bone.Rest.LocalMatrix * _boneMatriceAtFrame[bone.ParentIndex];
|
||||
var parentBoneMatrix = bone.IsRoot ? bone.Rest.Relation : _boneMatriceAtFrame[bone.ParentIndex];
|
||||
Matrix4x4 boneMatrix;
|
||||
Matrix4x4 parentBoneMatrix;
|
||||
if (IsAnimated)
|
||||
{
|
||||
boneMatrix = _boneMatriceAtFrame[bone.Index];
|
||||
parentBoneMatrix = _boneMatriceAtFrame[bone.ParentIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
boneMatrix = bone.Rest.Matrix;
|
||||
parentBoneMatrix = bone.IsRoot ? boneMatrix : BonesByLoweredName[bone.LoweredParentName].Rest.Matrix;
|
||||
}
|
||||
|
||||
_vbo.Update(baseIndex + 0, boneMatrix.Translation.X);
|
||||
_vbo.Update(baseIndex + 1, boneMatrix.Translation.Y);
|
||||
_vbo.Update(baseIndex + 2, boneMatrix.Translation.Z);
|
||||
_vbo.Update(baseIndex + 3, parentBoneMatrix.Translation.X);
|
||||
_vbo.Update(baseIndex + 4, parentBoneMatrix.Translation.Y);
|
||||
_vbo.Update(baseIndex + 5, parentBoneMatrix.Translation.Z);
|
||||
var count = 0;
|
||||
var baseIndex = bone.Index * _vertexSize;
|
||||
_vbo.Update(baseIndex + count++, boneMatrix.Translation.X);
|
||||
_vbo.Update(baseIndex + count++, boneMatrix.Translation.Y);
|
||||
_vbo.Update(baseIndex + count++, boneMatrix.Translation.Z);
|
||||
_vbo.Update(baseIndex + count++, 1.0f);
|
||||
_vbo.Update(baseIndex + count++, boneName == SelectedBone ? 0.0f : 1.0f);
|
||||
_vbo.Update(baseIndex + count++, boneName == SelectedBone ? 0.0f : 1.0f);
|
||||
_vbo.Update(baseIndex + count++, parentBoneMatrix.Translation.X);
|
||||
_vbo.Update(baseIndex + count++, parentBoneMatrix.Translation.Y);
|
||||
_vbo.Update(baseIndex + count++, parentBoneMatrix.Translation.Z);
|
||||
_vbo.Update(baseIndex + count++, 1.0f);
|
||||
_vbo.Update(baseIndex + count++, bone.LoweredParentName == SelectedBone ? 0.0f : 1.0f);
|
||||
_vbo.Update(baseIndex + count++, bone.LoweredParentName == SelectedBone ? 0.0f : 1.0f);
|
||||
}
|
||||
_vbo.Unbind();
|
||||
}
|
||||
|
|
@ -284,8 +298,9 @@ public class Skeleton : IDisposable
|
|||
{
|
||||
GL.Disable(EnableCap.DepthTest);
|
||||
|
||||
GL.BindVertexArray(vaoHandle);
|
||||
GL.DrawArrays(PrimitiveType.Lines, 0, _vertices.Length);
|
||||
GL.BindVertexArray(_vaoHandle);
|
||||
GL.DrawArrays(PrimitiveType.Lines, 0, _vbo.Size);
|
||||
GL.DrawArrays(PrimitiveType.Points, 0, _vbo.Size);
|
||||
GL.BindVertexArray(0);
|
||||
|
||||
GL.Enable(EnableCap.DepthTest);
|
||||
|
|
@ -303,7 +318,7 @@ public class Skeleton : IDisposable
|
|||
|
||||
var x = p1.X;
|
||||
var y = p1.Y + (p2.Y - p1.Y) / 2;
|
||||
for (int i = Math.Min(_breadcrumb.Count - 1, 5); i >= 1; i--)
|
||||
for (int i = Math.Min(_breadcrumb.Count - 1, 5); i >= 0; i--)
|
||||
{
|
||||
var boneName = _breadcrumb[i];
|
||||
var size = ImGui.CalcTextSize(boneName);
|
||||
|
|
@ -317,7 +332,7 @@ public class Skeleton : IDisposable
|
|||
break;
|
||||
}
|
||||
|
||||
drawList.AddText(position, i == 1 || ImGui.IsItemHovered() ? 0xFFFFFFFF : 0xA0FFFFFF, boneName);
|
||||
drawList.AddText(position, i == 0 || ImGui.IsItemHovered() ? 0xFFFFFFFF : 0xA0FFFFFF, boneName);
|
||||
x += size.X + 7.5f;
|
||||
drawList.AddText(position with { X = x }, 0xA0FFFFFF, ">");
|
||||
x += 7.5f;
|
||||
|
|
@ -328,7 +343,10 @@ public class Skeleton : IDisposable
|
|||
|
||||
public void ImGuiBoneHierarchy()
|
||||
{
|
||||
DrawBoneTree(SelectedBone, BonesByLoweredName[SelectedBone]);
|
||||
foreach (var name in BonesByLoweredName[SelectedBone].LoweredChildNames)
|
||||
{
|
||||
DrawBoneTree(name, BonesByLoweredName[name]);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawBoneTree(string boneName, Bone bone)
|
||||
|
|
@ -338,11 +356,11 @@ public class Skeleton : IDisposable
|
|||
ImGui.TableNextColumn();
|
||||
|
||||
var flags = ImGuiTreeNodeFlags.OpenOnArrow | ImGuiTreeNodeFlags.SpanFullWidth;
|
||||
if (boneName == SelectedBone) flags |= ImGuiTreeNodeFlags.Selected;
|
||||
// if (boneName == SelectedBone) flags |= ImGuiTreeNodeFlags.Selected;
|
||||
if (bone.IsVirtual) flags |= ImGuiTreeNodeFlags.Leaf;
|
||||
else if (!bone.IsDaron) flags |= ImGuiTreeNodeFlags.Bullet;
|
||||
|
||||
ImGui.SetNextItemOpen(bone.LoweredChildNames.Count <= 1 || flags.HasFlag(ImGuiTreeNodeFlags.Selected), ImGuiCond.Appearing);
|
||||
ImGui.SetNextItemOpen(bone.LoweredChildNames.Count <= 1, ImGuiCond.Appearing);
|
||||
var open = ImGui.TreeNodeEx(boneName, flags);
|
||||
if (ImGui.IsItemClicked() && !ImGui.IsItemToggledOpen() && bone.IsDaron)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,52 +0,0 @@
|
|||
using CUE4Parse_Conversion.Meshes.PSK;
|
||||
using FModel.Views.Snooper.Shading;
|
||||
using OpenTK.Graphics.OpenGL4;
|
||||
|
||||
namespace FModel.Views.Snooper.Models;
|
||||
|
||||
public class BoneModel : UModel
|
||||
{
|
||||
public BoneModel(CStaticMesh staticMesh)
|
||||
{
|
||||
var lod = staticMesh.LODs[LodLevel];
|
||||
|
||||
Indices = new uint[lod.Indices.Value.Length];
|
||||
for (int i = 0; i < Indices.Length; i++)
|
||||
{
|
||||
Indices[i] = (uint) lod.Indices.Value[i];
|
||||
}
|
||||
|
||||
Vertices = new float[lod.NumVerts * VertexSize];
|
||||
for (int i = 0; i < lod.Verts.Length; i++)
|
||||
{
|
||||
var count = 0;
|
||||
var baseIndex = i * VertexSize;
|
||||
var vert = lod.Verts[i];
|
||||
Vertices[baseIndex + count++] = vert.Position.X * Constants.SCALE_DOWN_RATIO;
|
||||
Vertices[baseIndex + count++] = vert.Position.Z * Constants.SCALE_DOWN_RATIO;
|
||||
Vertices[baseIndex + count++] = vert.Position.Y * Constants.SCALE_DOWN_RATIO;
|
||||
}
|
||||
|
||||
Materials = new Material[1];
|
||||
Materials[0] = new Material { IsUsed = true };
|
||||
|
||||
Sections = new Section[1];
|
||||
Sections[0] = new Section(0, Indices.Length, 0);
|
||||
|
||||
Box = staticMesh.BoundingBox * Constants.SCALE_DOWN_RATIO;
|
||||
}
|
||||
|
||||
public override void Render(Shader shader, bool outline = false)
|
||||
{
|
||||
GL.Disable(EnableCap.DepthTest);
|
||||
|
||||
Vao.Bind();
|
||||
foreach (var section in Sections)
|
||||
{
|
||||
GL.DrawElementsInstanced(PrimitiveType.LineStrip, section.FacesCount, DrawElementsType.UnsignedInt, section.FirstFaceIndexPtr, TransformsCount);
|
||||
}
|
||||
Vao.Unbind();
|
||||
|
||||
GL.Enable(EnableCap.DepthTest);
|
||||
}
|
||||
}
|
||||
|
|
@ -20,7 +20,8 @@ public class SkeletalModel : UModel
|
|||
public bool HasMorphTargets => Morphs.Count > 0;
|
||||
|
||||
public float MorphTime;
|
||||
public bool DrawSkeleton { get; set; }
|
||||
|
||||
public bool TreeIsOpen;
|
||||
|
||||
public SkeletalModel(USkeletalMesh export, CSkeletalMesh skeletalMesh, Transform transform = null)
|
||||
: base(export, skeletalMesh.LODs[LodLevel], export.Materials, skeletalMesh.LODs[LodLevel].Verts, skeletalMesh.LODs.Count, transform)
|
||||
|
|
|
|||
|
|
@ -260,17 +260,15 @@ public class Renderer : IDisposable
|
|||
Options.Lights[i].Render(_light);
|
||||
}
|
||||
|
||||
// bone pass
|
||||
foreach (var model in Options.Models.Values)
|
||||
{
|
||||
if (!model.IsVisible || model is not SkeletalModel { DrawSkeleton: true } skeletalModel) continue;
|
||||
_bone.Render(viewMatrix, projMatrix);
|
||||
skeletalModel.RenderBones(_bone);
|
||||
}
|
||||
|
||||
// outline pass
|
||||
// debug + outline pass
|
||||
if (Options.TryGetModel(out var selected) && selected.IsVisible)
|
||||
{
|
||||
if (selected is SkeletalModel { TreeIsOpen: true } skeletalModel)
|
||||
{
|
||||
_bone.Render(viewMatrix, projMatrix);
|
||||
skeletalModel.RenderBones(_bone);
|
||||
}
|
||||
|
||||
_outline.Render(viewMatrix, CameraOp.Position, projMatrix);
|
||||
selected.Render(_outline, true);
|
||||
}
|
||||
|
|
@ -292,9 +290,15 @@ public class Renderer : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
foreach (var model in Options.Models.Values)
|
||||
{
|
||||
model.Update(Options);
|
||||
foreach (var model in Options.Models.Values)
|
||||
{
|
||||
model.Update(Options);
|
||||
}
|
||||
if (Options.TryGetModel(out var selected) && selected is SkeletalModel { IsVisible: true, TreeIsOpen: true } skeletalModel)
|
||||
{
|
||||
skeletalModel.Skeleton.UpdateVertices();
|
||||
}
|
||||
}
|
||||
|
||||
CameraOp.Modify(wnd.KeyboardState, deltaSeconds);
|
||||
|
|
|
|||
|
|
@ -67,7 +67,6 @@ public class SnimGui
|
|||
|
||||
private Vector2 _outlinerSize;
|
||||
private bool _ti_open;
|
||||
private bool _bh_open;
|
||||
private bool _viewportFocus;
|
||||
|
||||
private readonly Vector4 _accentColor = new (0.125f, 0.42f, 0.831f, 1.0f);
|
||||
|
|
@ -104,8 +103,8 @@ public class SnimGui
|
|||
Draw3DViewport(s);
|
||||
DrawNavbar();
|
||||
|
||||
if (_ti_open) DrawTextureInspector(s);
|
||||
if (_bh_open) DrawBoneHierarchy(s);
|
||||
DrawTextureInspector(s);
|
||||
DrawSkeletonTree(s);
|
||||
|
||||
DrawModals(s);
|
||||
|
||||
|
|
@ -428,7 +427,6 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio
|
|||
s.Renderer.Options.SelectModel(guid);
|
||||
if (ImGui.MenuItem("Show", null, model.IsVisible)) model.IsVisible = !model.IsVisible;
|
||||
if (ImGui.MenuItem("Wireframe", null, model.ShowWireframe)) model.ShowWireframe = !model.ShowWireframe;
|
||||
if (model is SkeletalModel skeletalModel && ImGui.MenuItem("Draw Skeleton", null, skeletalModel.DrawSkeleton)) skeletalModel.DrawSkeleton = !skeletalModel.DrawSkeleton;
|
||||
ImGui.Separator();
|
||||
if (ImGui.MenuItem("Save"))
|
||||
{
|
||||
|
|
@ -436,35 +434,37 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio
|
|||
_saver.Value = model.Save(out _saver.Label, out _saver.Path);
|
||||
s.WindowShouldFreeze(false);
|
||||
}
|
||||
if (ImGui.MenuItem("Animate", model is SkeletalModel))
|
||||
if (model is SkeletalModel skeletalModel)
|
||||
{
|
||||
if (_swapper.IsAware)
|
||||
if (ImGui.MenuItem("Animate"))
|
||||
{
|
||||
s.Renderer.Options.RemoveAnimations();
|
||||
s.Renderer.Options.AnimateMesh(true);
|
||||
s.WindowShouldClose(true, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
_swapper.Title = "Skeletal Animation";
|
||||
_swapper.Description = "You're about to animate a model.\nThe window will close for you to extract an animation!\n\n";
|
||||
_swapper.Content = () =>
|
||||
if (_swapper.IsAware)
|
||||
{
|
||||
s.Renderer.Options.RemoveAnimations();
|
||||
s.Renderer.Options.AnimateMesh(true);
|
||||
};
|
||||
_swapper.Value = true;
|
||||
s.WindowShouldClose(true, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
_swapper.Title = "Skeletal Animation";
|
||||
_swapper.Description = "You're about to animate a model.\nThe window will close for you to extract an animation!\n\n";
|
||||
_swapper.Content = () =>
|
||||
{
|
||||
s.Renderer.Options.RemoveAnimations();
|
||||
s.Renderer.Options.AnimateMesh(true);
|
||||
};
|
||||
_swapper.Value = true;
|
||||
}
|
||||
}
|
||||
if (ImGui.MenuItem("Skeleton Tree"))
|
||||
{
|
||||
skeletalModel.TreeIsOpen = true;
|
||||
ImGui.SetWindowFocus("Skeleton Tree");
|
||||
}
|
||||
}
|
||||
if (ImGui.MenuItem("Skeleton Tree", model is SkeletalModel))
|
||||
{
|
||||
_bh_open = true;
|
||||
ImGui.SetWindowFocus("Skeleton Tree");
|
||||
}
|
||||
if (ImGui.MenuItem("Teleport To"))
|
||||
{
|
||||
var instancePos = model.Transforms[model.SelectedInstance].Matrix.Translation;
|
||||
s.Renderer.CameraOp.Teleport(instancePos, model.Box);
|
||||
s.Renderer.CameraOp.Teleport(model.GetTransform().Matrix.Translation, model.Box);
|
||||
}
|
||||
|
||||
if (ImGui.MenuItem("Delete")) s.Renderer.Options.RemoveModel(guid);
|
||||
|
|
@ -713,6 +713,7 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio
|
|||
|
||||
private void DrawTextureInspector(Snooper s)
|
||||
{
|
||||
if (!_ti_open) return;
|
||||
if (ImGui.Begin("Texture Inspector", ref _ti_open, ImGuiWindowFlags.NoScrollbar) &&
|
||||
s.Renderer.Options.TryGetModel(out var model) &&
|
||||
s.Renderer.Options.TryGetSection(model, out var section))
|
||||
|
|
@ -722,21 +723,14 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio
|
|||
ImGui.End(); // if window is collapsed
|
||||
}
|
||||
|
||||
private void DrawBoneHierarchy(Snooper s)
|
||||
private void DrawSkeletonTree(Snooper s)
|
||||
{
|
||||
if (!s.Renderer.Options.TryGetModel(out var model) || model is not SkeletalModel { TreeIsOpen: true } skeletalModel)
|
||||
return;
|
||||
|
||||
ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, Vector2.Zero);
|
||||
if (ImGui.Begin("Skeleton Tree", ref _bh_open, ImGuiWindowFlags.NoScrollbar) && s.Renderer.Options.TryGetModel(out var model) && model is SkeletalModel skeletalModel)
|
||||
if (ImGui.Begin("Skeleton Tree", ref skeletalModel.TreeIsOpen, ImGuiWindowFlags.NoScrollbar))
|
||||
{
|
||||
// ImGui.SeparatorText("Options");
|
||||
// if (ImGui.BeginTable("skeleton_options", 2))
|
||||
// {
|
||||
// Layout("Draw All Bones");ImGui.PushID(1);
|
||||
// ImGui.Checkbox("", ref skeletalModel.Skeleton.DrawAllBones);
|
||||
// ImGui.PopID();
|
||||
//
|
||||
// ImGui.EndTable();
|
||||
// }
|
||||
// ImGui.SeparatorText("Tree");
|
||||
skeletalModel.Skeleton.ImGuiBoneBreadcrumb();
|
||||
if (ImGui.BeginTable("skeleton_tree", 2, ImGuiTableFlags.NoSavedSettings | ImGuiTableFlags.RowBg, ImGui.GetContentRegionAvail(), ImGui.GetWindowWidth()))
|
||||
{
|
||||
|
|
@ -746,6 +740,7 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio
|
|||
ImGui.EndTable();
|
||||
}
|
||||
}
|
||||
ImGui.End(); // if window is collapsed
|
||||
ImGui.PopStyleVar();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ public class Snooper : GameWindow
|
|||
GL.Enable(EnableCap.CullFace);
|
||||
GL.Enable(EnableCap.DepthTest);
|
||||
GL.Enable(EnableCap.Multisample);
|
||||
GL.Enable(EnableCap.VertexProgramPointSize);
|
||||
GL.StencilOp(StencilOp.Keep, StencilOp.Replace, StencilOp.Replace);
|
||||
GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user