using SSBOs for unlimited bones

This commit is contained in:
4sval 2023-02-08 22:18:19 +01:00
parent 1ca18c3958
commit 9da407ea39
8 changed files with 48 additions and 20 deletions

View File

@ -11,7 +11,6 @@ public static class Constants
public const float SCALE_DOWN_RATIO = 0.01F; public const float SCALE_DOWN_RATIO = 0.01F;
public const int SAMPLES_COUNT = 4; public const int SAMPLES_COUNT = 4;
public const int MAX_BONE_UNIFORM = 250;
public const string WHITE = "#DAE5F2"; public const string WHITE = "#DAE5F2";
public const string GRAY = "#BBBBBB"; public const string GRAY = "#BBBBBB";

View File

@ -15,7 +15,10 @@ layout (location = 14) in vec3 vMorphTargetTangent;
uniform mat4 uView; uniform mat4 uView;
uniform mat4 uProjection; uniform mat4 uProjection;
uniform float uMorphTime; uniform float uMorphTime;
uniform mat4 uFinalBonesMatrix[250]; layout(std430, binding = 1) buffer layoutName
{
mat4 uFinalBonesMatrix[];
};
out vec3 fPos; out vec3 fPos;
out vec3 fNormal; out vec3 fNormal;

View File

@ -11,7 +11,10 @@ uniform mat4 uView;
uniform vec3 uViewPos; uniform vec3 uViewPos;
uniform mat4 uProjection; uniform mat4 uProjection;
uniform float uMorphTime; uniform float uMorphTime;
uniform mat4 uFinalBonesMatrix[250]; layout(std430, binding = 1) buffer layoutName
{
mat4 uFinalBonesMatrix[];
};
void main() void main()
{ {

View File

@ -9,7 +9,10 @@ layout (location = 13) in vec3 vMorphTargetPos;
uniform mat4 uView; uniform mat4 uView;
uniform mat4 uProjection; uniform mat4 uProjection;
uniform float uMorphTime; uniform float uMorphTime;
uniform mat4 uFinalBonesMatrix[250]; layout(std430, binding = 1) buffer layoutName
{
mat4 uFinalBonesMatrix[];
};
void main() void main()
{ {

View File

@ -36,6 +36,13 @@ public class BufferObject<TDataType> : IDisposable where TDataType : unmanaged
GL.BindBuffer(_bufferTarget, _handle); GL.BindBuffer(_bufferTarget, _handle);
} }
public void BindBufferBase(int index)
{
if (_bufferTarget != BufferTarget.ShaderStorageBuffer)
throw new ArgumentException("BindBufferBase is not allowed for anything but Shader Storage Buffers");
GL.BindBufferBase(BufferRangeTarget.ShaderStorageBuffer, index, _handle);
}
public void Unbind() public void Unbind()
{ {
GL.BindBuffer(_bufferTarget, 0); GL.BindBuffer(_bufferTarget, 0);

View File

@ -1,10 +1,13 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Numerics; using System.Numerics;
using CUE4Parse_Conversion.Animations; using CUE4Parse_Conversion.Animations;
using CUE4Parse.UE4.Assets.Exports.Animation; using CUE4Parse.UE4.Assets.Exports.Animation;
using CUE4Parse.UE4.Objects.UObject; using CUE4Parse.UE4.Objects.UObject;
using FModel.Views.Snooper.Buffers;
using FModel.Views.Snooper.Shading; using FModel.Views.Snooper.Shading;
using OpenTK.Graphics.OpenGL4;
using Serilog; using Serilog;
namespace FModel.Views.Snooper.Models.Animations; namespace FModel.Views.Snooper.Models.Animations;
@ -17,12 +20,15 @@ public struct BoneIndice
public class Skeleton : IDisposable public class Skeleton : IDisposable
{ {
private int _handle;
private BufferObject<Matrix4x4> _ssbo;
public readonly USkeleton UnrealSkeleton; public readonly USkeleton UnrealSkeleton;
public readonly bool IsLoaded; public readonly bool IsLoaded;
public readonly Dictionary<string, BoneIndice> BonesIndicesByLoweredName; public readonly Dictionary<string, BoneIndice> BonesIndicesByLoweredName;
public readonly Dictionary<int, Transform> BonesTransformByIndex; public readonly Dictionary<int, Transform> BonesTransformByIndex;
public readonly Dictionary<int, Matrix4x4> InvertedBonesMatrixByIndex; public readonly Matrix4x4[] InvertedBonesMatrixByIndex;
public Animation Anim; public Animation Anim;
public bool HasAnim => Anim != null; public bool HasAnim => Anim != null;
@ -31,7 +37,7 @@ public class Skeleton : IDisposable
{ {
BonesIndicesByLoweredName = new Dictionary<string, BoneIndice>(); BonesIndicesByLoweredName = new Dictionary<string, BoneIndice>();
BonesTransformByIndex = new Dictionary<int, Transform>(); BonesTransformByIndex = new Dictionary<int, Transform>();
InvertedBonesMatrixByIndex = new Dictionary<int, Matrix4x4>(); InvertedBonesMatrixByIndex = Array.Empty<Matrix4x4>();
} }
public Skeleton(FPackageIndex package, FReferenceSkeleton referenceSkeleton) : this() public Skeleton(FPackageIndex package, FReferenceSkeleton referenceSkeleton) : this()
@ -55,6 +61,7 @@ public class Skeleton : IDisposable
} }
#endif #endif
InvertedBonesMatrixByIndex = new Matrix4x4[BonesIndicesByLoweredName.Count];
foreach (var boneIndices in BonesIndicesByLoweredName.Values) foreach (var boneIndices in BonesIndicesByLoweredName.Values)
{ {
var bone = referenceSkeleton.FinalRefBonePose[boneIndices.Index]; var bone = referenceSkeleton.FinalRefBonePose[boneIndices.Index];
@ -84,16 +91,23 @@ public class Skeleton : IDisposable
Anim = new Animation(this, anim, rotationOnly); Anim = new Animation(this, anim, rotationOnly);
} }
public void SetUniform(Shader shader, float deltaSeconds = 0f, bool update = false) public void Setup()
{
_handle = GL.CreateProgram();
_ssbo = new BufferObject<Matrix4x4>(InvertedBonesMatrixByIndex, BufferTarget.ShaderStorageBuffer);
}
public void Render(float deltaSeconds = 0f, bool update = false)
{ {
if (!IsLoaded) return; if (!IsLoaded) return;
_ssbo.BindBufferBase(1);
if (!HasAnim) if (!HasAnim)
{ {
foreach (var boneIndex in BonesTransformByIndex.Keys) foreach (var boneIndex in BonesTransformByIndex.Keys)
{ {
if (boneIndex >= Constants.MAX_BONE_UNIFORM) _ssbo.Update(boneIndex, Matrix4x4.Identity);
break;
shader.SetUniform($"uFinalBonesMatrix[{boneIndex}]", Matrix4x4.Identity);
} }
} }
else else
@ -101,22 +115,20 @@ public class Skeleton : IDisposable
if (update) Anim.Update(deltaSeconds); if (update) Anim.Update(deltaSeconds);
foreach (var boneIndex in BonesTransformByIndex.Keys) foreach (var boneIndex in BonesTransformByIndex.Keys)
{ {
if (boneIndex >= Constants.MAX_BONE_UNIFORM) _ssbo.Update(boneIndex, InvertedBonesMatrixByIndex[boneIndex] * Anim.InterpolateBoneTransform(boneIndex));
break;
if (!InvertedBonesMatrixByIndex.TryGetValue(boneIndex, out var invertMatrix))
throw new ArgumentNullException($"no inverse matrix for bone '{boneIndex}'");
shader.SetUniform($"uFinalBonesMatrix[{boneIndex}]", invertMatrix * Anim.InterpolateBoneTransform(boneIndex));
} }
if (update) Anim.CheckForNextSequence(); if (update) Anim.CheckForNextSequence();
} }
_ssbo.Unbind();
} }
public void Dispose() public void Dispose()
{ {
BonesIndicesByLoweredName.Clear(); BonesIndicesByLoweredName.Clear();
BonesTransformByIndex.Clear(); BonesTransformByIndex.Clear();
InvertedBonesMatrixByIndex.Clear();
Anim?.Dispose(); Anim?.Dispose();
GL.DeleteProgram(_handle);
} }
} }

View File

@ -348,6 +348,7 @@ public class Model : IDisposable
Materials[i].Setup(options, broken ? 1 : UvCount); Materials[i].Setup(options, broken ? 1 : UvCount);
} }
if (HasSkeleton) Skeleton.Setup();
if (HasMorphTargets) if (HasMorphTargets)
{ {
for (uint morph = 0; morph < Morphs.Length; morph++) for (uint morph = 0; morph < Morphs.Length; morph++)
@ -382,7 +383,7 @@ public class Model : IDisposable
_vao.Bind(); _vao.Bind();
shader.SetUniform("uMorphTime", MorphTime); shader.SetUniform("uMorphTime", MorphTime);
if (HasSkeleton) Skeleton.SetUniform(shader, deltaSeconds, !outline); if (HasSkeleton) Skeleton.Render(deltaSeconds, !outline);
if (!outline) if (!outline)
{ {
shader.SetUniform("uUvCount", UvCount); shader.SetUniform("uUvCount", UvCount);
@ -413,7 +414,7 @@ public class Model : IDisposable
_vao.Bind(); _vao.Bind();
shader.SetUniform("uMorphTime", MorphTime); shader.SetUniform("uMorphTime", MorphTime);
if (HasSkeleton) Skeleton.SetUniform(shader); if (HasSkeleton) Skeleton.Render();
foreach (var section in Sections) foreach (var section in Sections)
{ {

View File

@ -452,7 +452,7 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio
if (model.HasSkeleton) if (model.HasSkeleton)
{ {
Layout("Skeleton");ImGui.Text($" : {model.Skeleton.UnrealSkeleton.Name}"); Layout("Skeleton");ImGui.Text($" : {model.Skeleton.UnrealSkeleton.Name}");
Layout("Bones");ImGui.Text($" : x{model.Skeleton.InvertedBonesMatrixByIndex.Count}"); Layout("Bones");ImGui.Text($" : x{model.Skeleton.InvertedBonesMatrixByIndex.Length}");
} }
else else
{ {