better skeleton tree

This commit is contained in:
Asval 2023-08-28 23:50:09 +02:00
parent 3c2795cded
commit b1be4da9b5
8 changed files with 107 additions and 135 deletions

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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)
{

View File

@ -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);
}
}

View File

@ -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)

View File

@ -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);

View File

@ -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();
}

View File

@ -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);