Skip to content

Commit

Permalink
Add option to keep MMD blendshapes intact #32
Browse files Browse the repository at this point in the history
  • Loading branch information
d4rkc0d3r committed Apr 16, 2023
1 parent 4ef99b8 commit f35a08e
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 8 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
## Next Version
### Features
* Add option to keep MMD blendshapes intact. [(more)](https://github.com/d4rkc0d3r/d4rkAvatarOptimizer/issues/32)

### Bug Fixes
* Apparently `sampler` is also a way to declare a `SamplerState`. So now the optimizer also replaces those.
* Parse and ignore const keyword in shader function parameters.
Expand Down
85 changes: 78 additions & 7 deletions Editor/d4rkAvatarOptimizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public class d4rkAvatarOptimizer : MonoBehaviour
public bool MergeSameDimensionTextures = true;
public bool MergeBackFaceCullingWithCullingOff = false;
public bool MergeDifferentRenderQueue = false;
public bool KeepMMDBlendShapes = false;
public bool DeleteUnusedComponents = true;
public bool DeleteUnusedGameObjects = false;
public bool MergeSimpleTogglesAsBlendTree = true;
Expand Down Expand Up @@ -145,6 +146,66 @@ public void Optimize()
private static HashSet<string> convertedMeshRendererPaths = new HashSet<string>();
private static Dictionary<Transform, Transform> movingParentMap = new Dictionary<Transform, Transform>();
private static Dictionary<string, Transform> transformFromOldPath = new Dictionary<string, Transform>();
// blendshape names come from https://www.deviantart.com/xoriu/art/MMD-Facial-Expressions-Chart-341504917
private static HashSet<string> MMDBlendShapes = new HashSet<string>()
{
"まばたき", "Blink",
"笑い", "Smile",
"ウィンク", "Wink",
"ウィンク右", "Wink-a",
"ウィンク2", "Wink-b",
"ウィンク2右", "Wink-c",
"なごみ", "Howawa",
"はぅ", "> <",
"びっくり", "Ha!!!",
"じと目", "Jito-eye",
"キリッ", "Kiri-eye",
"はちゅ目", "O O",
"星目", "EyeStar",
"はぁと", "EyeHeart",
"瞳小", "EyeSmall",
"瞳縦潰れ", "EyeSmall-v",
"光下", "EyeUnderli",
"恐ろしい子!", "EyeFunky",
"ハイライト消", "EyeHi-off",
"映り込み消", "EyeRef-off",
"喜び", "Joy",
"わぉ?!", "Wao?!",
"なごみω", "Howawa ω",
"悲しむ", "Wail",
"敵意", "Hostility",
"", "a",
"", "i",
"", "u",
"", "e",
"", "o",
"あ2", "a 2",
"", "n",
"", "Mouse_1",
"", "Mouse_2",
"", "",
"", "Wa",
"ω", "Omega",
"ω□", "ω□",
"にやり", "Niyari",
"にやり2", "Niyari2",
"にっこり", "Smile",
"ぺろっ", "Pero",
"てへぺろ", "Bero-tehe",
"てへぺろ2", "Bero-tehe2",
"口角上げ", "MouseUP",
"口角下げ", "MouseDW",
"口横広げ", "MouseWD",
"歯無し上", "ToothAnon",
"歯無し下", "ToothBnon",
"真面目", "Serious",
"困る", "Trouble",
"にこり", "Smily",
"怒り", "Get angry",
"", "UP",
"", "Down",
};

private static float progressBar = 0;

private void DisplayProgressBar(string text)
Expand Down Expand Up @@ -992,21 +1053,28 @@ public void CalculateUsedBlendShapePaths()
var mesh = skinnedMeshRenderer.sharedMesh;
if (mesh == null)
continue;
var blendShapeIDs = new List<int>();
blendShapesToBake[skinnedMeshRenderer] = blendShapeIDs;
var blendShapeIDsToBake = new List<int>();
blendShapesToBake[skinnedMeshRenderer] = blendShapeIDsToBake;
string path = GetPathToRoot(skinnedMeshRenderer) + "/blendShape.";
for (int i = 0; i < mesh.blendShapeCount; i++)
{
if (skinnedMeshRenderer.GetBlendShapeWeight(i) != 0 && !usedBlendShapes.Contains(path + mesh.GetBlendShapeName(i)))
var name = mesh.GetBlendShapeName(i);
if (KeepMMDBlendShapes && MMDBlendShapes.Contains(name))
{
usedBlendShapes.Add(path + name);
hasUsedBlendShapes.Add(skinnedMeshRenderer);
continue;
}
if (skinnedMeshRenderer.GetBlendShapeWeight(i) != 0 && !usedBlendShapes.Contains(path + name))
{
if (mesh.GetBlendShapeFrameCount(i) > 1)
{
usedBlendShapes.Add(path + mesh.GetBlendShapeName(i));
usedBlendShapes.Add(path + name);
hasUsedBlendShapes.Add(skinnedMeshRenderer);
}
else
{
blendShapeIDs.Add(i);
blendShapeIDsToBake.Add(i);
}
}
}
Expand Down Expand Up @@ -1037,10 +1105,13 @@ public List<List<(string blendshape, float value)>> FindMergeableBlendShapes(IEn
string path = GetPathToRoot(skinnedMeshRenderer) + "/blendShape.";
for (int i = 0; i < mesh.blendShapeCount; i++)
{
var name = mesh.GetBlendShapeName(i);
if (KeepMMDBlendShapes && MMDBlendShapes.Contains(name))
continue;
if (mesh.GetBlendShapeFrameCount(i) == 1)
{
validPaths.Add(path + mesh.GetBlendShapeName(i));
ratios[0][path + mesh.GetBlendShapeName(i)] = skinnedMeshRenderer.GetBlendShapeWeight(i);
validPaths.Add(path + name);
ratios[0][path + name] = skinnedMeshRenderer.GetBlendShapeWeight(i);
}
}
}
Expand Down
1 change: 1 addition & 0 deletions Editor/d4rkAvatarOptimizerEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -926,6 +926,7 @@ public override void OnInspectorGUI()
GUI.enabled = true;
Toggle("Merge Same Ratio Blend Shapes", ref optimizer.MergeSameRatioBlendShapes);
Toggle("Merge Simple Toggles as BlendTree", ref optimizer.MergeSimpleTogglesAsBlendTree);
Toggle("Keep MMD Blend Shapes", ref optimizer.KeepMMDBlendShapes);
Toggle("Delete Unused Components", ref optimizer.DeleteUnusedComponents);
Toggle("Delete Unused GameObjects", ref optimizer.DeleteUnusedGameObjects);
Toggle("Use Ring Finger as Foot Collider", ref optimizer.UseRingFingerAsFootCollider);
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ For example you have two animations. The first animates `A` to 100, `B` to 50 an
## Merge Simple Toggles as BlendTree
Tries to find layers in the FXLayer that have exactly two states with one transition each that has a simple bool condition. The optimizer will then merge all layers like that into one by using a large direct blend tree.
You can read about this technique [here](https://notes.sleightly.dev/dbt-combining/).
## Keep MMD Blend Shapes
When enabled the optimizer will keep the blend shapes that are used by MMD animations from getting removed or merged.
## Delete Unused Components
Deletes all components that are turned off and never get enabled by animations. It also deletes phys bone colliders that are not referenced by any used phys bone components.
## Delete Unused Game Objects
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "d4rkpl4y3r.d4rkavataroptimizer",
"displayName": "d4rkAvatarOptimizer",
"version": "2.0.1",
"version": "2.1.0-alpha.0",
"unity": "2019.4",
"description": "An optimizer aiming to reduce mesh & material count and more of VRChat 3.0 avatars.",
"dependencies": {},
Expand Down

0 comments on commit f35a08e

Please sign in to comment.