Skip to main content

Odal



Odal provides a data type, AssetInstance, that extends the semantics of an Entity. Like an Entity, an AssetInstance is owned by a specific participant and can only be acted on by that participant.

An AssetInstance is created by selecting an Entity and a .glb asset stored in the aukiverse console .glb asset store. Upon instantiation, Odal downloads the .glb and generates a parent-child pair of game objects, with the child carrying the mesh, rotated 180° such as to be front-facing to the session host's original front-facing direction by default. (As the asset is typically being spawned in front of the user). The asset store also allows to store a custom scale associated with the asset that is placed on the parent game object. The parent of the resulting parent-child pair can be obtained via Odal's GetUnmanagedGameObject() method.

The pose of the parent game object is driven by the pose of the associated Entity. Thus, the initial pose of the asset must be controlled by setting the pose of the associated Entity.

A copy of the same parent-child pair is instantiated for every participant. A participant can invoke GetUnmanagedGameObject() for an AssetInstance whose Entity it does not own, but note that it only gets a pointer to its local copy of the game object.

Predefined animations contained in the .glb file can be set and unset via Odal's Animate() method by the participant owning that AssetInstance. Animations set via Odal's API in this manner are automatically synchronized across all participants, with network lag taken into account.

Basic usage

Import the Odal module

using Auki.ConjureKit.Odal;

Initialize the Odal module

The Odal module depends on the Vikja module besides depending on ConjureKit.

Moreover, Odal initialization involves an async portion that is encapsulated in a separate function, Odal.Init(). Odal's Instantiate() function should only be called after both Odal.Init() and IConjureKit.Connect() has finished running. One way to achieve this is by using the OnJoined callback of the IConjureKit interface, which is called after every successful connection to a new server:

public class Demo : MonoBehaviour
{
private IConjureKit _conjureKit;
private Vikja _vikja;
private Odal _odal;

private void Start()
{
var config = AukiConfiguration.Get();
_conjureKit = new ConjureKit(config, cameraTransform, "app_key", "app_secret");
_vikja = new Vikja(_conjureKit);

_conjureKit.OnJoined += () => _odal.Instantiate(...);

_odal.Init(() => _conjureKit.Connect());
}
}

In the above code sample, _odal.Instantiate(...) may be replaced with arbitrary logic to be executed upon Session-joining.

Note that Odal destroys all AssetInstances alongside all associated parent-child game object pairs when leaving a Session.

Instantiate an AssetInstance

Assuming that ASSET_ID is the id of a .glb file uploaded to the asset store under your current app key, the following code example showcases instantiation logic:

_conjureKit.AddEntity(
new Pose(new Vector3(0, 0, 1), Quaternion.Euler(0, 20, 0)),
false,
entity =>
{
_odal.Instantiate(
ASSET_ID,
entity,
assetInstanceId => Debug.Log($"Instantiated assetInstance with id {assetInstanceId}."),
() => Debug.Log($"Instantiation error")
);
},
error => Debug.Log($"Add entity error: {error}")
);

Stop Odal-based rendering of participant devices

_odal.SetRenderParticipants(false);

Animate an AssetInstance

_odal.Animate(
entity,
"dance", // use _odal.GetAnimationClips(ASSET_ID) to the get the available animations for an asset instance
AnimationMode.LOOP // AnimationMode.ONCE, AnimationMode.PING_PONG
);