AR pet: Config and spawning of digital pet

In this chapter we'll cover SDK setup and digital asset spawning.

Initialize ConjureKit and spawn a digital pet asset

Install the Ur package, import the sample from Ur, and open the Main scene.

Then Import a digital pet prefab asset of your choice, ideally one that already comes with an animator and a controller.

In the sample's ^Main.cs^ script, add the following imports:

using Auki.ConjureKit;
using Auki.ConjureKit.Manna;
using Auki.Util;
using UnityEngine.UI;
using UnityEngine.XR.ARSubsystems;

Create these variables:

[SerializeField] private Text sessionState;
[SerializeField] private Text sessionID;
    
[SerializeField] private GameObject raccoon;
[SerializeField] private Button spawnButton;
    
private bool qrCodeBool;
[SerializeField] Button qrCodeButton;
    
private IConjureKit _conjureKit;
private Manna _manna;
    
private ARCameraManager arCameraManager;
private Texture2D _videoTexture;

In the ^Start()^ function, declare the ^arCameraManager^ variable, initialize ^ConjureKit^ (remember to add ^YOUR_APP_KEY^ and ^YOUR_APP_SECRET^), and connect to a Relay server.

arCameraManager = arCamera.GetComponent<ARCameraManager>();
        
_conjureKit = new ConjureKit(
    arCamera.transform,
    "YOUR_APP_KEY",
    "YOUR_APP_SECRET");
    
_manna = new Manna(_conjureKit);
        
_conjureKit.OnStateChanged += state =>
{
    sessionState.text = state.ToString();
    ToggleControlsState(state == State.Calibrated);
};
    
_conjureKit.OnJoined += session =>
{
    sessionID.text = session.Id.ToString();
};
    
_conjureKit.OnLeft += session =>
{
    sessionID.text = "";
};
    
_conjureKit.OnEntityAdded += CreateRaccoon;
_conjureKit.Connect();

Feed Manna with AR camera video frames acquired from ^ARCameraManager^ in order to recognize QR codes and perform instant calibration.

private void Update()
{
    _handTracker.Update();
    FeedMannaWithVideoFrames();
}

private void FeedMannaWithVideoFrames()
{
    var imageAcquired = arCameraManager.TryAcquireLatestCpuImage(out var cpuImage);
    if (!imageAcquired)
    {
        AukiDebug.LogInfo("Couldn't acquire CPU image");
        return;
    }

    if (_videoTexture == null) _videoTexture = new Texture2D(cpuImage.width, cpuImage.height, TextureFormat.R8, false);

    var conversionParams = new XRCpuImage.ConversionParams(cpuImage, TextureFormat.R8);
    cpuImage.ConvertAsync(
        conversionParams,
        (status, @params, buffer) =>
        {
            _videoTexture.SetPixelData(buffer, 0, 0);
            _videoTexture.Apply();
            cpuImage.Dispose();

            _manna.ProcessVideoFrameTexture(
                _videoTexture,
                arCamera.projectionMatrix,
                arCamera.worldToCameraMatrix
            );
        }
    );
}

Delete the ^ToggleHandLandmarks()^ function from the sample code as well as the call to it.

Then add the following functions: ^ToggleControlsState()^, ^ToggleLighthouse()^, ^CreateRaccoon()^, and ^CreateRaccoonEntity()^:

private void ToggleControlsState(bool interactable)
{
    if (spawnButton) spawnButton.interactable = interactable;
    if (qrCodeButton) qrCodeButton.interactable = interactable;
}

public void ToggleLighthouse()
{
    qrCodeBool = !qrCodeBool;
    _manna.SetLighthouseVisible(qrCodeBool);
}

public void CreateRaccoonEntity()
{
    if (_conjureKit.GetState() != State.Calibrated)
        return;
    
    Vector3 position = arCamera.transform.position + arCamera.transform.forward * 0.5f;
    Quaternion rotation = Quaternion.Euler(0, arCamera.transform.eulerAngles.y, 0);
    
    Pose entityPos = new Pose(position, rotation);
    
    _conjureKit.GetSession().AddEntity(
        entityPos,
        onComplete: entity => CreateRaccoon(entity),
        onError: error => Debug.Log(error));
}

private void CreateRaccoon(Entity entity)
{
    if (entity.Flag == EntityFlag.EntityFlagParticipantEntity) return;

    var pose = _conjureKit.GetSession().GetEntityPose(entity);
    Instantiate(raccoon, pose.position, pose.rotation);
}

In Unity, create two legacy text objects called ^SessionState^ and ^SessionID^, as well as two buttons called ^SpawnButton^ and ^QR^. Position these on the canvas.

Add an On Click callback for ^SpawnButton^ to ^CreateRaccoonEntity()^; for the ^QR^ button it should be ^ToggleLighthouse()^.

Drag the two text objects and the two buttons to their corresponding fields in the Main GameObject.

Drag the digital pet prefab into its field in the Main GameObject as well and edit or create its animator controller. The default sequence of animations should start at "Entry," transition to the "Default State" and any other animations, and end at "Exit."

Hit the Play button and spawn your pet. If it's facing the wrong direction, adjust its Y axis rotation:

Quaternion rotation = Quaternion.Euler(0, 180, 0);

In order to spawn the pet on a surface, find the AR Plane Manager component inside the AR Session Origin GameObject and change its Detection Mode to "Horizontal".

In the ^CreateRaccoonEntity()^ function, instead of positioning the pet relative to the AR Camera, perform a raycast to the detected plane and spawn the pet where the ray hits the plane:

public void CreateRaccoonEntity()
{
    if (_conjureKit.GetState() != State.Calibrated)
        return;
    
    Ray ray = arCamera.ScreenPointToRay(new Vector3(Screen.width / 2, Screen.height / 2));
    List<ARRaycastHit> hits = new List<ARRaycastHit>();
    
    if (arRaycastManager.Raycast(ray, hits, TrackableType.PlaneWithinPolygon))
    {
        Quaternion rotation = Quaternion.Euler(0, 180, 0);
        Pose hitPose = new Pose(hits[0].pose.position, rotation);

        _conjureKit.GetSession().AddEntity(
            hitPose,
            onComplete: entity => CreateRaccoon(entity),
            onError: error => Debug.Log(error));
    }
}

If you build and run the project now (remember to add open scenes before building), the app should connect to ConjureKit and the pet should spawn on the floor.

This is the beginning of this lesson

Need a refresher on the essentials?

Check out more lessons, DIY kits and essentials reading material at the developer learning centre homepage.

Want to build on the posemesh and need a helping hand?

Apply for a grant of AUKI tokens to get your project off the ground, and work directly with the Auki Labs team to get your creation to market. Successful applicants may be granted up to 100k USD worth of AUKI tokens, and development and marketing support from the Auki Labs team.