mirror of
https://github.com/4sval/FModel.git
synced 2026-03-22 01:34:37 -05:00
using SSBOs for unlimited bones
This commit is contained in:
parent
1ca18c3958
commit
9da407ea39
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user