Fix anim graph debugging to handle nested graph connections highlights properly
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user