上传YomovSDK
This commit is contained in:
@@ -0,0 +1,296 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using Unity.XR.OpenXR.Features.PICOSupport;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.XR;
|
||||
|
||||
namespace Unity.XR.PXR
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public class PXR_SpatialMeshManager : MonoBehaviour
|
||||
{
|
||||
public GameObject meshPrefab;
|
||||
private Dictionary<Guid, GameObject> meshIDToGameobject;
|
||||
private Dictionary<Guid, PxrSpatialMeshInfo> spatialMeshNeedingDraw;
|
||||
private Mesh mesh;
|
||||
private XRMeshSubsystem subsystem;
|
||||
static List<XRMeshSubsystem> s_SubsystemsReuse = new List<XRMeshSubsystem>();
|
||||
private int objectPoolMaxSize = 200;
|
||||
private Queue<GameObject> meshObjectsPool;
|
||||
private const float frameCount = 15.0f;
|
||||
|
||||
/// <summary>
|
||||
/// The drawing of the new spatial mesh is complete.
|
||||
/// </summary>
|
||||
public static Action<Guid, GameObject> MeshAdded;
|
||||
|
||||
/// <summary>
|
||||
/// The drawing the updated spatial mesh is complete.
|
||||
/// </summary>
|
||||
public static Action<Guid, GameObject> MeshUpdated;
|
||||
|
||||
/// <summary>
|
||||
/// The deletion of the disappeared spatial mesh is complete.
|
||||
/// </summary>
|
||||
public static Action<Guid> MeshRemoved;
|
||||
|
||||
void Start()
|
||||
{
|
||||
spatialMeshNeedingDraw = new Dictionary<Guid, PxrSpatialMeshInfo>();
|
||||
meshIDToGameobject = new Dictionary<Guid, GameObject>();
|
||||
meshObjectsPool = new Queue<GameObject>();
|
||||
|
||||
InitializePool();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
GetXRMeshSubsystem();
|
||||
if (subsystem != null && subsystem.running)
|
||||
{
|
||||
DrawMesh();
|
||||
}
|
||||
}
|
||||
|
||||
void GetXRMeshSubsystem()
|
||||
{
|
||||
if (subsystem != null)
|
||||
return;
|
||||
SubsystemManager.GetSubsystems(s_SubsystemsReuse);
|
||||
|
||||
if (s_SubsystemsReuse.Count == 0)
|
||||
return;
|
||||
|
||||
subsystem = s_SubsystemsReuse[0];
|
||||
|
||||
|
||||
PXR_PermissionRequest.RequestUserPermissionMR(Granted =>
|
||||
{
|
||||
subsystem.Start();
|
||||
if (subsystem.running)
|
||||
{
|
||||
OpenXRExtensions.SpatialMeshDataUpdated += SpatialMeshDataUpdated;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
GetXRMeshSubsystem();
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
if (subsystem != null && subsystem.running)
|
||||
subsystem.Stop();
|
||||
}
|
||||
|
||||
private void InitializePool()
|
||||
{
|
||||
if (meshPrefab != null)
|
||||
{
|
||||
while (meshObjectsPool.Count < objectPoolMaxSize)
|
||||
{
|
||||
GameObject obj = Instantiate(meshPrefab);
|
||||
obj.transform.SetParent(this.transform);
|
||||
obj.SetActive(false);
|
||||
meshObjectsPool.Enqueue(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawMesh()
|
||||
{
|
||||
if (meshPrefab != null)
|
||||
{
|
||||
StartCoroutine(ForeachLoopCoroutine());
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator ForeachLoopCoroutine()
|
||||
{
|
||||
int totalWork = spatialMeshNeedingDraw.Count;
|
||||
if (totalWork > 0 )
|
||||
{
|
||||
var meshList = spatialMeshNeedingDraw.Values.ToList();
|
||||
int workPerFrame = Mathf.CeilToInt(totalWork / frameCount);
|
||||
int currentIndex = 0;
|
||||
|
||||
while (currentIndex < totalWork)
|
||||
{
|
||||
int workThisFrame = 0;
|
||||
while (workThisFrame < workPerFrame && currentIndex < totalWork)
|
||||
{
|
||||
CreateMeshRoutine(meshList[currentIndex]);
|
||||
currentIndex++;
|
||||
workThisFrame++;
|
||||
}
|
||||
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SpatialMeshDataUpdated(List<PxrSpatialMeshInfo> meshInfos)
|
||||
{
|
||||
for (int i = 0; i < meshInfos.Count; i++)
|
||||
{
|
||||
switch (meshInfos[i].state)
|
||||
{
|
||||
case MeshChangeState.Added:
|
||||
{
|
||||
spatialMeshNeedingDraw.Add(meshInfos[i].uuid, meshInfos[i]);
|
||||
}
|
||||
break;
|
||||
case MeshChangeState.Updated:
|
||||
{
|
||||
if (!spatialMeshNeedingDraw.ContainsKey(meshInfos[i].uuid))
|
||||
{
|
||||
spatialMeshNeedingDraw.Add(meshInfos[i].uuid, meshInfos[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
spatialMeshNeedingDraw[meshInfos[i].uuid] = meshInfos[i];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MeshChangeState.Removed:
|
||||
{
|
||||
MeshRemoved?.Invoke(meshInfos[i].uuid);
|
||||
|
||||
spatialMeshNeedingDraw.Remove(meshInfos[i].uuid);
|
||||
GameObject removedGo;
|
||||
if (meshIDToGameobject.TryGetValue(meshInfos[i].uuid, out removedGo))
|
||||
{
|
||||
if (meshObjectsPool.Count < objectPoolMaxSize)
|
||||
{
|
||||
removedGo.SetActive(false);
|
||||
meshObjectsPool.Enqueue(removedGo);
|
||||
}
|
||||
else
|
||||
{
|
||||
Destroy(removedGo);
|
||||
}
|
||||
meshIDToGameobject.Remove(meshInfos[i].uuid);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MeshChangeState.Unchanged:
|
||||
{
|
||||
spatialMeshNeedingDraw.Remove(meshInfos[i].uuid);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateMeshRoutine(PxrSpatialMeshInfo block)
|
||||
{
|
||||
GameObject meshGameObject = GetOrCreateGameObject(block.uuid);
|
||||
var meshFilter = meshGameObject.GetComponentInChildren<MeshFilter>();
|
||||
var meshCollider = meshGameObject.GetComponentInChildren<MeshCollider>();
|
||||
|
||||
if (meshFilter.mesh == null)
|
||||
{
|
||||
mesh = new Mesh();
|
||||
}
|
||||
else
|
||||
{
|
||||
mesh = meshFilter.mesh;
|
||||
mesh.Clear();
|
||||
}
|
||||
Color[] normalizedColors = new Color[block.vertices.Length];
|
||||
for (int i = 0; i < block.vertices.Length; i++)
|
||||
{
|
||||
normalizedColors[i] = GetMeshColorBySemanticLabel(block.labels[i]);
|
||||
}
|
||||
mesh.SetVertices(block.vertices);
|
||||
mesh.SetColors(normalizedColors);
|
||||
mesh.SetTriangles(block.indices, 0);
|
||||
meshFilter.mesh = mesh;
|
||||
if (meshCollider != null)
|
||||
{
|
||||
meshCollider.sharedMesh = mesh;
|
||||
}
|
||||
meshGameObject.transform.position = block.position;
|
||||
meshGameObject.transform.rotation = block.rotation;
|
||||
|
||||
switch (block.state)
|
||||
{
|
||||
case MeshChangeState.Added:
|
||||
{
|
||||
MeshAdded?.Invoke(block.uuid, meshGameObject);
|
||||
}
|
||||
break;
|
||||
case MeshChangeState.Updated:
|
||||
{
|
||||
MeshUpdated?.Invoke(block.uuid, meshGameObject);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
GameObject CreateGameObject(Guid meshId)
|
||||
{
|
||||
GameObject meshObject = meshObjectsPool.Dequeue();
|
||||
meshObject.name = $"Mesh {meshId}";
|
||||
meshObject.SetActive(true);
|
||||
return meshObject;
|
||||
}
|
||||
|
||||
GameObject GetOrCreateGameObject(Guid meshId)
|
||||
{
|
||||
GameObject go = null;
|
||||
if (!meshIDToGameobject.TryGetValue(meshId, out go))
|
||||
{
|
||||
go = CreateGameObject(meshId);
|
||||
meshIDToGameobject[meshId] = go;
|
||||
}
|
||||
|
||||
return go;
|
||||
}
|
||||
|
||||
private Color GetMeshColorBySemanticLabel(PxrSemanticLabel label)
|
||||
{
|
||||
switch (label)
|
||||
{
|
||||
case PxrSemanticLabel.Unknown:
|
||||
return Color.white;
|
||||
case PxrSemanticLabel.Floor:
|
||||
return Color.red;
|
||||
case PxrSemanticLabel.Ceiling:
|
||||
return Color.green;
|
||||
case PxrSemanticLabel.Wall:
|
||||
return Color.blue;
|
||||
case PxrSemanticLabel.Door:
|
||||
return Color.grey;
|
||||
case PxrSemanticLabel.Window:
|
||||
return Color.yellow;
|
||||
case PxrSemanticLabel.Opening:
|
||||
return Color.cyan;
|
||||
case PxrSemanticLabel.Table:
|
||||
return Color.magenta;
|
||||
case PxrSemanticLabel.Sofa:
|
||||
return Color.gray;
|
||||
case PxrSemanticLabel.Chair:
|
||||
return new Color(0.8f, 0.2f, 0.5f);
|
||||
case PxrSemanticLabel.Human:
|
||||
return new Color(0.8f, 0.2f, 0.6f);
|
||||
default:
|
||||
return Color.white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user