diff --git a/Editor/d4rkAvatarOptimizer.cs b/Editor/d4rkAvatarOptimizer.cs index e382247..b62f93d 100644 --- a/Editor/d4rkAvatarOptimizer.cs +++ b/Editor/d4rkAvatarOptimizer.cs @@ -43,6 +43,7 @@ public class Settings public bool NaNimationAllow3BoneSkinning = false; public bool MergeSkinnedMeshesSeparatedByDefaultEnabledState = true; public bool MergeStaticMeshesAsSkinned = true; + public bool MergePreferBodyOverVisemeMesh = false; public bool MergeDifferentPropertyMaterials = true; public bool MergeSameDimensionTextures = true; public bool MergeMainTex = false; @@ -220,6 +221,9 @@ public bool MergeSkinnedMeshesSeparatedByDefaultEnabledState { public bool MergeStaticMeshesAsSkinned { get { return settings.MergeSkinnedMeshes && settings.MergeStaticMeshesAsSkinned; } set { settings.MergeStaticMeshesAsSkinned = value; } } + public bool MergePreferBodyOverVisemeMesh { + get { return settings.MergeSkinnedMeshes && settings.MergePreferBodyOverVisemeMesh; } + set { settings.MergePreferBodyOverVisemeMesh = value; } } public bool MergeDifferentPropertyMaterials { get { return HasCustomShaderSupport && settings.MergeDifferentPropertyMaterials; } set { settings.MergeDifferentPropertyMaterials = value; } } @@ -282,6 +286,7 @@ public bool CanChangeSetting(string fieldName) {nameof(NaNimationAllow3BoneSkinning), "Allow 3 Bone Skinning"}, {nameof(MergeSkinnedMeshesSeparatedByDefaultEnabledState), "Keep Default Enabled State"}, {nameof(MergeStaticMeshesAsSkinned), "Merge Static Meshes as Skinned"}, + {nameof(MergePreferBodyOverVisemeMesh), "Prefer Merging into Body over Viseme Mesh"}, {nameof(MergeDifferentPropertyMaterials), "Merge Different Property Materials"}, {nameof(MergeSameDimensionTextures), "Merge Same Dimension Textures"}, {nameof(MergeMainTex), "Merge MainTex"}, @@ -318,6 +323,7 @@ public static string GetDisplayName(string fieldName) {nameof(Settings.NaNimationAllow3BoneSkinning), false}, {nameof(Settings.MergeSkinnedMeshesSeparatedByDefaultEnabledState), true}, {nameof(Settings.MergeStaticMeshesAsSkinned), false}, + {nameof(Settings.MergePreferBodyOverVisemeMesh), false}, {nameof(Settings.MergeDifferentPropertyMaterials), false}, {nameof(Settings.MergeSameDimensionTextures), false}, {nameof(Settings.MergeMainTex), false}, @@ -339,6 +345,7 @@ public static string GetDisplayName(string fieldName) {nameof(Settings.NaNimationAllow3BoneSkinning), false}, {nameof(Settings.MergeSkinnedMeshesSeparatedByDefaultEnabledState), true}, {nameof(Settings.MergeStaticMeshesAsSkinned), true}, + {nameof(Settings.MergePreferBodyOverVisemeMesh), false}, {nameof(Settings.MergeDifferentPropertyMaterials), true}, {nameof(Settings.MergeSameDimensionTextures), true}, {nameof(Settings.MergeMainTex), false}, @@ -360,6 +367,7 @@ public static string GetDisplayName(string fieldName) {nameof(Settings.NaNimationAllow3BoneSkinning), true}, {nameof(Settings.MergeSkinnedMeshesSeparatedByDefaultEnabledState), false}, {nameof(Settings.MergeStaticMeshesAsSkinned), true}, + {nameof(Settings.MergePreferBodyOverVisemeMesh), false}, {nameof(Settings.MergeDifferentPropertyMaterials), true}, {nameof(Settings.MergeSameDimensionTextures), true}, {nameof(Settings.MergeMainTex), true}, @@ -1032,13 +1040,24 @@ public List> FindPossibleSkinnedMeshMerges() { if (subList.Count == 1) continue; - int index = subList.FindIndex(smr => smr == avDescriptor?.VisemeSkinnedMesh); - if (index == -1) - { - var obj = subList.OrderBy(smr => GetPathToRoot(smr).Count(c => c == '/')) - .ThenByDescending(smr => smr.name == "Body" ? 1 : 0).First(); - index = subList.IndexOf(obj); + + int visemeMeshIndex = subList.FindIndex(smr => smr == avDescriptor?.VisemeSkinnedMesh); + int bodyMeshIndex = subList.FindIndex(smr => smr.name == "Body"); + int shallowestMeshIndex = subList.IndexOf(subList.OrderBy(smr => GetPathToRoot(smr).Count(c => c == '/')).First()); + + int index = shallowestMeshIndex; + if (settings.MergePreferBodyOverVisemeMesh) { + if (bodyMeshIndex >= 0) + index = bodyMeshIndex; + else if (visemeMeshIndex >= 0) + index = visemeMeshIndex; + } else { + if (visemeMeshIndex >= 0) + index = visemeMeshIndex; + else if (bodyMeshIndex >= 0) + index = bodyMeshIndex; } + var oldFirst = subList[0]; subList[0] = subList[index]; subList[index] = oldFirst; diff --git a/Editor/d4rkAvatarOptimizerEditor.cs b/Editor/d4rkAvatarOptimizerEditor.cs index f16c5d2..e876d6a 100644 --- a/Editor/d4rkAvatarOptimizerEditor.cs +++ b/Editor/d4rkAvatarOptimizerEditor.cs @@ -97,6 +97,7 @@ public override void OnInspectorGUI() ToggleOptimizerProperty(nameof(optimizer.MergeSkinnedMeshesSeparatedByDefaultEnabledState)); EditorGUI.indentLevel--; ToggleOptimizerProperty(nameof(optimizer.MergeStaticMeshesAsSkinned)); + ToggleOptimizerProperty(nameof(optimizer.MergePreferBodyOverVisemeMesh)); EditorGUI.indentLevel--; if (d4rkAvatarOptimizer.HasCustomShaderSupport) { diff --git a/README.md b/README.md index e2bea99..1ddbf5c 100644 --- a/README.md +++ b/README.md @@ -102,6 +102,8 @@ This is useful to not look weird with blocked animations in case of NaNimation t ## Merge Static Meshes as Skinned Automatically converts static meshes to skinned meshes so that they can be merged with other meshes and have their materials merged as well. This only happens if the static mesh has materials that can be merged with materials from the skinned mesh it tries to get merged into. Does not convert meshes on the UIMenu layer since they are mostly used for computation. +## Prefer Merging into Body over Viseme Mesh +By default, when merging meshes together, the Viseme mesh referenced in the VRC Avatar Descriptor will be prioritized as the merge target, followed by any mesh named "Body". Enable this setting to prefer merging into a "Body" mesh by default instead. This can be used to improve compatiblity with MMD worlds if your avatar contains a Body mesh and a separate viseme mesh. ## Merge Different Property Materials Merges materials with the same shader where properties can have different values. If they do have different values the values will get written to a constant buffer. Material IDs get written to uv.w and used to access the correct value from that cbuffer.