Skip to main content

Manna



The Manna module enables devices to establish their pose in another device's Session by scanning a QR code on the screen of the other device.

When a participant successfully scans another participant's QR code, the scanning participant is brought into the Session of the participant displaying the QR code while leaving their current Session. Entities owned by the scanning participant in their former session are not brought into the new Session.

Basic Usage

Import the Manna module

using Auki.ConjureKit.Manna;

Initialize the Manna module

public class Demo : MonoBehaviour
{
public Transform cameraTransform;

private IConjureKit _conjureKit;
private Manna _manna;

private void Start()
{
_conjureKit = new ConjureKit(cameraTransform, "app_key", "app_secret");
_manna = new Manna(_conjureKit);
}
}

Show the QR code

_manna.SetLighthouseVisible(true);

One frame calibration

Manna needs to be supplied with camera feed frames to detect QR codes and perform Instant Calibration. Please take a look at the Demo Sample from the Manna package for an example of how to use the AR Foundation's AR Camera Background to retrieve the camera feed images.

private void FeedMannaWithVideoFrames()
{
if (_videoTexture == null) CreateVideoTexture();
if (_videoTexture == null) return;

CopyVideoTexture();

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

private void CreateVideoTexture()
{
if (Application.platform == RuntimePlatform.IPhonePlayer)
{
var textureNames = arCameraBackground.material.GetTexturePropertyNames();
for (var i = 0; i < textureNames.Length; i++)
{
var texture = arCameraBackground.material.GetTexture(textureNames[i]);
if (texture == null || (texture.graphicsFormat != GraphicsFormat.R8_UNorm)) continue;
Debug.Log($"Creating video texture based on: {textureNames[i]}, format: {texture.graphicsFormat}, size: {texture.width}x{texture.height}");
_videoTexture = new RenderTexture(texture.width, texture.height, 0, GraphicsFormat.R8G8B8A8_UNorm);
break;
}
}
else if (Application.platform == RuntimePlatform.Android)
{
var arTexture = !arCameraBackground.material.HasProperty("_MainTex") ? null : arCameraBackground.material.GetTexture("_MainTex");
if (arTexture != null)
{
Debug.Log($"Creating video texture format: {arTexture.graphicsFormat}, size: {arTexture.width}x{arTexture.height}");
_videoTexture = new RenderTexture(arTexture.height, arTexture.width, 0, GraphicsFormat.R8G8B8A8_UNorm);
}
}
}

private void CopyVideoTexture()
{
// Copy the camera background to a RenderTexture
if (Application.platform == RuntimePlatform.Android)
{
var commandBuffer = new CommandBuffer();
commandBuffer.name = "AR Camera Background Blit Pass";
var arTexture = !arCameraBackground.material.HasProperty("_MainTex") ? null : arCameraBackground.material.GetTexture("_MainTex");
Graphics.SetRenderTarget(_videoTexture.colorBuffer, _videoTexture.depthBuffer);
commandBuffer.ClearRenderTarget(true, false, Color.clear);
commandBuffer.Blit(arTexture, BuiltinRenderTextureType.CurrentActive, arCameraBackground.material);
Graphics.ExecuteCommandBuffer(commandBuffer);
commandBuffer.Dispose();
}
else if(Application.platform == RuntimePlatform.IPhonePlayer)
{
var textureY = arCameraBackground.material.GetTexture("_textureY");
Graphics.Blit(textureY, _videoTexture);
}
}