Skip to content

Commit

Permalink
Merge pull request #334 from anatawa12/freeze-unused-blend-shapes
Browse files Browse the repository at this point in the history
Freeze meaningless blend shapes
  • Loading branch information
anatawa12 authored Aug 23, 2023
2 parents 94d19c4 + ebbe700 commit 8b89959
Show file tree
Hide file tree
Showing 15 changed files with 94 additions and 11 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG-PRERELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ The format is based on [Keep a Changelog].
- Support for Multi Frame BlendShapes `#333`

### Changed
- Auto FreezeBlendShape now freezes meaningless BlendShape `#334`
- If you removed some vertices with RemoveMeshInBox or RemoveMeshWithBlendShape, some BlendShape may transform no vertices
- Auto FreeseBlendShae now freezez such a BlendShapes
- Auto FreezeBlendShape now freezes vertices even if already FreezeBlendShape is configured. `#334`

### Deprecated

Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ The format is based on [Keep a Changelog].
- Support for Multi Frame BlendShapes `#333`

### Changed
- Auto FreezeBlendShape now freezes meaningless BlendShape `#334`
- If you removed some vertices with RemoveMeshInBox or RemoveMeshWithBlendShape, some BlendShape may transform no vertices
- Auto FreeseBlendShae now freezez such a BlendShapes
- Auto FreezeBlendShape now freezes vertices even if already FreezeBlendShape is configured. `#334`

### Deprecated

Expand Down
1 change: 1 addition & 0 deletions Editor/EditSkinnedMeshComponentUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ private T CheckRecursive<T>(Func<T> compute)
[typeof(MergeToonLitMaterial)] = x => new MergeToonLitMaterialProcessor((MergeToonLitMaterial)x),
[typeof(RemoveMeshInBox)] = x => new RemoveMeshInBoxProcessor((RemoveMeshInBox)x),
[typeof(RemoveMeshByBlendShape)] = x => new RemoveMeshByBlendShapeProcessor((RemoveMeshByBlendShape)x),
[typeof(InternalAutoFreezeMeaninglessBlendShape)] = x => new InternalAutoFreezeMeaninglessBlendShapeProcessor((InternalAutoFreezeMeaninglessBlendShape)x),
};

private static IEditSkinnedMeshProcessor CreateProcessor(EditSkinnedMeshComponent mergePhysBone) =>
Expand Down
12 changes: 10 additions & 2 deletions Editor/Processors/SkinnedMeshes/EditSkinnedMeshProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Anatawa12.AvatarOptimizer.Processors.SkinnedMeshes
internal abstract class EditSkinnedMeshProcessor<TComponent> : IEditSkinnedMeshProcessor
where TComponent : EditSkinnedMeshComponent
{
public abstract int ProcessOrder { get; }
public abstract EditSkinnedMeshProcessorOrder ProcessOrder { get; }
public virtual IEnumerable<SkinnedMeshRenderer> Dependencies => Array.Empty<SkinnedMeshRenderer>();
protected TComponent Component { get; }
public SkinnedMeshRenderer Target { get; }
Expand Down Expand Up @@ -38,7 +38,7 @@ public override bool Equals(object obj) =>

internal interface IEditSkinnedMeshProcessor
{
int ProcessOrder { get; }
EditSkinnedMeshProcessorOrder ProcessOrder { get; }
IEnumerable<SkinnedMeshRenderer> Dependencies { get; }
SkinnedMeshRenderer Target { get; }
EditSkinnedMeshComponent Component { get; }
Expand All @@ -47,6 +47,14 @@ internal interface IEditSkinnedMeshProcessor
[NotNull] IMeshInfoComputer GetComputer([NotNull] IMeshInfoComputer upstream);
}

enum EditSkinnedMeshProcessorOrder : int
{
Generation = int.MinValue,
RemovingMesh = -20000,
AutoConfigureFreezeBlendShape = -10000 - 1,
AfterRemoveMesh = -10000,
}

internal interface IMeshInfoComputer
{
(string name, float weight)[] BlendShapes();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public FreezeBlendShapeProcessor(FreezeBlendShape component) : base(component)
{
}

public override int ProcessOrder => -10000;
public override EditSkinnedMeshProcessorOrder ProcessOrder => EditSkinnedMeshProcessorOrder.AfterRemoveMesh;

public override void Process(OptimizerSession session, MeshInfo2 target, MeshInfo2Holder meshInfo2Holder)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System.Collections.Generic;
using System.Linq;
using UnityEditor;

namespace Anatawa12.AvatarOptimizer.Processors.SkinnedMeshes
{
internal class InternalAutoFreezeMeaninglessBlendShapeProcessor : EditSkinnedMeshProcessor<InternalAutoFreezeMeaninglessBlendShape>
{
public InternalAutoFreezeMeaninglessBlendShapeProcessor(InternalAutoFreezeMeaninglessBlendShape component) : base(component)
{
}

public override EditSkinnedMeshProcessorOrder ProcessOrder => EditSkinnedMeshProcessorOrder.AfterRemoveMesh;

public override void Process(OptimizerSession session, MeshInfo2 target, MeshInfo2Holder meshInfo2Holder)
{
var meaningfulBlendShapes = new HashSet<string>();

foreach (var vertex in target.Vertices)
foreach (var kvp in vertex.BlendShapes.Where(kvp => kvp.Value != default))
meaningfulBlendShapes.Add(kvp.Key);

var freezeBlendShape = Target.GetComponent<FreezeBlendShape>();
var serialized = new SerializedObject(freezeBlendShape);
var editorUtil = PrefabSafeSet.EditorUtil<string>.Create(
serialized.FindProperty(nameof(FreezeBlendShape.shapeKeysSet)),
0, p => p.stringValue, (p, v) => p.stringValue = v);
foreach (var (meaningLess, _) in target.BlendShapes.Where(x => !meaningfulBlendShapes.Contains(x.name)))
editorUtil.GetElementOf(meaningLess).EnsureAdded();
serialized.ApplyModifiedPropertiesWithoutUndo();
}

// nothing to do
public override IMeshInfoComputer GetComputer(IMeshInfoComputer upstream) => upstream;
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public MergeSkinnedMeshProcessor(MergeSkinnedMesh component) : base(component)

public override IEnumerable<SkinnedMeshRenderer> Dependencies => Component.renderersSet.GetAsList();

public override int ProcessOrder => int.MinValue;
public override EditSkinnedMeshProcessorOrder ProcessOrder => EditSkinnedMeshProcessorOrder.Generation;

public override void Process(OptimizerSession session, MeshInfo2 target, MeshInfo2Holder meshInfo2Holder)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public MergeToonLitMaterialProcessor(MergeToonLitMaterial component) : base(comp
{
}

public override int ProcessOrder => -10000;
public override EditSkinnedMeshProcessorOrder ProcessOrder => EditSkinnedMeshProcessorOrder.AfterRemoveMesh;

public override void Process(OptimizerSession session, MeshInfo2 target, MeshInfo2Holder meshInfo2Holder)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public RemoveMeshByBlendShapeProcessor(RemoveMeshByBlendShape component) : base(
}

// This needs to be less than FreezeBlendshapeProcessor.ProcessOrder.
public override int ProcessOrder => -10001;
public override EditSkinnedMeshProcessorOrder ProcessOrder => EditSkinnedMeshProcessorOrder.RemovingMesh;

public override void Process(OptimizerSession session, MeshInfo2 target, MeshInfo2Holder meshInfo2Holder)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public RemoveMeshInBoxProcessor(RemoveMeshInBox component) : base(component)
{
}

public override int ProcessOrder => -10000;
public override EditSkinnedMeshProcessorOrder ProcessOrder => EditSkinnedMeshProcessorOrder.RemovingMesh;

public override void Process(OptimizerSession session, MeshInfo2 target, MeshInfo2Holder meshInfo2Holder)
{
Expand Down
14 changes: 10 additions & 4 deletions Editor/Processors/TraceAndOptimize/AutoFreezeBlendShape.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,13 @@ public AutoFreezeBlendShape(AnimatorParser animator, OptimizerSession session)

public void Process()
{
// first optimization: unused blend shapes
foreach (var skinnedMeshRenderer in _session.GetComponents<SkinnedMeshRenderer>())
{
var mesh = skinnedMeshRenderer.sharedMesh;

// skip SMR without mesh
if (!mesh) continue;
// skip configured mesh
if (skinnedMeshRenderer.GetComponent<FreezeBlendShape>()) continue;

var modifies = _animator.GetModifiedProperties(skinnedMeshRenderer);
var blendShapeValues = Enumerable.Range(0, mesh.blendShapeCount)
Expand Down Expand Up @@ -53,7 +52,7 @@ public void Process()
skinnedMeshRenderer.SetBlendShapeWeight(i, blendShapeValues[i]);
EditorUtility.SetDirty(skinnedMeshRenderer);

var freeze = skinnedMeshRenderer.gameObject.AddComponent<FreezeBlendShape>();
var freeze = skinnedMeshRenderer.gameObject.GetOrAddComponent<FreezeBlendShape>();
var serialized = new SerializedObject(freeze);
var editorUtil = PrefabSafeSet.EditorUtil<string>.Create(
serialized.FindProperty(nameof(FreezeBlendShape.shapeKeysSet)),
Expand All @@ -62,6 +61,13 @@ public void Process()
editorUtil.GetElementOf(shape).EnsureAdded();
serialized.ApplyModifiedPropertiesWithoutUndo();
}

// second optimization: remove meaningless blendShapes
foreach (var skinnedMeshRenderer in _session.GetComponents<SkinnedMeshRenderer>())
{
skinnedMeshRenderer.gameObject.GetOrAddComponent<FreezeBlendShape>();
skinnedMeshRenderer.gameObject.GetOrAddComponent<InternalAutoFreezeMeaninglessBlendShape>();
}
}
}
}
}
7 changes: 7 additions & 0 deletions Editor/Utils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,13 @@ public static void FillArray<T>(T[] array, T value)
array[i] = value;
}

public static T GetOrAddComponent<T>(this GameObject go) where T : Component
{
var component = go.GetComponent<T>();
if (!component) component = go.AddComponent<T>();
return component;
}

public static Transform GetTarget(this VRCPhysBoneBase physBoneBase) =>
physBoneBase.rootTransform ? physBoneBase.rootTransform : physBoneBase.transform;

Expand Down
11 changes: 11 additions & 0 deletions Runtime/InternalAutoFreezeMeaninglessBlendShape.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using UnityEngine;

namespace Anatawa12.AvatarOptimizer
{
// TODO move to somewhere else? e.g. in editor module if possible
[AddComponentMenu("")]
[DisallowMultipleComponent]
internal class InternalAutoFreezeMeaninglessBlendShape : EditSkinnedMeshComponent
{
}
}
3 changes: 3 additions & 0 deletions Runtime/InternalAutoFreezeMeaninglessBlendShape.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 8b89959

Please sign in to comment.