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 int SAMPLES_COUNT = 4;
public const int MAX_BONE_UNIFORM = 250;
public const string WHITE = "#DAE5F2";
public const string GRAY = "#BBBBBB";

View File

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

View File

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

View File

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

View File

@ -36,6 +36,13 @@ public class BufferObject<TDataType> : IDisposable where TDataType : unmanaged
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()
{
GL.BindBuffer(_bufferTarget, 0);

View File

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

View File

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