diff --git a/Source/Editor/Surface/Archetypes/Animation.cs b/Source/Editor/Surface/Archetypes/Animation.cs
index c659b475a..cbe9c3d85 100644
--- a/Source/Editor/Surface/Archetypes/Animation.cs
+++ b/Source/Editor/Surface/Archetypes/Animation.cs
@@ -28,6 +28,51 @@ namespace FlaxEditor.Surface.Archetypes
}
}
+ ///
+ /// Customized for Blend with Mask node.
+ ///
+ public class SkeletonMaskSample : SurfaceNode
+ {
+ private AssetSelect _assetSelect;
+ private Box _assetBox;
+
+ ///
+ public SkeletonMaskSample(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch)
+ : base(id, context, nodeArch, groupArch)
+ {
+ }
+
+ ///
+ public override void OnSurfaceLoaded(SurfaceNodeActions action)
+ {
+ base.OnSurfaceLoaded(action);
+
+ if (Surface != null)
+ {
+ _assetSelect = GetChild();
+
+ // 4 is the id of skeleton mask parameter node.
+ if (TryGetBox(4, out var box))
+ {
+ _assetBox = box;
+ _assetSelect.Visible = !_assetBox.HasAnyConnection;
+ }
+ }
+ }
+
+ ///
+ public override void ConnectionTick(Box box)
+ {
+ base.ConnectionTick(box);
+
+ if (_assetBox == null)
+ return;
+ if (box.ID != _assetBox.ID)
+ return;
+ _assetSelect.Visible = !box.HasAnyConnection;
+ }
+ }
+
///
/// Customized for the animation sampling nodes
///
@@ -76,7 +121,7 @@ namespace FlaxEditor.Surface.Archetypes
Title = _assetBox.HasAnyConnection || asset == null ? "Animation" : asset.ShortName;
else
Title = asset?.ShortName ?? "Animation";
-
+
var style = Style.Current;
Resize(Mathf.Max(230, style.FontLarge.MeasureText(Title).X + 30), 160);
}
@@ -524,7 +569,7 @@ namespace FlaxEditor.Surface.Archetypes
{
TypeID = 10,
Title = "Blend Additive",
- Description =
+ Description =
"Blend animation poses (with additive mode)" +
"\n" +
"\nNote: " +
@@ -552,6 +597,7 @@ namespace FlaxEditor.Surface.Archetypes
TypeID = 11,
Title = "Blend with Mask",
Description = "Blend animation poses using skeleton mask",
+ Create = (id, context, arch, groupArch) => new SkeletonMaskSample(id, context, arch, groupArch),
Flags = NodeFlags.AnimGraph,
Size = new Float2(180, 140),
DefaultValues = new object[]
@@ -565,7 +611,8 @@ namespace FlaxEditor.Surface.Archetypes
NodeElementArchetype.Factory.Input(0, "Pose A", true, typeof(void), 1),
NodeElementArchetype.Factory.Input(1, "Pose B", true, typeof(void), 2),
NodeElementArchetype.Factory.Input(2, "Alpha", true, typeof(float), 3, 0),
- NodeElementArchetype.Factory.Asset(0, 70, 1, typeof(SkeletonMask)),
+ NodeElementArchetype.Factory.Input(3, "Skeleton Mask Asset", true, typeof(SkeletonMask), 4),
+ NodeElementArchetype.Factory.Asset(0, Surface.Constants.LayoutOffsetY * 4, 1, typeof(SkeletonMask)),
}
},
new NodeArchetype
diff --git a/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp b/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp
index cdf1ebd84..d3b61c951 100644
--- a/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp
+++ b/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp
@@ -228,7 +228,7 @@ void AnimGraphExecutor::ProcessAnimation(AnimGraphImpulse* nodes, AnimGraphNode*
trace.Value = animPos;
trace.NodeId = node->ID;
}
-
+
// Evaluate nested animations
bool hasNested = false;
if (anim->NestedAnims.Count() != 0)
@@ -1131,6 +1131,17 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
{
const float alpha = Math::Saturate((float)tryGetValue(node->GetBox(3), node->Values[0]));
auto mask = node->Assets[0].As();
+ auto maskAssetBox = node->GetBox(4); // 4 is the id of skeleton mask parameter node.
+
+ // Check if have some mask asset connected with the mask node
+ if (maskAssetBox->HasConnection())
+ {
+ const Value assetBoxValue = tryGetValue(maskAssetBox, Value::Null);
+
+ // Use the mask connected with this node instead of default mask asset
+ if (assetBoxValue != Value::Null)
+ mask = (SkeletonMask*)assetBoxValue.AsAsset;
+ }
// Only A or missing/invalid mask
if (Math::NearEqual(alpha, 0.0f, ANIM_GRAPH_BLEND_THRESHOLD) || mask == nullptr || mask->WaitForLoaded())