From b1be4da9b50a8c77b31800986f7d93bb1550629f Mon Sep 17 00:00:00 2001 From: Asval Date: Mon, 28 Aug 2023 23:50:09 +0200 Subject: [PATCH] better skeleton tree --- FModel/Resources/bone.frag | 3 +- FModel/Resources/bone.vert | 4 + FModel/Views/Snooper/Animations/Skeleton.cs | 86 ++++++++++++-------- FModel/Views/Snooper/Models/BoneModel.cs | 52 ------------ FModel/Views/Snooper/Models/SkeletalModel.cs | 3 +- FModel/Views/Snooper/Renderer.cs | 26 +++--- FModel/Views/Snooper/SnimGui.cs | 67 +++++++-------- FModel/Views/Snooper/Snooper.cs | 1 + 8 files changed, 107 insertions(+), 135 deletions(-) delete mode 100644 FModel/Views/Snooper/Models/BoneModel.cs diff --git a/FModel/Resources/bone.frag b/FModel/Resources/bone.frag index 316129b3..cdfebf9d 100644 --- a/FModel/Resources/bone.frag +++ b/FModel/Resources/bone.frag @@ -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); } diff --git a/FModel/Resources/bone.vert b/FModel/Resources/bone.vert index 1d91226c..a1eda419 100644 --- a/FModel/Resources/bone.vert +++ b/FModel/Resources/bone.vert @@ -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; } diff --git a/FModel/Views/Snooper/Animations/Skeleton.cs b/FModel/Views/Snooper/Animations/Skeleton.cs index f3813f31..4f2dd73e 100644 --- a/FModel/Views/Snooper/Animations/Skeleton.cs +++ b/FModel/Views/Snooper/Animations/Skeleton.cs @@ -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 _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(_vertices, BufferTarget.ArrayBuffer); + _vaoHandle = GL.GenVertexArray(); + GL.BindVertexArray(_vaoHandle); - vaoHandle = GL.GenVertexArray(); - GL.BindVertexArray(vaoHandle); - _vbo.Bind(); + _vbo = new BufferObject(_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) { diff --git a/FModel/Views/Snooper/Models/BoneModel.cs b/FModel/Views/Snooper/Models/BoneModel.cs deleted file mode 100644 index 65870c98..00000000 --- a/FModel/Views/Snooper/Models/BoneModel.cs +++ /dev/null @@ -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); - } -} diff --git a/FModel/Views/Snooper/Models/SkeletalModel.cs b/FModel/Views/Snooper/Models/SkeletalModel.cs index 465a7412..d66117db 100644 --- a/FModel/Views/Snooper/Models/SkeletalModel.cs +++ b/FModel/Views/Snooper/Models/SkeletalModel.cs @@ -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) diff --git a/FModel/Views/Snooper/Renderer.cs b/FModel/Views/Snooper/Renderer.cs index fee4c332..c411db19 100644 --- a/FModel/Views/Snooper/Renderer.cs +++ b/FModel/Views/Snooper/Renderer.cs @@ -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); diff --git a/FModel/Views/Snooper/SnimGui.cs b/FModel/Views/Snooper/SnimGui.cs index 158034ea..58ad5a5e 100644 --- a/FModel/Views/Snooper/SnimGui.cs +++ b/FModel/Views/Snooper/SnimGui.cs @@ -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(); } diff --git a/FModel/Views/Snooper/Snooper.cs b/FModel/Views/Snooper/Snooper.cs index f51ebb19..210b7100 100644 --- a/FModel/Views/Snooper/Snooper.cs +++ b/FModel/Views/Snooper/Snooper.cs @@ -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);