From a3a43bd162ae7942c5fc8cd49b38919247b0f0cc Mon Sep 17 00:00:00 2001 From: yum Date: Wed, 19 Feb 2025 15:27:18 -0800 Subject: Begin cleaning up the dependent/independent splitting function --- Scripts/YOTSCore.cs | 318 ++++++++++++++++++++++++++-------------------------- 1 file changed, 158 insertions(+), 160 deletions(-) (limited to 'Scripts') diff --git a/Scripts/YOTSCore.cs b/Scripts/YOTSCore.cs index f0cb084..1716fd0 100644 --- a/Scripts/YOTSCore.cs +++ b/Scripts/YOTSCore.cs @@ -58,16 +58,6 @@ namespace YOTS } public ToggleSpec() {} - - public IEnumerable GetAffectedAttributes() { - foreach (var mesh in meshToggles) { - yield return $"MeshToggle:{mesh}"; - } - - foreach (var blend in blendShapes) { - yield return $"BlendShape:{blend.path}/{blend.blendShape}"; - } - } } [System.Serializable] @@ -188,6 +178,14 @@ namespace YOTS public class YOTSCore { private static Dictionary animationClips = new Dictionary(); + private static string GetMeshToggleAttributeId(string path) { + return "MeshToggle:" + path; + } + + private static string GetBlendShapeAttributeId(string path, string blendShape) { + return "BlendShape:" + path + "/" + blendShape; + } + public static AnimatorController GenerateAnimator(string configJson, VRCExpressionParameters vrcParams, VRCExpressionsMenu vrcMenu) { Debug.Log("=== Starting Animator Generation Process ==="); @@ -447,7 +445,6 @@ namespace YOTS var depthGroup = togglesByDepth[i]; AnimatorLayer layer = new AnimatorLayer(); layer.name = i == 0 ? "YOTS_BaseLayer" : $"YOTS_OverrideLayer{(i - 1).ToString("00")}"; - foreach (var toggle in depthGroup) { string paramName = toggle.name; if (!genAnimatorConfig.parameters.Any(p => p.name == paramName)) @@ -466,7 +463,6 @@ namespace YOTS parameter = paramName }); } - genAnimatorConfig.layers.Add(layer); } // Add animations @@ -518,6 +514,8 @@ namespace YOTS } private static GeneratedAnimatorConfig ApplyIndependentFixToAnimatorConfig(GeneratedAnimatorConfig genAnimatorConfig) { + // TODO meshToggles do not implement offValue/onValue at the JSON level, + // so this is redundant. float GetOffValueForMesh(string path, List offList) { var offToggle = offList?.FirstOrDefault(mt => mt.path == path); return offToggle != null ? offToggle.value : 0.0f; @@ -528,9 +526,9 @@ namespace YOTS return offBlend != null ? offBlend.value : 0.0f; } + // Create mapping from toggle name -> (on animation, off animation) Dictionary toggleAnimations = new Dictionary(); - foreach (var anim in genAnimatorConfig.animations) { if (anim.name.EndsWith("_On")) { string toggleName = anim.name.Substring(0, anim.name.LastIndexOf("_On")); @@ -557,19 +555,16 @@ namespace YOTS string entryName = entry.name; string toggleName = entryName; if (toggleName.EndsWith("_On")) - toggleName = toggleName.Substring(0, toggleName.LastIndexOf("_On")); + toggleName = toggleName.Substring(0, toggleName.Length - "_On".Length); else if (toggleName.EndsWith("_Off")) - toggleName = toggleName.Substring(0, toggleName.LastIndexOf("_Off")); - else if (toggleName.Contains("_Independent")) - toggleName = toggleName.Replace("_Independent", ""); - else if (toggleName.Contains("_Dependent")) - toggleName = toggleName.Replace("_Dependent", ""); - + toggleName = toggleName.Substring(0, toggleName.Length - "_Off".Length); if (!toggleToLayerIndex.ContainsKey(toggleName)) toggleToLayerIndex[toggleName] = i; } } + // Mapping from attribute touched by animation to the set of toggles + // which affect it. Dictionary> attributeToToggles = new Dictionary>(); foreach (var kvp in toggleAnimations) { string toggleName = kvp.Key; @@ -579,17 +574,16 @@ namespace YOTS HashSet attributes = new HashSet(); if (pair.on.meshToggles != null) { foreach (var mt in pair.on.meshToggles) { - string attr = "MeshToggle:" + mt.path; + string attr = GetMeshToggleAttributeId(mt.path); attributes.Add(attr); } } if (pair.on.blendShapes != null) { foreach (var bs in pair.on.blendShapes) { - string attr = "BlendShape:" + bs.path + "/" + bs.blendShape; + string attr = GetBlendShapeAttributeId(bs.path, bs.blendShape); attributes.Add(attr); } } - foreach (var attr in attributes) { if (!attributeToToggles.TryGetValue(attr, out var set)) { set = new HashSet(); @@ -599,6 +593,9 @@ namespace YOTS } } + // TODO assert that all toggles affecting the same attribute are on + // different layers. + List newAnimations = new List(); AnimatorLayer baseLayer = genAnimatorConfig.layers.FirstOrDefault(l => l.name == "BaseLayer"); @@ -608,157 +605,158 @@ namespace YOTS foreach (var kvp in toggleAnimations) { string toggleName = kvp.Key; var pair = kvp.Value; - int layerIndex = toggleToLayerIndex.ContainsKey(toggleName) ? toggleToLayerIndex[toggleName] : 0; - bool isBase = (layerIndex == 0); + int layerIndex = toggleToLayerIndex[toggleName]; - if (isBase) { + if (layerIndex == 0) { newAnimations.Add(pair.on); newAnimations.Add(pair.off); + continue; } - else { - List independentMesh = new List(); - List dependentMesh = new List(); - - if (pair.on.meshToggles != null) { - foreach (var mt in pair.on.meshToggles) { - string attr = "MeshToggle:" + mt.path; - if (attributeToToggles[attr].Count == 1) - independentMesh.Add(mt); - else - dependentMesh.Add(mt); - } - } - List independentBlend = new List(); - List dependentBlend = new List(); + // Work out which of the animation's mesh toggles are overrides and + // which are independent. + List independentMesh = new List(); + List dependentMesh = new List(); + if (pair.on.meshToggles != null) { + foreach (var mt in pair.on.meshToggles) { + string attr = GetMeshToggleAttributeId(mt.path); + if (attributeToToggles[attr].Count == 1) + independentMesh.Add(mt); + else + dependentMesh.Add(mt); + } + } - if (pair.on.blendShapes != null) { - foreach (var bs in pair.on.blendShapes) { - string attr = "BlendShape:" + bs.path + "/" + bs.blendShape; - if (attributeToToggles[attr].Count == 1) - independentBlend.Add(bs); - else - dependentBlend.Add(bs); - } + // Work out which of the animation's blendshapes are overrides and + // which are independent. + List independentBlend = new List(); + List dependentBlend = new List(); + if (pair.on.blendShapes != null) { + foreach (var bs in pair.on.blendShapes) { + string attr = GetBlendShapeAttributeId(bs.path, bs.blendShape); + if (attributeToToggles[attr].Count == 1) + independentBlend.Add(bs); + else + dependentBlend.Add(bs); } + } - bool hasIndependent = (independentMesh.Count > 0 || independentBlend.Count > 0); - bool hasDependent = (dependentMesh.Count > 0 || dependentBlend.Count > 0); - - if (hasIndependent && hasDependent) { - GeneratedAnimationClipConfig dependentOn = new GeneratedAnimationClipConfig(); - dependentOn.name = toggleName + "_Dependent_On"; - dependentOn.meshToggles = dependentMesh; - dependentOn.blendShapes = dependentBlend; - - GeneratedAnimationClipConfig dependentOff = new GeneratedAnimationClipConfig(); - dependentOff.name = toggleName + "_Dependent_Off"; - dependentOff.meshToggles = dependentMesh - .Select(mt => new GeneratedMeshToggle{ - path = mt.path, - value = GetOffValueForMesh(mt.path, pair.off.meshToggles) - }) - .ToList(); - dependentOff.blendShapes = dependentBlend - .Select(bs => new GeneratedBlendShape{ - path = bs.path, - blendShape = bs.blendShape, - value = GetOffValueForBlend(bs.path, bs.blendShape, pair.off.blendShapes) - }) - .ToList(); - - GeneratedAnimationClipConfig independentOn = new GeneratedAnimationClipConfig(); - independentOn.name = toggleName + "_Independent_On"; - independentOn.meshToggles = independentMesh; - independentOn.blendShapes = independentBlend; - - GeneratedAnimationClipConfig independentOff = new GeneratedAnimationClipConfig(); - independentOff.name = toggleName + "_Independent_Off"; - independentOff.meshToggles = independentMesh - .Select(mt => new GeneratedMeshToggle{ - path = mt.path, - value = GetOffValueForMesh(mt.path, pair.off.meshToggles) - }) - .ToList(); - independentOff.blendShapes = independentBlend - .Select(bs => new GeneratedBlendShape{ - path = bs.path, - blendShape = bs.blendShape, - value = GetOffValueForBlend(bs.path, bs.blendShape, pair.off.blendShapes) - }) - .ToList(); - - newAnimations.Add(dependentOn); - newAnimations.Add(dependentOff); - newAnimations.Add(independentOn); - newAnimations.Add(independentOff); - - AnimatorLayer overrideLayer = genAnimatorConfig.layers[layerIndex]; - foreach (var entry in overrideLayer.directBlendTree.entries) { - if (entry.name.StartsWith(toggleName) && - (entry.name.EndsWith("_On") || entry.name.EndsWith("_Off"))) { - entry.name = entry.name.EndsWith("_On") ? toggleName + "_Dependent_On" : toggleName + "_Dependent_Off"; - } - } + bool hasIndependent = (independentMesh.Count > 0 || independentBlend.Count > 0); + bool hasDependent = (dependentMesh.Count > 0 || dependentBlend.Count > 0); + + if (hasIndependent && hasDependent) { + GeneratedAnimationClipConfig dependentOn = new GeneratedAnimationClipConfig(); + dependentOn.name = toggleName + "_Dependent_On"; + dependentOn.meshToggles = dependentMesh; + dependentOn.blendShapes = dependentBlend; + + GeneratedAnimationClipConfig dependentOff = new GeneratedAnimationClipConfig(); + dependentOff.name = toggleName + "_Dependent_Off"; + dependentOff.meshToggles = dependentMesh + .Select(mt => new GeneratedMeshToggle{ + path = mt.path, + value = GetOffValueForMesh(mt.path, pair.off.meshToggles) + }) + .ToList(); + dependentOff.blendShapes = dependentBlend + .Select(bs => new GeneratedBlendShape{ + path = bs.path, + blendShape = bs.blendShape, + value = GetOffValueForBlend(bs.path, bs.blendShape, pair.off.blendShapes) + }) + .ToList(); - if (baseLayer != null) { - baseLayer.directBlendTree.entries.Add(new AnimatorDirectBlendTreeEntry{ - name = toggleName + "_Independent_On", - parameter = toggleName - }); - baseLayer.directBlendTree.entries.Add(new AnimatorDirectBlendTreeEntry{ - name = toggleName + "_Independent_Off", - parameter = toggleName - }); + GeneratedAnimationClipConfig independentOn = new GeneratedAnimationClipConfig(); + independentOn.name = toggleName + "_Independent_On"; + independentOn.meshToggles = independentMesh; + independentOn.blendShapes = independentBlend; + + GeneratedAnimationClipConfig independentOff = new GeneratedAnimationClipConfig(); + independentOff.name = toggleName + "_Independent_Off"; + independentOff.meshToggles = independentMesh + .Select(mt => new GeneratedMeshToggle{ + path = mt.path, + value = GetOffValueForMesh(mt.path, pair.off.meshToggles) + }) + .ToList(); + independentOff.blendShapes = independentBlend + .Select(bs => new GeneratedBlendShape{ + path = bs.path, + blendShape = bs.blendShape, + value = GetOffValueForBlend(bs.path, bs.blendShape, pair.off.blendShapes) + }) + .ToList(); + + newAnimations.Add(dependentOn); + newAnimations.Add(dependentOff); + newAnimations.Add(independentOn); + newAnimations.Add(independentOff); + + AnimatorLayer overrideLayer = genAnimatorConfig.layers[layerIndex]; + foreach (var entry in overrideLayer.directBlendTree.entries) { + if (entry.name.StartsWith(toggleName) && + (entry.name.EndsWith("_On") || entry.name.EndsWith("_Off"))) { + entry.name = entry.name.EndsWith("_On") ? toggleName + "_Dependent_On" : toggleName + "_Dependent_Off"; } } - else if (hasIndependent && !hasDependent) { - GeneratedAnimationClipConfig independentOn = new GeneratedAnimationClipConfig(); - independentOn.name = toggleName + "_Independent_On"; - independentOn.meshToggles = pair.on.meshToggles; - independentOn.blendShapes = pair.on.blendShapes; - GeneratedAnimationClipConfig independentOff = new GeneratedAnimationClipConfig(); - independentOff.name = toggleName + "_Independent_Off"; - independentOff.meshToggles = pair.off.meshToggles; - independentOff.blendShapes = pair.off.blendShapes; - - newAnimations.Add(independentOn); - newAnimations.Add(independentOff); - - AnimatorLayer overrideLayer = genAnimatorConfig.layers[layerIndex]; - overrideLayer.directBlendTree.entries.RemoveAll(e => e.name.StartsWith(toggleName)); - if (baseLayer != null) { - baseLayer.directBlendTree.entries.Add(new AnimatorDirectBlendTreeEntry{ - name = toggleName + "_Independent_On", - parameter = toggleName - }); - baseLayer.directBlendTree.entries.Add(new AnimatorDirectBlendTreeEntry{ - name = toggleName + "_Independent_Off", - parameter = toggleName - }); - } + + if (baseLayer != null) { + baseLayer.directBlendTree.entries.Add(new AnimatorDirectBlendTreeEntry{ + name = toggleName + "_Independent_On", + parameter = toggleName + }); + baseLayer.directBlendTree.entries.Add(new AnimatorDirectBlendTreeEntry{ + name = toggleName + "_Independent_Off", + parameter = toggleName + }); } - else if (!hasIndependent && hasDependent) { - GeneratedAnimationClipConfig dependentOn = new GeneratedAnimationClipConfig(); - dependentOn.name = toggleName + "_Dependent_On"; - dependentOn.meshToggles = pair.on.meshToggles; - dependentOn.blendShapes = pair.on.blendShapes; - GeneratedAnimationClipConfig dependentOff = new GeneratedAnimationClipConfig(); - dependentOff.name = toggleName + "_Dependent_Off"; - dependentOff.meshToggles = pair.off.meshToggles; - dependentOff.blendShapes = pair.off.blendShapes; - - newAnimations.Add(dependentOn); - newAnimations.Add(dependentOff); - - AnimatorLayer overrideLayer = genAnimatorConfig.layers[layerIndex]; - foreach (var entry in overrideLayer.directBlendTree.entries) { - if (entry.name.StartsWith(toggleName) && - (entry.name.EndsWith("_On") || entry.name.EndsWith("_Off"))) { - entry.name = entry.name.EndsWith("_On") ? toggleName + "_Dependent_On" : toggleName + "_Dependent_Off"; - } + } else if (hasIndependent) { + GeneratedAnimationClipConfig independentOn = new GeneratedAnimationClipConfig(); + independentOn.name = toggleName + "_Independent_On"; + independentOn.meshToggles = pair.on.meshToggles; + independentOn.blendShapes = pair.on.blendShapes; + GeneratedAnimationClipConfig independentOff = new GeneratedAnimationClipConfig(); + independentOff.name = toggleName + "_Independent_Off"; + independentOff.meshToggles = pair.off.meshToggles; + independentOff.blendShapes = pair.off.blendShapes; + + newAnimations.Add(independentOn); + newAnimations.Add(independentOff); + + AnimatorLayer overrideLayer = genAnimatorConfig.layers[layerIndex]; + overrideLayer.directBlendTree.entries.RemoveAll(e => e.name.StartsWith(toggleName)); + if (baseLayer != null) { + baseLayer.directBlendTree.entries.Add(new AnimatorDirectBlendTreeEntry{ + name = toggleName + "_Independent_On", + parameter = toggleName + }); + baseLayer.directBlendTree.entries.Add(new AnimatorDirectBlendTreeEntry{ + name = toggleName + "_Independent_Off", + parameter = toggleName + }); + } + } else if (hasDependent) { + GeneratedAnimationClipConfig dependentOn = new GeneratedAnimationClipConfig(); + dependentOn.name = toggleName + "_Dependent_On"; + dependentOn.meshToggles = pair.on.meshToggles; + dependentOn.blendShapes = pair.on.blendShapes; + GeneratedAnimationClipConfig dependentOff = new GeneratedAnimationClipConfig(); + dependentOff.name = toggleName + "_Dependent_Off"; + dependentOff.meshToggles = pair.off.meshToggles; + dependentOff.blendShapes = pair.off.blendShapes; + + newAnimations.Add(dependentOn); + newAnimations.Add(dependentOff); + + AnimatorLayer overrideLayer = genAnimatorConfig.layers[layerIndex]; + foreach (var entry in overrideLayer.directBlendTree.entries) { + if (entry.name.StartsWith(toggleName) && + (entry.name.EndsWith("_On") || entry.name.EndsWith("_Off"))) { + entry.name = entry.name.EndsWith("_On") ? toggleName + "_Dependent_On" : toggleName + "_Dependent_Off"; } } + } else { + throw new ArgumentException($"Toggle {toggleName} seems to have no animations."); } } -- cgit v1.2.3