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
);