fix: occasionally objects controlling reactive components "flicker" (#1298)

Reported-by: @whipnice
This commit is contained in:
bd_ 2024-10-19 17:15:14 -07:00 committed by GitHub
parent 3ba0219430
commit ae975506d7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -1,9 +1,11 @@
using System.Linq; using System.Linq;
using nadena.dev.modular_avatar.core.editor;
using nadena.dev.ndmf; using nadena.dev.ndmf;
using UnityEditor; using UnityEditor;
using UnityEditor.Animations; using UnityEditor.Animations;
using UnityEngine; using UnityEngine;
using VRC.SDK3.Avatars.Components; using VRC.SDK3.Avatars.Components;
using BuildContext = nadena.dev.ndmf.BuildContext;
namespace nadena.dev.modular_avatar.animation namespace nadena.dev.modular_avatar.animation
{ {
@ -23,11 +25,16 @@ namespace nadena.dev.modular_avatar.animation
if (fx == null) return; if (fx == null) return;
var nullMotion = new AnimationClip();
nullMotion.name = "NullMotion";
var blendTree = new BlendTree(); var blendTree = new BlendTree();
blendTree.blendType = BlendTreeType.Direct; blendTree.blendType = BlendTreeType.Direct;
blendTree.useAutomaticThresholds = false; blendTree.useAutomaticThresholds = false;
blendTree.children = asc.BoundReadableProperties.Select(GenerateDelayChild).ToArray(); blendTree.children = asc.BoundReadableProperties
.Select(prop => GenerateDelayChild(nullMotion, prop))
.ToArray();
var asm = new AnimatorStateMachine(); var asm = new AnimatorStateMachine();
var state = new AnimatorState(); var state = new AnimatorState();
@ -54,7 +61,7 @@ namespace nadena.dev.modular_avatar.animation
}).ToArray(); }).ToArray();
} }
private ChildMotion GenerateDelayChild((EditorCurveBinding, string) binding) private ChildMotion GenerateDelayChild(Motion nullMotion, (EditorCurveBinding, string) binding)
{ {
var ecb = binding.Item1; var ecb = binding.Item1;
var prop = binding.Item2; var prop = binding.Item2;
@ -64,10 +71,40 @@ namespace nadena.dev.modular_avatar.animation
curve.AddKey(0, 1); curve.AddKey(0, 1);
AnimationUtility.SetEditorCurve(motion, ecb, curve); AnimationUtility.SetEditorCurve(motion, ecb, curve);
// Occasionally, we'll have a very small value pop up, probably due to FP errors.
// To correct for this, instead of directly using the property in the direct blend tree,
// we'll use a 1D blend tree to give ourselves a buffer.
var bufferBlendTree = new BlendTree();
bufferBlendTree.blendType = BlendTreeType.Simple1D;
bufferBlendTree.useAutomaticThresholds = false;
bufferBlendTree.blendParameter = prop;
bufferBlendTree.children = new[]
{
new ChildMotion
{
motion = nullMotion,
timeScale = 1,
threshold = 0
},
new ChildMotion
{
motion = nullMotion,
timeScale = 1,
threshold = 0.01f
},
new ChildMotion
{
motion = motion,
timeScale = 1,
threshold = 1
}
};
return new ChildMotion return new ChildMotion
{ {
motion = motion, motion = bufferBlendTree,
directBlendParameter = prop, directBlendParameter = MergeBlendTreePass.ALWAYS_ONE,
timeScale = 1 timeScale = 1
}; };
} }