Skip to content

Commit

Permalink
perf: improve performance of AutoMergeBlendShape
Browse files Browse the repository at this point in the history
This pass was obtaining the blendshape buffer for each vertex, then processing those buffers.
However, in practice, most vertices share the same buffer; this pass ignored this, and redid
the same work thousands of times as a result.

This reduces processing time from ~370ms to ~22ms on my main avatar.
  • Loading branch information
bdunderscore committed Nov 4, 2024
1 parent 9ea7c9a commit bd9d8a6
Showing 1 changed file with 25 additions and 3 deletions.
28 changes: 25 additions & 3 deletions Editor/Processors/TraceAndOptimize/AutoMergeBlendShape.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Unity.Collections;
using Unity.Jobs;
using UnityEngine;
using UnityEngine.Profiling;

namespace Anatawa12.AvatarOptimizer.Processors.TraceAndOptimizes;

Expand All @@ -23,13 +24,22 @@ protected override void Execute(BuildContext context, TraceAndOptimizeState stat
{
if (state.Exclusions.Contains(skinnedMeshRenderer.gameObject)) continue; // manual exclusion

ErrorReport.WithContextObject(skinnedMeshRenderer, () => DoAutoMerge(context.GetMeshInfoFor(skinnedMeshRenderer), context));
ErrorReport.WithContextObject(skinnedMeshRenderer, () =>
{
Profiler.BeginSample("GetMeshInfoFor", skinnedMeshRenderer);
var meshInfo = context.GetMeshInfoFor(skinnedMeshRenderer);
Profiler.EndSample();

DoAutoMerge(meshInfo, context);
});
}
}

private static void DoAutoMerge(MeshInfo2 meshInfo2, BuildContext context)
{
var animationComponent = context.GetAnimationComponent(meshInfo2.SourceRenderer);

Profiler.BeginSample("Compute merge keys");
var groups = new Dictionary<MergeKey, List<string>>();

foreach (var (name, weight) in meshInfo2.BlendShapes)
Expand All @@ -43,10 +53,17 @@ private static void DoAutoMerge(MeshInfo2 meshInfo2, BuildContext context)
}

// nothing to merge
if (groups.Values.All(x => x.Count <= 1)) return;
if (groups.Values.All(x => x.Count <= 1))
{
Profiler.EndSample();
return;
}
Profiler.EndSample();

Profiler.BeginSample("Prepare merge");
// prepare merge
var buffers = meshInfo2.Vertices.Select(x => x.BlendShapeBuffer).ToArray();
var buffers = meshInfo2.Vertices.Select(x => x.BlendShapeBuffer).Distinct().ToArray();
Profiler.EndSample();

// bulk remove to optimize removing blendshape process
var removeNames = new HashSet<string>();
Expand All @@ -59,6 +76,7 @@ private static void DoAutoMerge(MeshInfo2 meshInfo2, BuildContext context)
{
// validate the blendShapes are simple enough to merge
// if not, skip
Profiler.BeginSample("AutoMergeBlendShape: Validate");
foreach (var buffer in buffers)
{
float? commonFrameWeight = null;
Expand All @@ -80,6 +98,7 @@ private static void DoAutoMerge(MeshInfo2 meshInfo2, BuildContext context)
}
}
}
Profiler.EndSample();

// validation passed, merge
var newName = $"AAO_Merged_{string.Join("_", names)}_{i++}";
Expand All @@ -94,6 +113,7 @@ private static void DoAutoMerge(MeshInfo2 meshInfo2, BuildContext context)
meshInfo2.BlendShapes.Add((newName, key.defaultWeight));
removeNames.UnionWith(names);

Profiler.BeginSample("AutoMergeBlendShape: Merge");
// actually merge data
foreach (var buffer in buffers)
{
Expand Down Expand Up @@ -136,6 +156,8 @@ private static void DoAutoMerge(MeshInfo2 meshInfo2, BuildContext context)
}
}

Profiler.EndSample();

next_shape: ;
}

Expand Down

0 comments on commit bd9d8a6

Please sign in to comment.