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, interactive objects and even environments.

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

Getting Started Video Guide

Dynamic Object Component

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 (Basic)

  • 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.

ID (Advanced)

See Advanced Dynamic Objects below.

  • Use Custom ID - This identifies a specific object.
  • Group Name - This will identify types of objects.

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'.

Advanced Dynamic Objects

Custom ID

IDs are not necessarily assigned in a consistent order. This is fine for many use cases; however, if you want to aggregate data across multiple play sessions, it is important to have consistent Custom IDs for specific objects. IDs 0-1000 are reserved for this purpose. You also need to upload a Manifest of all the Dynamic Objects in the scene.

Open Window > cognitiveVR > Update Dynamic Object Manifest...

object manifest

You may need to sign in again to get the current Object Manifest for your scene. This will display the number of new Dynamic Objects that are not included in the Manifest and the deleted Dynamic Objects that are in the Manifest but cannot be found in the scene.

Press Set Custom Ids to assign unique Ids to each object in your scene. Then press Update Existing Manifest to upload the Manifest with the new Dynamic Objects. You will rarely need to create a New Manifest - probably only when the scene changes significantly.

Group Name

Group Names are used to identify similar items. For example, if you have a number of interactive pink flamingos that share a Group Name, each will still behave as seperate unique objects. However, when you view heatmaps on any pink flamingo, it will show a heatmap aggregated from all pink flamingos heatmaps.

Note

Dynamic objects are stored with your scene, so you must export and upload your scene first. If you upload a new scene, you will have to re-upload your dynamic objects.

Add the Dynamic Object component to the gameobject you wish to track.

On the component, either:

  • Select a common controller mesh to use
  • Enable Use Custom Mesh, choose a mesh name and press Export. This will only export the Mesh Renderers found on the gameobject and its children

When you have exported all meshes you wish to use, select Window>cognitiveVR>Upload Dynamic Objects. You can re-upload dynamic objects to your scene, but there will be a delay before the new dynamic object replaces the old one.

Controller Inputs

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

controllers

This method has some advantages over sending controller inputs as transactions (using the Controller Input Component). First, the scene will not become cluttered with a sprite for each input event. Second, your Dashboard will not recieve these input transaction - without the context of where/when these input events happen, these transactions may be of limited value anyway.

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 a SteamVR_TrackedObject, SteamVR_TrackedController and Dynamic Object 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!

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 or anything else you can imagine.

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 ControllerGrabBegin(GameObject controllerGameObject)
{
    //begin Engagement
    var thisDynamic = GetComponent<CognitiveVR.DynamicObject>();
    var controllerDynamic = controllerGameObject.GetComponent<CognitiveVR.DynamicObject>();
    int id = -1;

    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 ControllerGrabEnd(GameObject controllerGameObject)
{
    //end Engagement
    var thisDynamic = GetComponent<CognitiveVR.DynamicObject>();
    var controllerDynamic = controllerGameObject.GetComponent<CognitiveVR.DynamicObject>();
    int id = -1;

    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

Code Reference

In most cases the options on the component will be sufficient. However, you can also send 'snapshots' of the dynamic object manually. This is mostly useful if you are not automatically updating the position and rotation using the 'Tick' coroutine. This can also be useful if you are setting custom parameters before sending the first snapshot.

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

    snap.UpdateTransform(); //updates the position of the dynamic object even if it hasn't moved beyond the threshold
    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. You won't need to modify this in almost any case
}

Example Use Cases

Multiplayer

The 'Remote Player' hmds and controllers should have the dynamic object component on them. Since there are many ways to implement multiplayer, please get in touch so we can discuss your project!

AI Characters

Add the Dynamic object component. Keep the default settings. Skinned Mesh Renderers can be exported in SDK version 0.6.2. If they are disabled or destroyed when they are defeated, they will disappear from SceneExplorer as expected.

Grabbable Objects

Add the Dynamic object component. Export a custom mesh. To track precise movements, we recommend lowering the Update Rate to 0.1 seconds, lowering the Position Threshold to 0.05 meters and Rotation Threshold to 10 degrees.

Controllers

Add the Dynamic object component. Just select a common mesh and you're good to go! You may want to check 'Sync with Player Update' and set the 'Position Threshold' and 'Rotation Threshold' very low.

Procedural Levels

For each prefab 'chunk' you can spawn, add a Dynamic Object component. Leave 'Snapshot On Enable' on and turn 'Update Ticks on Enable' off. This will only send one snapshot about the position and rotation of the 'chunk' when it is spawned into your scene.