Skip to content

Commit

Permalink
Optimized bones passed into shaders to only be the ones actually used…
Browse files Browse the repository at this point in the history
… by vertices.
  • Loading branch information
MeltyPlayer committed Feb 17, 2024
1 parent 29eee19 commit 5b7b24f
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 11 deletions.
23 changes: 20 additions & 3 deletions FinModelUtility/Fin/Fin.Ui/src/rendering/gl/GlBufferManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,12 @@ private void InitializeStatic_(IModel model) {
var boneTransformManager = new BoneTransformManager();
boneTransformManager.CalculateStaticMatricesForRendering(model);

var usedBoneIndexMap = model.Skin.BonesUsedByVertices
.Select((bone, index) => (index, bone))
.ToDictionary(
pair => pair.bone,
pair => pair.index);

for (var i = 0; i < this.vertices_.Count; ++i) {
this.vertexAccessor_.Target(this.vertices_[i]);
var vertex = this.vertexAccessor_;
Expand All @@ -137,9 +143,20 @@ private void InitializeStatic_(IModel model) {
} else {
var boneWeights = vertex.BoneWeights!.Weights;
for (var b = 0; b < 4; ++b) {
var boneWeight = b < boneWeights.Count ? boneWeights[b] : null;
this.boneIdsData_[4 * i + b] = 1 + (boneWeight?.Bone.Index ?? -1);
this.boneWeightsData_[4 * i + b] = boneWeight?.Weight ?? 0;
int boneIndex;
float weight;

if (b < boneWeights.Count) {
var boneWeight = boneWeights[b];
boneIndex = 1 + usedBoneIndexMap[boneWeight.Bone];
weight = boneWeight.Weight;
} else {
boneIndex = 0;
weight = 0;
}

this.boneIdsData_[4 * i + b] = boneIndex;
this.boneWeightsData_[4 * i + b] = weight;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ protected BGlMaterialShader(

this.matricesUniform_ = this.impl_.GetUniformMat4s(
GlslConstants.UNIFORM_BONE_MATRICES_NAME,
1 + model.Skeleton.Bones.Count);
1 + model.Skin.BonesUsedByVertices.Count);
this.matricesUniform_.SetAndMarkDirty(0, Matrix4x4.Identity);

this.shininessUniform_ = this.impl_.GetUniformFloat(
Expand Down Expand Up @@ -136,7 +136,8 @@ public void Use() {
this.cameraPositionUniform_.SetAndMaybeMarkDirty(
new Vector3(scCamX, scCamY, scCamZ));

foreach (var bone in this.model_.Skeleton.Bones) {
var boneIndex = 1;
foreach (var bone in this.model_.Skin.BonesUsedByVertices) {
var localToWorldMatrix =
this.boneTransformManager_?.GetLocalToWorldMatrix(bone).Impl ??
Matrix4x4.Identity;
Expand All @@ -145,7 +146,7 @@ public void Use() {
Matrix4x4.Identity;

this.matricesUniform_.SetAndMarkDirty(
1 + bone.Index,
boneIndex++,
inverseMatrix * localToWorldMatrix);
}

Expand Down
26 changes: 26 additions & 0 deletions FinModelUtility/Fin/Fin/src/data/sets/FinSortedSet.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using System.Collections;
using System.Collections.Generic;

namespace fin.data.sets {
public class FinSortedSet<T>(Comparer<T> comparer) : IFinSet<T> {
private readonly SortedSet<T> impl_ = new(comparer);

public FinSortedSet() : this(Comparer<T>.Default) { }

public FinSortedSet(Comparison<T> comparison) : this(
Comparer<T>.Create(comparison)) { }

public int Count => this.impl_.Count;

public bool Contains(T value) => this.impl_.Contains(value);

public void Clear() => this.impl_.Clear();

public bool Add(T value) => this.impl_.Add(value);
public bool Remove(T value) => this.impl_.Remove(value);

IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
public IEnumerator<T> GetEnumerator() => this.impl_.GetEnumerator();
}
}
2 changes: 2 additions & 0 deletions FinModelUtility/Fin/Fin/src/model/SkinInterfaces.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Numerics;

using fin.data.indexable;
using fin.data.sets;
using fin.math.matrix.four;
using fin.math.xyz;

Expand All @@ -14,6 +15,7 @@ public interface ISkin {
IMesh AddMesh();
bool AllowMaterialRendererMerging { get; set; }

IReadOnlyFinSet<IBone> BonesUsedByVertices { get; }
IReadOnlyList<IBoneWeights> BoneWeights { get; }

IBoneWeights GetOrCreateBoneWeights(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public class BoneWeightsDictionary {

public IBoneWeights GetOrCreate(
VertexSpace vertexSpace,
out bool newlyCreated,
params IBoneWeight[] weights
) {
var error = .0001;
Expand All @@ -32,9 +33,11 @@ params IBoneWeight[] weights
new BoneWeightsSet();
}

newlyCreated = false;
if (!allBoneWeightsWithCount.TryGetExisting(vertexSpace, weights,
out var boneWeights)) {
allBoneWeightsWithCount.Add(boneWeights = CreateInstance_(vertexSpace, weights));
out var boneWeights)) {
newlyCreated = true;
allBoneWeightsWithCount.Add(boneWeights = this.CreateInstance_(vertexSpace, weights));
}

return boneWeights;
Expand Down
23 changes: 21 additions & 2 deletions FinModelUtility/Fin/Fin/src/model/impl/SkinImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

using fin.data;
using fin.data.indexable;
using fin.data.sets;
using fin.math.matrix.four;
using fin.math.xyz;
using fin.util.enumerables;
Expand All @@ -21,6 +22,8 @@ private class SkinImpl : ISkin<TVertex> {
private readonly IList<TVertex> vertices_;
private readonly IList<IMesh> meshes_ = new List<IMesh>();

private readonly FinSortedSet<IBone> bonesUsedByVertices_
= new((lhs, rhs) => lhs.Index.CompareTo(rhs.Index));
private readonly BoneWeightsDictionary boneWeightsDictionary_ = new();

private readonly IndexableDictionary<IBone, IBoneWeights>
Expand Down Expand Up @@ -77,6 +80,9 @@ public IMesh AddMesh() {

public bool AllowMaterialRendererMerging { get; set; } = true;

public IReadOnlyFinSet<IBone> BonesUsedByVertices
=> this.bonesUsedByVertices_;

public IReadOnlyList<IBoneWeights> BoneWeights
=> this.boneWeightsDictionary_.List;

Expand All @@ -88,14 +94,27 @@ public IBoneWeights GetOrCreateBoneWeights(
vertexSpace,
new BoneWeight(bone, FinMatrix4x4.IDENTITY, 1));
this.boneWeightsByBone_[bone] = boneWeights;
this.bonesUsedByVertices_.Add(bone);
}

return boneWeights;
}

public IBoneWeights GetOrCreateBoneWeights(VertexSpace vertexSpace,
params IBoneWeight[] weights)
=> boneWeightsDictionary_.GetOrCreate(vertexSpace, weights);
params IBoneWeight[] weights) {
var boneWeights
= this.boneWeightsDictionary_.GetOrCreate(
vertexSpace,
out var newlyCreated,
weights);
if (newlyCreated) {
foreach (var boneWeight in weights) {
this.bonesUsedByVertices_.Add(boneWeight.Bone);
}
}

return boneWeights;
}

public IBoneWeights CreateBoneWeights(VertexSpace vertexSpace,
params IBoneWeight[] weights)
Expand Down
2 changes: 1 addition & 1 deletion FinModelUtility/Fin/Fin/src/shaders/glsl/GlslUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public static string GetVertexSrc(IModel model, bool useBoneMatrices) {
if (useBoneMatrices) {
vertexSrc.Append($"""
uniform mat4 {GlslConstants.UNIFORM_BONE_MATRICES_NAME}[{1 + model.Skeleton.Bones.Count}];
uniform mat4 {GlslConstants.UNIFORM_BONE_MATRICES_NAME}[{1 + model.Skin.BonesUsedByVertices.Count}];
""");
}

Expand Down

0 comments on commit 5b7b24f

Please sign in to comment.