Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
1b38083
Migrated interactivity work into UnityGLTF.
Jmangles May 12, 2025
0328bad
Removed some leftovers
Jmangles May 12, 2025
ce39293
Creation of BehaviourEngine and event/animation wrappers is now handl…
Jmangles May 13, 2025
bd478a3
Fix for debug log node getting eaten by the gitignore due to being in…
Jmangles May 14, 2025
1b7c392
Changed plugin names.
Jmangles May 14, 2025
b4c2c51
Removed unnecessary OnLoadComplete callback that was added.
Jmangles May 14, 2025
c457b92
Playback now supported for GLTF assets that are dragged into a scene …
Jmangles May 22, 2025
c106c13
Fixed issue with tests failing from the new debug/log schema.
Jmangles May 22, 2025
22a0b2e
Changed onSelect, onHoverIn, and onHoverOut to use the event system.
Jmangles May 27, 2025
83ff69b
Dragging in an interactive GLTF asset at runtime now works and immedi…
Jmangles May 28, 2025
ec39abb
Added safety for grabbing a number string in a node that goes above 64
Jmangles May 28, 2025
1c8da45
Colliders only get added to nodes/children of nodes that contain a se…
Jmangles May 29, 2025
5d274fa
Use MeshColliders instead of BoxColliders for selectable/hoverable no…
Jmangles May 30, 2025
8141209
Fix for editor-time exporting
Jmangles May 30, 2025
4e1a0f6
Fix for hoverability/selectability not working on export from playback
Jmangles May 30, 2025
0d730bf
Updated math/rotate3D to match new spec changes. Updated name of math…
Jmangles Jun 4, 2025
106e765
Added new quaternion nodes from spec update.
Jmangles Jun 9, 2025
30bfcd3
Added tests for quaternion conjugate, multiply, angle between, and to…
Jmangles Jun 11, 2025
282680a
Added tests for remaining quaternion nodes.
Jmangles Jun 11, 2025
3781bf5
Fixed description of a quat mul test.
Jmangles Jun 11, 2025
9deb5c1
Renamed "b" values in math/rotate2D and math/rotate3D to match newest…
Jmangles Jun 23, 2025
9fc86bd
Invalid pointers no longer throw.
Jmangles Jun 23, 2025
d007cef
Optimized node configuration to parse into its final type during the …
Jmangles Jun 24, 2025
1532a9b
Removed string from default types.
Jmangles Jun 24, 2025
b3079fb
Tests now generate with Unix line endings. Fixed math tests to only h…
Jmangles Jul 14, 2025
42573b1
Fix for any graphs exported with float2x2 values. Updated naming for …
Jmangles Aug 20, 2025
388a464
Added tests for matCompose and matDecompose. Fixed test graphs for ma…
Jmangles Sep 3, 2025
1e4d262
Fixed bug in node spec for matDecompose. Made matCompose and matDecom…
Jmangles Sep 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
8 changes: 8 additions & 0 deletions Editor/Scripts/Interactivity/Playback.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using UnityEngine;

using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine.UIElements;

namespace UnityGLTF.Interactivity.Playback
{
[CustomEditor(typeof(GLTFInteractivityAnimationWrapper))]
public class GLTFInteractivityAnimationWrapper_Inspector : Editor
{
public override void OnInspectorGUI()
{
EditorGUILayout.LabelField("Required to support animations during interactivity playback.");
EditorGUILayout.LabelField("Only works when this asset is imported with Legacy animation mode.");
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using UnityEngine;

using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine.UIElements;

namespace UnityGLTF.Interactivity.Playback
{
[CustomEditor(typeof(GLTFInteractivityData))]
public class GLTFInteractivityData_Inspector : Editor
{
public override void OnInspectorGUI()
{
EditorGUILayout.LabelField("Contains serialized data representing this GLTF's interactivity graph.");
EditorGUILayout.Space();
var data = (GLTFInteractivityData)target;
data.showData = EditorGUILayout.Toggle("Show Data", data.showData);

if (data.showData)
base.OnInspectorGUI();
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using UnityEngine;

using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine.UIElements;

namespace UnityGLTF.Interactivity.Playback
{
[CustomEditor(typeof(GLTFInteractivityPlayback))]
public class GLTFInteractivityPlayback_Inspector : Editor
{
public override void OnInspectorGUI()
{
EditorGUILayout.LabelField("Handles the onStart and onTick events for this interactive GLTF.");
EditorGUILayout.LabelField("Make sure colliders are enabled in the importer for hover/selection events.");
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "UnityGLTF.Interactivity.Playback.Editor",
"rootNamespace": "",
"references": [
"GUID:044607fd7a2ec4483a9d4a82c8ab78a7",
"GUID:b5e009300cbc0584fa5c0fa797ef4c5f"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file added Runtime/Resources/animation_test.bytes
Binary file not shown.
7 changes: 7 additions & 0 deletions Runtime/Resources/animation_test.bytes.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file added Runtime/Resources/pointer_test.bytes
Binary file not shown.
7 changes: 7 additions & 0 deletions Runtime/Resources/pointer_test.bytes.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Runtime/Scripts/GLTFSceneImporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -519,7 +519,7 @@ public void Dispose()

if (this.progress != null)
await Task.Yield();

onLoadComplete?.Invoke(LastLoadedScene, null);
}

Expand Down
8 changes: 8 additions & 0 deletions Runtime/Scripts/Interactivity/Playback.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

158 changes: 158 additions & 0 deletions Runtime/Scripts/Interactivity/Playback/BehaviourEngine.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Assertions;

namespace UnityGLTF.Interactivity.Playback
{
public class BehaviourEngine
{
public Graph graph { get; private set; }
public readonly Dictionary<Node, BehaviourEngineNode> engineNodes = new();
public GLTFInteractivityAnimationWrapper animationWrapper { get; private set; }
public readonly PointerInterpolationManager pointerInterpolationManager = new();
public readonly VariableInterpolationManager variableInterpolationManager = new();
public readonly NodeDelayManager nodeDelayManager = new();

public event Action onStart;

public event Action<RayArgs> onSelect;
public event Action<RayArgs> onHoverIn;
public event Action<RayArgs> onHoverOut;
public event Action onTick;
public event Action<int, Dictionary<string, IProperty>> onCustomEventFired;
public event Action<Flow> onFlowTriggered;

public PointerResolver pointerResolver { get; private set; }

public BehaviourEngine(Graph graph, PointerResolver pointerResolver)
{
this.graph = graph;
this.pointerResolver = pointerResolver;

for (int i = 0; i < graph.nodes.Count; i++)
{
engineNodes.Add(graph.nodes[i], NodeRegistry.CreateBehaviourEngineNode(this, graph.nodes[i]));
}
}

public void StartPlayback()
{
onStart?.Invoke();
}

public void Tick()
{
pointerInterpolationManager.OnTick();
variableInterpolationManager.OnTick();
nodeDelayManager.OnTick();

onTick?.Invoke();
}

public void Select(in RayArgs args)
{
onSelect?.Invoke(args);
}

public void HoverIn(in RayArgs args)
{
onHoverIn?.Invoke(args);
}

public void HoverOut(in RayArgs args)
{
onHoverOut?.Invoke(args);
}

public void ExecuteFlow(Flow flow)
{
Assert.IsNotNull(flow.toNode);

var node = engineNodes[flow.toNode];

onFlowTriggered?.Invoke(flow);

node.ValidateAndExecute(flow.toSocket);
}

public void FireCustomEvent(int eventIndex, Dictionary<string, IProperty> outValues = null)
{
if (eventIndex < 0 || eventIndex >= graph.customEvents.Count)
return; // TODO: Add error handling.

onCustomEventFired?.Invoke(eventIndex, outValues);
}

public IProperty ParseValue(Value v)
{
if (v.node == null)
return v.property;

var node = engineNodes[v.node];
return node.GetOutputValue(v.socket);
}

public IProperty GetVariableProperty(int variableIndex)
{
return graph.variables[variableIndex].property;
}

public bool TryGetPointer(string pointerString, BehaviourEngineNode engineNode, out IPointer pointer)
{
try
{
pointer = pointerResolver.GetPointer(pointerString, engineNode);
}
catch (Exception ex)
{
Debug.LogException(ex); // Feeding in a really malformed pointerString could throw maybe?

pointer = PointerHelpers.InvalidPointer();
}
return !pointer.invalid;
}

public void SetAnimationWrapper(GLTFInteractivityAnimationWrapper wrapper, Animation animation)
{
animationWrapper = wrapper;
wrapper.SetData(this, animation);
pointerResolver.CreateAnimationPointers(wrapper);
}

public void PlayAnimation(in AnimationPlayData data)
{
if (!HasAnimationWrapper())
return;

animationWrapper.PlayAnimation(data);
}

public void StopAnimation(int index)
{
if (!HasAnimationWrapper())
return;

animationWrapper.StopAnimation(index);
}

public void StopAnimationAt(int index, float stopTime, Action callback)
{
if (!HasAnimationWrapper())
return;

animationWrapper.StopAnimationAt(index, stopTime, callback);
}

public bool HasAnimationWrapper()
{
if (animationWrapper == null)
{
Util.LogWarning("Tried to play an animation on a glb that has no animations.");
return false;
}

return true;
}
}
}
11 changes: 11 additions & 0 deletions Runtime/Scripts/Interactivity/Playback/BehaviourEngine.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading