Table of Contents

Spatial Mesh

Overview

Spatial mesh is used to represent and understand the three-dimensional structure of the physical environment. It typically consists of a series of polygons (usually triangles) that together form a three-dimensional mesh to describe objects and surfaces in the real world. In Unity, you can access and update mesh information through the XRMeshSubsystem and dynamically generate and update mesh objects in the scene.

How to Enable Spatial Mesh

YVR implements the UnityXR XRMeshSubsystem interface. For details, refer to the Unity XRMeshSubsystem documentation.

  • Enable the scene feature.

    • Check the scene Support feature

      sceneSupport

    • Request the corresponding scene permission

    public void ScenePermissionRequest()
    {
            const string spatialPermission = "com.yvr.permission.USE_SCENE";
            if (!UnityEngine.Android.Permission.HasUserAuthorizedPermission(spatialPermission))
            {
                    var callbacks = new UnityEngine.Android.PermissionCallbacks();
                    callbacks.PermissionDenied += Denied;
                    callbacks.PermissionGranted += Granted;
                    UnityEngine.Android.Permission.RequestUserPermission(spatialPermission, callbacks);
            }
    }
    private void Denied(string permission) => Debug.Log($"{permission} Denied");
    private void Granted(string permission) => Debug.Log($"{permission} Granted");
    
  • Enable mesh detection

    YVRMeshTracking.instance.CreateMeshDetector();
    
  • Enable passthrough mode.

    YVRPlugin.Instance.SetPassthrough(true);
    
  • Get the available XRMeshSubsystem instance.

    var meshSubsystems = new List<XRMeshSubsystem>();
    SubsystemManager.GetInstances(meshSubsystems);
    

Get Spatial Mesh Update Information

  • Get current mesh information
    private static XRMeshSubsystem s_MeshSubsystem;
    private static List<MeshInfo> s_MeshInfos = new List<MeshInfo>();
    private Dictionary<MeshId, MeshFilter> m_MeshIdToGo = new Dictionary<MeshId, MeshFilter>();
    private void UpdateMeshInfos()
    {
            if (s_MeshSubsystem == null)
            {
                    Debug.LogError("s_MeshSubsystem is null");
                    return;
            }
            if (s_MeshSubsystem.TryGetMeshInfos(s_MeshInfos))
            {
                    foreach (var meshInfo in s_MeshInfos)
                    {
                            switch (meshInfo.ChangeState)
                            {
                                    case MeshChangeState.Added:
                                    case MeshChangeState.Updated:
                                            AddToQueueIfNecessary(meshInfo);
                                            break;
                                    case MeshChangeState.Removed:
                                            if (m_MeshIdToGo.TryGetValue(meshInfo.MeshId, out var meshGo))
                                            {
                                                    Destroy(meshGo);
                                                    m_MeshIdToGo.Remove(meshInfo.MeshId);
                                            }
                                            break;
                                    default:
                                            break;
                            }
                    }
            }
    }
    

Update Mesh Block Position and Rotation

  • Update mesh object position and rotation.
    private void UpdateMeshTransform()
    {
            NativeArray<MeshTransform> meshTransforms = s_MeshSubsystem.GetUpdatedMeshTransforms(Allocator.Temp);
            foreach (var item in meshTransforms)
            {
                    if (m_MeshIdToGo.TryGetValue(item.MeshId, out MeshFilter meshFilter))
                    {
                            if (meshFilter.transform.position != item.Position)
                            {
                                    meshFilter.transform.position = item.Position;
                                    meshFilter.transform.rotation = item.Rotation;
                            }
                    }
            }
    }
        ```
    
    

Update Corresponding Mesh Block Data

  • If the mesh object does not exist, instantiate a new mesh object and add it to the dictionary.
  • If it exists, generate the mesh asynchronously and update its position and rotation.
    public GameObject emptyMeshPrefab;
    public Transform target;
     private void AddToQueueIfNecessary(MeshInfo meshInfo)
    {
            if (!m_MeshIdToGo.TryGetValue(meshInfo.MeshId, out var meshFilter))
            {
                    meshFilter = Instantiate(emptyMeshPrefab, target, false).AddComponent<MeshFilter>();
                    m_MeshIdToGo[meshInfo.MeshId] = meshFilter;
            }
            var mesh = meshFilter.mesh;
            s_MeshSubsystem.GenerateMeshAsync(meshInfo.MeshId, mesh, null, MeshVertexAttributes.None, (result) =>
            {
                    if (result.Status == MeshGenerationStatus.Success)
                    {
                            if (meshFilter.transform.position != result.Position)
                            {
                                    meshFilter.transform.position = result.Position;
                                    meshFilter.transform.rotation = result.Rotation;
                            }
                    }
            }, MeshGenerationOptions.ConsumeTransform);
    }
    

How to Stop Mesh Detection

    YVRMeshTracking.instance.DestroyMeshDetector();