Dynamic Objects

The dynamic object component allows you to track the position and state of gameobjects during the user's session. These can be used to track controllers, AI characters, and interactive objects.

This page will explain the different variables of the Dynamic Object component, provide code samples and outline example use cases.

Currently unsupported or work in progress

  • Visualizing material or texture changes on dynamic objects
  • Custom scale for dynamic objects (such as room scale) in SceneExplorer
  • Display custom properties on object snapshots

Basic Dynamic Object Options

  • Use Custom Mesh - Allows you to use a custom mesh with a certain name to represent this gameobject on SceneExplorer. This mesh can be used by many different dynamic object components.

  • Track Gaze on Dynamic Object - You must set a collider on this gameobject for the camera to correctly track the gaze on the object.

Controllers

The Dynamic Object component can easily track the player's controllers.

  1. Add a Dynamic Object component to the controller GameObject.
  2. Uncheck 'UseCustomMesh'.
  3. Choose the controller type from the dropdown menu.

Basics SceneExplorer management

A mesh representing a Dynamic Object is uploaded to SceneExplorer and saved to your scene. If you have multiple scenes, you will have to upload mesh data to each scene or version.

A default mesh name is chosen when you add a Dynamic Object component. Make sure you share mesh names between Dynamic Objects where appropriate. For example: multiple car gameobjects might have the mesh names "car","car (1)","car (2)",etc. If these all use the same mesh renderer and materials, simplify the mesh name to "car" to help SceneExplorer load quickly.

Gaze tracking on a Dynamic Object uses Physics raycasts. Make sure you have colliders and that the colliders closely represent the surface of the object to record accurate gaze data.

When you have added dynamic object components to everything you want, open the Manage Dynamic Objects window from the cognitive3D menu. It will show all the dynamic object components in the scene. There may be warnings about colliders for gaze tracking - this does not affect the mesh uploaded to scene explorer. Select Upload Selected or Upload All to export these meshes and upload them to your scene.

For a Dynamic Object to be aggregated across multiple sessions, you will have to upload a list of all the Dynamic Objects in your scene. This is done automatically when you upload Dynamic Object meshes. You can also press Save & Sync with Server in the Manage Dynamic Objects window.

Prefab Dynamic Objects

Having gameobject prefabs with dynamic object components works correctly with one exception - if you spawn multiple instances of one prefab, the ID used to identify it will be split between multiple instances and may not display correctly. In this case, it is important to uncheck 'UseCustomId'.

Aggregation over multiple sessions will not be calculated on dynamic objects that do not use custom ids.

Engagements

Custom Engagements allow you to record precise information about how a user manipulates the scene. An Engagement could represent a state such as grabbing an object, proximity to an object, pointing at an object, etc.

To begin or end an Engagement, call the BeginEngagement or EndEngagement function on the Dynamic Object component. The example below shows how you could implement an Engagement into a grab event - this will differ depending on how you implement your interactions.

void OnControllerGrabBegin(GameObject controllerGameObject)
{
    //begin Engagement
    var thisDynamic = GetComponent<CognitiveVR.DynamicObject>();
    var controllerDynamic = controllerGameObject.GetComponent<CognitiveVR.DynamicObject>();
    int id = -1;

    //including this id is optional. it is used to identify an engagement if there are multiple engagements with the same type occuring
    if (controllerDynamic != null && controllerDynamic.ObjectId != null) { id = controllerDynamic.ObjectId.Id; }
    if (thisDynamic != null) { thisDynamic.BeginEngagement("grab", id); }


    //your code to 'grab' the object
    transform.SetParent(controllerGameObject.transform);
}

void OnControllerGrabEnd(GameObject controllerGameObject)
{
    //end Engagement
    var thisDynamic = GetComponent<CognitiveVR.DynamicObject>();
    var controllerDynamic = controllerGameObject.GetComponent<CognitiveVR.DynamicObject>();
    int id = -1;

    //including this id is optional. it is used to identify an engagement if there are multiple engagements with the same type occuring
    if (controllerDynamic != null && controllerDynamic.ObjectId != null) { id = controllerDynamic.ObjectId.Id; }
    if (thisDynamic != null) { thisDynamic.EndEngagement("grab", id); }


    //your code to 'drop' the object
    transform.SetParent(null);
}

Engagement statistics will now be available on SceneExplorer for both aggregated viewing and session-by-session statistics.

engagementstats

Advanced Dynamic Objects

dynamic

Mesh

  • Common Mesh - These are common preset meshes. You do not need to export and upload meshes for these controllers.
  • Use Custom Mesh - Allows you to use a custom mesh with a certain name to represent this gameobject on SceneExplorer. See Exporting Dynamic Objects below.

Setup

  • Snapshot On Enable - Each time OnEnable is called in Unity, this will create a snapshot of the gameobject at the current position and rotation.
  • Update Ticks On Enable - This will start an automatic 'Tick' coroutine that will update the position and rotation of the object.
  • Track Gaze on Dynamic Object - This object will not ReleaseIdOnDisable or ReleaseIdOnDestroy. You must set a collider on this gameobject for the camera to correctly track the gaze on the object.

ID

  • Use Custom ID - This identifies a specific instance of an object.
  • Group Name - Group Names are used to identify similar items. If you have a number of dynamic objects that share a Group Name, each will still behave as seperate unique objects. However, when you can view heatmaps aggregated from all objects in the group.
  • Release ID OnDisable - Allow other dynamic objects to use this Id when this gameobject becomes disabled.
  • Release ID OnDestroy - Allow other dynamic objects to use this Id when this gameobject becomes destroyed.

Snapshot Threshold

  • Sync with Player Update - This is the 'Interval for Player Snapshots' in the Tracker Options Window.
  • Update Interval - Used if the 'Tick' coroutine on this object has been started. This delay before checking if the object moved beyond its threshold.
  • Position Threshold - Meters the object must move to write a new snapshot. Checked each 'Tick'.
  • Rotation Threshold - Degrees the object must rotate to write a new snapshot. Checked each 'Tick'.

By default a Dynamic Object will record lots of snapshots in high accuracy and in high frequency. On less important Dynamic Objects, you could set a larger Position Threshold and Rotation Threshold or Disable Sync with Player Update and set the Update Interval higher.

Controller Inputs

Dynamic Objects for controllers can display the user's inputs in a popup window in SceneExplorer.

controllers

Displaying controller inputs this way currently has some limitations:

  • Only Vive controllers are supported
  • A SteamVR_ControllerManager component must be present in your scene and have a reference to the left and right controllers
  • You must have SteamVR_TrackedObject, SteamVR_TrackedController and Dynamic Object components on the controller gameobject
  • The Dynamic Object must use the Vive Controller common mesh

It is recommended that you enable Sync with Player Update on the Dynamic Object so the recording will happen frequently. If all these requirements are met, displaying controller inputs happens automatically!

Code Reference

In almost every case the basic options on the component will be sufficient. However, you can also send 'snapshots' of the dynamic object manually.

void Start()
{
    var snap = GetComponent<CognitiveVR.DynamicObject>().NewSnapshot();

    snap.UpdateTransform(); //updates the position of the dynamic object
    snap.SetTick(false); //start or stop the Tick coroutine that tries to automatically update the position

    snap.SetProperties(Dictionary<string,object>(){{"key","value"}}); //you can add addititional information to snapshots. this is currently unused
    snap.SetEnabled(false); //show or hide the dynamic object. This is automatically disabled when the gameobject becomes disabled or destroyed. It is automatically enabled when the gameobject becomes enabled and SnapshotOnEnable is true
}