Fix low-pass Simple1D blend trees are now ordered:
- Invoking WithAnimation on a Simple1D blend tree now always results in the list of ChildMotion being reordered by threshold. - This prevents an issue with Unity where it is unable to properly run a low-pass filter if the thresholds are stored in the array in the reverse order.
This commit is contained in:
@@ -43,9 +43,6 @@ namespace AnimatorAsCode.V1
|
|||||||
// Define this BlendTree as being Simple1D.
|
// Define this BlendTree as being Simple1D.
|
||||||
public AacFlBlendTree1D Simple1D(AacFlFloatParameter parameter)
|
public AacFlBlendTree1D Simple1D(AacFlFloatParameter parameter)
|
||||||
{
|
{
|
||||||
// FIXME: Simple 1D blend tree builders can be very capricious, as items inserted into it must be in the threshold order (???!!!)
|
|
||||||
// Change the API so that when items are added into the array, then it's sorted
|
|
||||||
|
|
||||||
BlendTree.blendType = BlendTreeType.Simple1D;
|
BlendTree.blendType = BlendTreeType.Simple1D;
|
||||||
BlendTree.blendParameter = parameter.Name;
|
BlendTree.blendParameter = parameter.Name;
|
||||||
BlendTree.useAutomaticThresholds = false;
|
BlendTree.useAutomaticThresholds = false;
|
||||||
@@ -138,32 +135,61 @@ namespace AnimatorAsCode.V1
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a BlendTree in the specified threshold. The last parameter overload is optional: by default, the timeScale is 1, cycle offset is 0, mirror is false.
|
// Add a BlendTree in the specified threshold. By default, the timeScale is 1, cycle offset is 0, mirror is false.
|
||||||
public AacFlBlendTree1D WithAnimation(AacFlBlendTree blendTree, float threshold, Action<AacFlBlendTreeChildMotion> furtherDefiningChild = null)
|
public AacFlBlendTree1D WithAnimation(AacFlBlendTree blendTree, float threshold)
|
||||||
{
|
{
|
||||||
// FIXME: Simple 1D blend tree builders can be very capricious, as items inserted into it must be in the threshold order (???!!!)
|
return WithAnimationInternal(blendTree.BlendTree, threshold, null);
|
||||||
// Change the API so that when items are added into the array, then it's sorted
|
|
||||||
return WithAnimation(blendTree.BlendTree, threshold, furtherDefiningChild);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a Clip in the specified threshold. The last parameter overload is optional: by default, the timeScale is 1, cycle offset is 0, mirror is false.
|
// Add a Clip in the specified threshold. By default, the timeScale is 1, cycle offset is 0, mirror is false.
|
||||||
public AacFlBlendTree1D WithAnimation(AacFlClip clip, float threshold, Action<AacFlBlendTreeChildMotion> furtherDefiningChild = null)
|
public AacFlBlendTree1D WithAnimation(AacFlClip clip, float threshold)
|
||||||
{
|
{
|
||||||
// FIXME: Simple 1D blend tree builders can be very capricious, as items inserted into it must be in the threshold order (???!!!)
|
return WithAnimationInternal(clip.Clip, threshold, null);
|
||||||
// Change the API so that when items are added into the array, then it's sorted
|
|
||||||
return WithAnimation(clip.Clip, threshold, furtherDefiningChild);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a raw motion in the specified threshold. The last parameter overload is optional: by default, the timeScale is 1, cycle offset is 0, mirror is false.
|
// Add a raw motion in the specified threshold. By default, the timeScale is 1, cycle offset is 0, mirror is false.
|
||||||
public AacFlBlendTree1D WithAnimation(Motion motion, float threshold, Action<AacFlBlendTreeChildMotion> furtherDefiningChild = null)
|
public AacFlBlendTree1D WithAnimation(Motion motion, float threshold)
|
||||||
|
{
|
||||||
|
return WithAnimationInternal(motion, threshold, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a BlendTree in the specified threshold, and further define that motion. By default, the timeScale is 1, cycle offset is 0, mirror is false.
|
||||||
|
public AacFlBlendTree1D WithAnimation(AacFlBlendTree blendTree, float threshold, Action<AacFlBlendTreeChildMotion> furtherDefiningChild)
|
||||||
|
{
|
||||||
|
// Disallow null here: as nulls are allowed in the internal function,
|
||||||
|
// we want to stop early if this specific non-null overload is invoked with a null param.
|
||||||
|
if (furtherDefiningChild == null) throw new NullReferenceException();
|
||||||
|
|
||||||
|
return WithAnimationInternal(blendTree.BlendTree, threshold, furtherDefiningChild);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a Clip in the specified threshold, and further define that motion. By default, the timeScale is 1, cycle offset is 0, mirror is false.
|
||||||
|
public AacFlBlendTree1D WithAnimation(AacFlClip clip, float threshold, Action<AacFlBlendTreeChildMotion> furtherDefiningChild)
|
||||||
|
{
|
||||||
|
// Disallow null here: as nulls are allowed in the internal function,
|
||||||
|
// we want to stop early if this specific non-null overload is invoked with a null param.
|
||||||
|
if (furtherDefiningChild == null) throw new NullReferenceException();
|
||||||
|
|
||||||
|
return WithAnimationInternal(clip.Clip, threshold, furtherDefiningChild);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a raw motion in the specified threshold, and further define that motion. By default, the timeScale is 1, cycle offset is 0, mirror is false.
|
||||||
|
public AacFlBlendTree1D WithAnimation(Motion motion, float threshold, Action<AacFlBlendTreeChildMotion> furtherDefiningChild)
|
||||||
|
{
|
||||||
|
// Disallow null here: as nulls are allowed in the internal function,
|
||||||
|
// we want to stop early if this specific non-null overload is invoked with a null param.
|
||||||
|
if (furtherDefiningChild == null) throw new NullReferenceException();
|
||||||
|
|
||||||
|
return WithAnimationInternal(motion, threshold, furtherDefiningChild);
|
||||||
|
}
|
||||||
|
|
||||||
|
private AacFlBlendTree1D WithAnimationInternal(Motion motion, float threshold, Action<AacFlBlendTreeChildMotion> furtherDefiningChildNullable)
|
||||||
{
|
{
|
||||||
// FIXME: Simple 1D blend tree builders can be very capricious, as items inserted into it must be in the threshold order (???!!!)
|
|
||||||
// Change the API so that when items are added into the array, then it's sorted
|
|
||||||
var children = BlendTree.children ?? new ChildMotion[0];
|
var children = BlendTree.children ?? new ChildMotion[0];
|
||||||
var childrenList = children.ToList();
|
var childrenList = children.ToList();
|
||||||
|
|
||||||
var childMotionModifier = new AacFlBlendTreeChildMotion();
|
var childMotionModifier = new AacFlBlendTreeChildMotion();
|
||||||
furtherDefiningChild?.Invoke(childMotionModifier);
|
furtherDefiningChildNullable?.Invoke(childMotionModifier);
|
||||||
childrenList.Add(new ChildMotion
|
childrenList.Add(new ChildMotion
|
||||||
{
|
{
|
||||||
motion = motion,
|
motion = motion,
|
||||||
@@ -172,7 +198,13 @@ namespace AnimatorAsCode.V1
|
|||||||
mirror = childMotionModifier.Mirror,
|
mirror = childMotionModifier.Mirror,
|
||||||
cycleOffset = childMotionModifier.CycleOffset
|
cycleOffset = childMotionModifier.CycleOffset
|
||||||
});
|
});
|
||||||
BlendTree.children = childrenList.ToArray();
|
BlendTree.children = childrenList
|
||||||
|
// 1D blend trees are capricious; if the thresholds are not in the correct order, the blend tree will:
|
||||||
|
// - misbehave at runtime as it might only blend in the 0th item no matter what
|
||||||
|
// - it will display in the animator UI in a confusing manner
|
||||||
|
// Sort the 1D blend tree to avoid this.
|
||||||
|
.OrderBy(childMotion => childMotion.threshold)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user