Skip to content

Commit

Permalink
fix(parameter-slot): prevent flickering by switching between control …
Browse files Browse the repository at this point in the history
…states directly
  • Loading branch information
poi-vrc committed May 6, 2024
1 parent 797d786 commit 06e28a4
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 11 deletions.
81 changes: 70 additions & 11 deletions Editor/Animations/SmartControlComposer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,24 @@ internal class SmartControlComposer
private const string VRCPhysBoneStretchSuffix = "_Stretch";
private const string VRCPhysBoneSquishSuffix = "_Squish";

private class ParameterSlotLayerInfo
{
public AnimatorLayerBuilder layer;
public AnimatorStateBuilder entryState;
public Dictionary<DTSmartControl, AnimatorStateBuilder> scEnabledStates;
public Dictionary<DTSmartControl, AnimatorStateBuilder> scPrepareDisabledStates;

public ParameterSlotLayerInfo()
{
layer = null;
entryState = null;
scEnabledStates = new Dictionary<DTSmartControl, AnimatorStateBuilder>();
scPrepareDisabledStates = new Dictionary<DTSmartControl, AnimatorStateBuilder>();
}
}

private readonly HashSet<DTSmartControl> _controls;
private readonly Dictionary<DTParameterSlot, Tuple<AnimatorLayerBuilder, AnimatorStateBuilder>> _parameterSlotLayers;
private readonly Dictionary<DTParameterSlot, ParameterSlotLayerInfo> _parameterSlotLayerInfos;
private readonly AnimatorOptions _options;
private readonly AnimatorController _controller;

Expand All @@ -44,7 +60,7 @@ public SmartControlComposer(AnimatorOptions options, AnimatorController controll
_options = options;
_controller = controller;
_controls = new HashSet<DTSmartControl>();
_parameterSlotLayers = new Dictionary<DTParameterSlot, Tuple<AnimatorLayerBuilder, AnimatorStateBuilder>>();
_parameterSlotLayerInfos = new Dictionary<DTParameterSlot, ParameterSlotLayerInfo>();
}

private void AddParameterConfig(Transform transform, string parameterName, float defaultValue, bool networkSynced, bool saved)
Expand Down Expand Up @@ -105,11 +121,11 @@ private void HandleDriverMenuItem(DTSmartControl ctrl)
}
}

private Tuple<AnimatorLayerBuilder, AnimatorStateBuilder> PrepareOrGetParameterSlotLayer(DTParameterSlot parameterSlot)
private ParameterSlotLayerInfo PrepareOrGetParameterSlotLayer(DTParameterSlot parameterSlot)
{
if (_parameterSlotLayers.ContainsKey(parameterSlot))
if (_parameterSlotLayerInfos.ContainsKey(parameterSlot))
{
return _parameterSlotLayers[parameterSlot];
return _parameterSlotLayerInfos[parameterSlot];
}

// generate parameter name
Expand Down Expand Up @@ -143,7 +159,11 @@ private Tuple<AnimatorLayerBuilder, AnimatorStateBuilder> PrepareOrGetParameterS
animator.FloatParameter(parameterSlot.ParameterName, parameterSlot.ParameterDefaultValue);
}

return _parameterSlotLayers[parameterSlot] = new Tuple<AnimatorLayerBuilder, AnimatorStateBuilder>(layer, entryState);
return _parameterSlotLayerInfos[parameterSlot] = new ParameterSlotLayerInfo()
{
layer = layer,
entryState = entryState
};
}

private void HandleDriverParameterSlot(DTSmartControl ctrl)
Expand All @@ -156,9 +176,9 @@ private void HandleDriverParameterSlot(DTSmartControl ctrl)
}

// prepare and get value slot anystate layer
var tuple = PrepareOrGetParameterSlotLayer(parameterSlot);
var layer = tuple.Item1;
var entryState = tuple.Item2;
var info = PrepareOrGetParameterSlotLayer(parameterSlot);
var layer = info.layer;
var entryState = info.entryState;

// generate menu item
if (ctrl.ParameterSlotConfig.GenerateMenuItem)
Expand Down Expand Up @@ -195,17 +215,51 @@ private void HandleDriverParameterSlot(DTSmartControl ctrl)

var enabledState = layer.NewState($"{ctrl.name} Enabled");
var prepareDisabledState = layer.NewState($"{ctrl.name} Prepare Disabled");
info.scEnabledStates[ctrl] = enabledState;
info.scPrepareDisabledStates[ctrl] = prepareDisabledState;

entryState.AddTransition(enabledState)
.Equals(parameterSlot.ParameterName, ctrl.ParameterSlotConfig.MappedValue);
enabledState.AddTransition(prepareDisabledState)
.NotEquals(parameterSlot.ParameterName, ctrl.ParameterSlotConfig.MappedValue);
prepareDisabledState.AddTransition(entryState)
.NotEquals(parameterSlot.ParameterName, ctrl.ParameterSlotConfig.MappedValue);
// we add the condition to entry state in FillParameterSlotInterControlTransitions
// to prioritize switching between control states instead

ComposeBinaryToggles(_controller, prepareDisabledState, enabledState, ctrl);
}

private void FillParameterSlotInterControlTransitions()
{
// this fills conditions in each controls' state to allow
// switching to each other directly without going to entry state
foreach (var psKvp in _parameterSlotLayerInfos)
{
var parameterSlot = psKvp.Key;
var info = psKvp.Value;
foreach (var prepareDisabledKvp in info.scPrepareDisabledStates)
{
var ctrl = prepareDisabledKvp.Key;
var prepareDisabledState = prepareDisabledKvp.Value;

foreach (var enabledKvp in info.scEnabledStates)
{
var anotherCtrl = enabledKvp.Key;
var enabledState = enabledKvp.Value;
if (anotherCtrl == ctrl)
{
continue;
}
prepareDisabledState.AddTransition(enabledState)
.Equals(parameterSlot.ParameterName, anotherCtrl.ParameterSlotConfig.MappedValue);
}

// only if no conditions match, it falls back to entry state
prepareDisabledState.AddTransition(info.entryState)
.NotEquals(parameterSlot.ParameterName, ctrl.ParameterSlotConfig.MappedValue);
}
}
}

private string VRCPhysBoneDataSourceToParam(string prefix, DTSmartControl.SCVRCPhysBoneDriverConfig.DataSource source)
{
if (source == DTSmartControl.SCVRCPhysBoneDriverConfig.DataSource.Angle)
Expand Down Expand Up @@ -340,6 +394,11 @@ public void Compose(DTSmartControl ctrl)
// EditorUtility.SetDirty(ctrl.Controller);
}

public void Finish()
{
FillParameterSlotInterControlTransitions();
}

private void ComposeBinary(DTSmartControl ctrl, List<string> conditionalParams)
{
if (HasCrossControlCycle(ctrl))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ public override bool Invoke(Context ctx)
{
composer.Compose(ctrl);
}
composer.Finish();

EditorUtility.SetDirty(fx);

Expand Down

0 comments on commit 06e28a4

Please sign in to comment.