Fix anim graph debugging to handle nested graph connections highlights properly

This commit is contained in:
Wojtek Figat
2024-02-07 19:22:07 +01:00
parent a38d1ad7cc
commit cfb8350c65
7 changed files with 67 additions and 20 deletions

View File

@@ -134,12 +134,7 @@ namespace FlaxEditor.Surface
// Follow input node contexts path to verify if it matches with the path in the event
var c = node.Context;
for (int i = nodePathSize - 1; i >= 0 && c != null; i--)
{
if (c.OwnerNodeID != nodePath[i])
c = null;
else
c = c.Parent;
}
c = c.OwnerNodeID == nodePath[i] ? c.Parent : null;
if (c != null)
{
traceEvent = e;

View File

@@ -33,6 +33,30 @@ namespace FlaxEditor.Surface
/// </summary>
public event Action<VisjectSurfaceContext> ContextChanged;
/// <summary>
/// Finds the surface context with the given owning nodes IDs path.
/// </summary>
/// <param name="nodePath">The node ids path.</param>
/// <returns>Found context or null if cannot.</returns>
public VisjectSurfaceContext FindContext(Span<uint> nodePath)
{
// Get size of the path
int nodePathSize = 0;
while (nodePathSize < nodePath.Length && nodePath[nodePathSize] != 0)
nodePathSize++;
// Follow each context path to verify if it matches with the path in the input path
foreach (var e in _contextCache)
{
var c = e.Value;
for (int i = nodePathSize - 1; i >= 0 && c != null; i--)
c = c.OwnerNodeID == nodePath[i] ? c.Parent : null;
if (c != null)
return e.Value;
}
return null;
}
/// <summary>
/// Creates the Visject surface context for the given surface data source context.
/// </summary>

View File

@@ -154,10 +154,11 @@ namespace FlaxEditor.Windows.Assets
}
[StructLayout(LayoutKind.Sequential)]
private struct AnimGraphDebugFlowInfo
private unsafe struct AnimGraphDebugFlowInfo
{
public uint NodeId;
public int BoxId;
public fixed uint NodePath[8];
}
private FlaxObjectRefPickerControl _debugPicker;
@@ -252,25 +253,26 @@ namespace FlaxEditor.Windows.Assets
return obj is AnimatedModel player && player.AnimationGraph == OriginalAsset;
}
private void OnDebugFlow(Asset asset, Object obj, uint nodeId, uint boxId)
private unsafe void OnDebugFlow(Animations.DebugFlowInfo flowInfo)
{
// Filter the flow
if (_debugPicker.Value != null)
{
if (asset != OriginalAsset || _debugPicker.Value != obj)
if (flowInfo.Asset != OriginalAsset || _debugPicker.Value != flowInfo.Instance)
return;
}
else
{
if (asset != Asset || _preview.PreviewActor != obj)
if (flowInfo.Asset != Asset || _preview.PreviewActor != flowInfo.Instance)
return;
}
// Register flow to show it in UI on a surface
var flowInfo = new AnimGraphDebugFlowInfo { NodeId = nodeId, BoxId = (int)boxId };
var flow = new AnimGraphDebugFlowInfo { NodeId = flowInfo.NodeId, BoxId = (int)flowInfo.BoxId };
Utils.MemoryCopy(new IntPtr(flow.NodePath), new IntPtr(flowInfo.NodePath0), sizeof(uint) * 8ul);
lock (_debugFlows)
{
_debugFlows.Add(flowInfo);
_debugFlows.Add(flow);
}
}
@@ -394,7 +396,7 @@ namespace FlaxEditor.Windows.Assets
}
/// <inheritdoc />
public override void OnUpdate()
public override unsafe void OnUpdate()
{
// Extract animations playback state from the events tracing
var debugActor = _debugPicker.Value as AnimatedModel;
@@ -413,7 +415,8 @@ namespace FlaxEditor.Windows.Assets
{
foreach (var debugFlow in _debugFlows)
{
var node = Surface.Context.FindNode(debugFlow.NodeId);
var context = Surface.FindContext(new Span<uint>(debugFlow.NodePath, 8));
var node = context?.FindNode(debugFlow.NodeId);
var box = node?.GetBox(debugFlow.BoxId);
box?.HighlightConnections();
}

View File

@@ -52,7 +52,7 @@ namespace
AnimationsService AnimationManagerInstance;
TaskGraphSystem* Animations::System = nullptr;
#if USE_EDITOR
Delegate<Asset*, ScriptingObject*, uint32, uint32> Animations::DebugFlow;
Delegate<Animations::DebugFlowInfo> Animations::DebugFlow;
#endif
AnimEvent::AnimEvent(const SpawnParams& params)
@@ -127,7 +127,7 @@ void AnimationsSystem::Execute(TaskGraph* graph)
#if USE_EDITOR
// If debug flow is registered, then warm it up (eg. static cached method inside DebugFlow_ManagedWrapper) so it doesn't crash on highly multi-threaded code
if (Animations::DebugFlow.IsBinded())
Animations::DebugFlow(nullptr, nullptr, 0, 0);
Animations::DebugFlow(Animations::DebugFlowInfo());
#endif
// Schedule work to update all animated models in async

View File

@@ -22,8 +22,25 @@ API_CLASS(Static) class FLAXENGINE_API Animations
API_FIELD(ReadOnly) static TaskGraphSystem* System;
#if USE_EDITOR
// Custom event that is called every time the Anim Graph signal flows over the graph (including the data connections). Can be used to read and visualize the animation blending logic. Args are: anim graph asset, animated object, node id, box id
API_EVENT() static Delegate<Asset*, ScriptingObject*, uint32, uint32> DebugFlow;
// Data wrapper for the debug flow information.
API_STRUCT(NoDefault) struct DebugFlowInfo
{
DECLARE_SCRIPTING_TYPE_MINIMAL(DebugFlowInfo);
// Anim Graph asset
API_FIELD() Asset* Asset = nullptr;
// Animated actor
API_FIELD() ScriptingObject* Instance = nullptr;
// Graph node id.
API_FIELD() uint32 NodeId = 0;
// Graph box id.
API_FIELD() uint32 BoxId = 0;
// Ids of graph nodes (call of hierarchy).
API_FIELD(Internal, NoArray) uint32 NodePath[8] = {};
};
// Custom event that is called every time the Anim Graph signal flows over the graph (including the data connections). Can be used to read and visualize the animation blending logic.
API_EVENT() static Delegate<DebugFlowInfo> DebugFlow;
#endif
/// <summary>

View File

@@ -425,7 +425,15 @@ VisjectExecutor::Value AnimGraphExecutor::eatBox(Node* caller, Box* box)
context.CallStack.Add(caller);
#if USE_EDITOR
Animations::DebugFlow(_graph._owner, context.Data->Object, box->GetParent<Node>()->ID, box->ID);
Animations::DebugFlowInfo flowInfo;
flowInfo.Asset = _graph._owner;
flowInfo.Instance = context.Data->Object;
flowInfo.NodeId = box->GetParent<Node>()->ID;
flowInfo.BoxId = box->ID;
const auto* nodePath = context.NodePath.Get();
for (int32 i = 0; i < context.NodePath.Count(); i++)
flowInfo.NodePath[i] = nodePath[i];
Animations::DebugFlow(flowInfo);
#endif
// Call per group custom processing event

View File

@@ -227,7 +227,7 @@ void AnimGraphExecutor::ProcessAnimation(AnimGraphImpulse* nodes, AnimGraphNode*
trace.Asset = anim;
trace.Value = animPos;
trace.NodeId = node->ID;
auto* nodePath = context.NodePath.Get();
const auto* nodePath = context.NodePath.Get();
for (int32 i = 0; i < context.NodePath.Count(); i++)
trace.NodePath[i] = nodePath[i];
}