Init
This commit is contained in:
@@ -0,0 +1,284 @@
|
||||
/*******************************************************************************
|
||||
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
|
||||
|
||||
NOTICE:All information contained herein is, and remains the property of
|
||||
PICO Technology Co., Ltd. The intellectual and technical concepts
|
||||
contained herein are proprietary to PICO Technology Co., Ltd. and may be
|
||||
covered by patents, patents in process, and are protected by trade secret or
|
||||
copyright law. Dissemination of this information or reproduction of this
|
||||
material is strictly forbidden unless prior written permission is obtained from
|
||||
PICO Technology Co., Ltd.
|
||||
*******************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using LitJson;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.XR.PXR
|
||||
{
|
||||
public class PXR_SceneCaptureManager : MonoBehaviour
|
||||
{
|
||||
private const string TAG = "[PXR_SceneCaptureManager]";
|
||||
|
||||
public GameObject box2DPrefab;
|
||||
public GameObject box3DPrefab;
|
||||
[SerializeField]
|
||||
private TextAsset sceneCaptureData;
|
||||
private List<Guid> sceneAnchorList;
|
||||
|
||||
void Start()
|
||||
{
|
||||
|
||||
#if UNITY_EDITOR
|
||||
LoadSceneDataFromJson();
|
||||
#else
|
||||
PXR_Manager.EnableVideoSeeThrough = true;
|
||||
sceneAnchorList = new List<Guid>();
|
||||
StartSceneCaptureProvider();
|
||||
#endif
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
PXR_Manager.SceneAnchorDataUpdated += SceneAnchorDataUpdated;
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
PXR_Manager.SceneAnchorDataUpdated -= SceneAnchorDataUpdated;
|
||||
}
|
||||
|
||||
private async void StartSceneCaptureProvider()
|
||||
{
|
||||
var result0 = await PXR_MixedReality.StartSenseDataProvider(PxrSenseDataProviderType.SceneCapture);
|
||||
if (result0 == PxrResult.SUCCESS)
|
||||
{
|
||||
LoadSceneData();
|
||||
}
|
||||
else
|
||||
{
|
||||
PLog.e(TAG, "SceneCaptureProvider start fail", false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private async void LoadSceneData()
|
||||
{
|
||||
var result = await PXR_MixedReality.QuerySceneAnchorAsync(default);
|
||||
|
||||
if (result.result == PxrResult.SUCCESS)
|
||||
{
|
||||
if (result.anchorDictionary.Count > 0)
|
||||
{
|
||||
foreach (var item in result.anchorDictionary)
|
||||
{
|
||||
if (!sceneAnchorList.Contains(item.Value))
|
||||
{
|
||||
var result1 = PXR_MixedReality.GetSceneSemanticLabel(item.Key, out var label);
|
||||
if (result1 == PxrResult.SUCCESS)
|
||||
{
|
||||
DrawSceneModel(item.Key, label);
|
||||
}
|
||||
sceneAnchorList.Add(item.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var result2 = await PXR_MixedReality.StartSceneCaptureAsync(default);
|
||||
if (result2 == PxrResult.SUCCESS)
|
||||
{
|
||||
LoadSceneData();
|
||||
}
|
||||
PLog.e(TAG, "Query scene anchor count is 0", false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PLog.e(TAG, "Query scene anchor fail" + result.result, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void SceneAnchorDataUpdated()
|
||||
{
|
||||
LoadSceneData();
|
||||
}
|
||||
|
||||
private void DrawSceneModel(ulong anchorHandle, PxrSemanticLabel label)
|
||||
{
|
||||
/*
|
||||
* UnKnown 0,
|
||||
Floor-------Polygon
|
||||
Ceiling,----Polygon
|
||||
Wall,-------Box2D
|
||||
Door,-------Box2D
|
||||
Window,-----Box2D
|
||||
Opening,----Box2D
|
||||
WallArt,----Box2D
|
||||
VirtualWall,----Box2D
|
||||
Table,------Box3D
|
||||
Sofa,-------Box3D
|
||||
Chair,------Box3D
|
||||
Chair,------Box3D
|
||||
Plant,------Box3D
|
||||
Refrigerator,------Box3D
|
||||
WashingMachine,------Box3D
|
||||
AirConditioner,------Box3D
|
||||
Lamp,------Box3D
|
||||
*/
|
||||
|
||||
switch (label)
|
||||
{
|
||||
case PxrSemanticLabel.Unknown:
|
||||
break;
|
||||
case PxrSemanticLabel.Floor:
|
||||
case PxrSemanticLabel.Ceiling:
|
||||
break;
|
||||
case PxrSemanticLabel.Wall:
|
||||
case PxrSemanticLabel.Door:
|
||||
case PxrSemanticLabel.Window:
|
||||
case PxrSemanticLabel.Opening:
|
||||
case PxrSemanticLabel.WallArt:
|
||||
{
|
||||
var result = PXR_MixedReality.GetSceneBox2DData(anchorHandle, out var offset, out var extent);
|
||||
if (result == PxrResult.SUCCESS)
|
||||
{
|
||||
//currently,offset not support
|
||||
if (box2DPrefab != null)
|
||||
{
|
||||
var sceneAnchor = new GameObject(anchorHandle.ToString());
|
||||
var box2D = Instantiate(box2DPrefab);
|
||||
box2D.transform.localScale = new Vector3(extent.x, extent.y, 0);
|
||||
PXR_MixedReality.LocateAnchor(anchorHandle, out var anchorPosition, out var anchorRotation);
|
||||
box2D.transform.SetParent(sceneAnchor.transform);
|
||||
sceneAnchor.transform.rotation = anchorRotation;
|
||||
sceneAnchor.transform.position = anchorPosition;
|
||||
}
|
||||
else
|
||||
{
|
||||
PLog.e(TAG, "box2D prefab is null", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PxrSemanticLabel.Table:
|
||||
case PxrSemanticLabel.Sofa:
|
||||
case PxrSemanticLabel.Chair:
|
||||
case PxrSemanticLabel.Plant:
|
||||
case PxrSemanticLabel.Refrigerator:
|
||||
case PxrSemanticLabel.WashingMachine:
|
||||
case PxrSemanticLabel.AirConditioner:
|
||||
case PxrSemanticLabel.Lamp:
|
||||
{
|
||||
var result = PXR_MixedReality.GetSceneBox3DData(anchorHandle, out var position, out var rotation, out var extent);
|
||||
if (result == PxrResult.SUCCESS)
|
||||
{
|
||||
if (box3DPrefab != null)
|
||||
{
|
||||
var sceneAnchor = new GameObject(anchorHandle.ToString());
|
||||
var box3D = Instantiate(box3DPrefab);
|
||||
//currently,rotation not support
|
||||
box3D.transform.localPosition = position;
|
||||
box3D.transform.localScale = extent;
|
||||
PXR_MixedReality.LocateAnchor(anchorHandle, out var anchorPosition, out var anchorRotation);
|
||||
box3D.transform.SetParent(sceneAnchor.transform);
|
||||
sceneAnchor.transform.rotation = anchorRotation;
|
||||
sceneAnchor.transform.position = anchorPosition;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
PLog.e(TAG, "box3D prefab is null", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private void LoadSceneDataFromJson()
|
||||
{
|
||||
if (sceneCaptureData != null)
|
||||
{
|
||||
JsonData jsonData = JsonMapper.ToObject(sceneCaptureData.ToString());
|
||||
for (int i = 0; i < jsonData.Count; i++)
|
||||
{
|
||||
var sceneAnchorInfo = jsonData[i];
|
||||
|
||||
var uuid = sceneAnchorInfo["Guid"].ToString();
|
||||
Enum.TryParse(jsonData[i]["SemanticLabel"].ToString(), out PxrSemanticLabel semantic);
|
||||
|
||||
var pX = Convert.ToSingle(jsonData[i]["Position"]["x"].ToString());
|
||||
var pY = Convert.ToSingle(jsonData[i]["Position"]["y"].ToString());
|
||||
var pZ = Convert.ToSingle(jsonData[i]["Position"]["z"].ToString());
|
||||
var position = new Vector3(pX, pY, pZ);
|
||||
|
||||
var rX = Convert.ToSingle(jsonData[i]["Rotation"]["x"].ToString());
|
||||
var rY = Convert.ToSingle(jsonData[i]["Rotation"]["y"].ToString());
|
||||
var rZ = Convert.ToSingle(jsonData[i]["Rotation"]["z"].ToString());
|
||||
var rW = Convert.ToSingle(jsonData[i]["Rotation"]["w"].ToString());
|
||||
var rotation = new Quaternion(rX, rY, rZ, rW);
|
||||
|
||||
var box2DInfo = jsonData[i]["Box2DInfo"];
|
||||
if (box2DInfo != null)
|
||||
{
|
||||
var oX = Convert.ToSingle(jsonData[i]["Box2DInfo"]["Offset"]["x"].ToString());
|
||||
var oY = Convert.ToSingle(jsonData[i]["Box2DInfo"]["Offset"]["y"].ToString());
|
||||
var offset = new Vector2(oX, oY);
|
||||
var eX = Convert.ToSingle(jsonData[i]["Box2DInfo"]["Extent"]["x"].ToString());
|
||||
var eY = Convert.ToSingle(jsonData[i]["Box2DInfo"]["Extent"]["y"].ToString());
|
||||
var extent = new Vector2(eX, eY);
|
||||
DrawSceneCaptureDataBox2D(uuid, semantic, position, rotation, offset, extent);
|
||||
}
|
||||
|
||||
var box3DInfo = jsonData[i]["Box3DInfo"];
|
||||
if (box3DInfo != null)
|
||||
{
|
||||
var oX = Convert.ToSingle(jsonData[i]["Box3DInfo"]["Offset"]["x"].ToString());
|
||||
var oY = Convert.ToSingle(jsonData[i]["Box3DInfo"]["Offset"]["y"].ToString());
|
||||
var oZ = Convert.ToSingle(jsonData[i]["Box3DInfo"]["Offset"]["z"].ToString());
|
||||
var offset = new Vector3(oX, oY, oZ);
|
||||
var eX = Convert.ToSingle(jsonData[i]["Box3DInfo"]["Extent"]["x"].ToString());
|
||||
var eY = Convert.ToSingle(jsonData[i]["Box3DInfo"]["Extent"]["y"].ToString());
|
||||
var eZ = Convert.ToSingle(jsonData[i]["Box3DInfo"]["Extent"]["z"].ToString());
|
||||
var extent = new Vector3(eX, eY, eZ);
|
||||
DrawSceneCaptureDataBox3D(uuid, semantic, position, rotation, offset, extent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawSceneCaptureDataBox2D(string uuid, PxrSemanticLabel label, Vector3 position, Quaternion rotation, Vector2 offset, Vector2 extent)
|
||||
{
|
||||
if (box2DPrefab != null)
|
||||
{
|
||||
var sceneAnchor = new GameObject(uuid);
|
||||
var box2D = Instantiate(box2DPrefab);
|
||||
box2D.transform.localScale = new Vector3(extent.x, extent.y, 0);
|
||||
box2D.transform.SetParent(sceneAnchor.transform);
|
||||
sceneAnchor.transform.rotation = rotation;
|
||||
sceneAnchor.transform.position = position;
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawSceneCaptureDataBox3D(string uuid, PxrSemanticLabel label, Vector3 position, Quaternion rotation, Vector3 offset, Vector3 extent)
|
||||
{
|
||||
if (box3DPrefab != null)
|
||||
{
|
||||
var sceneAnchor = new GameObject(uuid);
|
||||
var box3D = Instantiate(box3DPrefab);
|
||||
//currently,rotation not support
|
||||
box3D.transform.localPosition = offset;
|
||||
box3D.transform.localScale = extent;
|
||||
box3D.transform.SetParent(sceneAnchor.transform);
|
||||
sceneAnchor.transform.rotation = rotation;
|
||||
sceneAnchor.transform.position = position;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5890c56b737118245adea1cba9b51cf4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,124 @@
|
||||
/*******************************************************************************
|
||||
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
|
||||
|
||||
NOTICE:All information contained herein is, and remains the property of
|
||||
PICO Technology Co., Ltd. The intellectual and technical concepts
|
||||
contained herein are proprietary to PICO Technology Co., Ltd. and may be
|
||||
covered by patents, patents in process, and are protected by trade secret or
|
||||
copyright law. Dissemination of this information or reproduction of this
|
||||
material is strictly forbidden unless prior written permission is obtained from
|
||||
PICO Technology Co., Ltd.
|
||||
*******************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.XR.Interaction.Toolkit;
|
||||
#if UNITY_6000_0_OR_NEWER
|
||||
using UnityEngine.XR.Interaction.Toolkit.Interactables;
|
||||
#endif
|
||||
|
||||
namespace Unity.XR.PXR
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public class PXR_SpatialAnchor : MonoBehaviour
|
||||
{
|
||||
private const string TAG = "[PXR_SpatialAnchor]";
|
||||
|
||||
[HideInInspector]
|
||||
public bool Created = false;
|
||||
[HideInInspector]
|
||||
public ulong anchorHandle;
|
||||
[HideInInspector]
|
||||
public Guid anchorUuid;
|
||||
|
||||
// Start is called before the first frame update
|
||||
void Start()
|
||||
{
|
||||
if (!Created)
|
||||
{
|
||||
CreateSpatialAnchor();
|
||||
}
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
if (Created)
|
||||
{
|
||||
var result = PXR_MixedReality.LocateAnchor(anchorHandle, out var position, out var rotation);
|
||||
if (result == PxrResult.SUCCESS)
|
||||
{
|
||||
transform.SetPositionAndRotation(position, rotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
var result = PXR_MixedReality.DestroyAnchor(anchorHandle);
|
||||
if (result != PxrResult.SUCCESS)
|
||||
{
|
||||
PLog.e(TAG, "DestroySpatialAnchor Fail: " + result, false);
|
||||
}
|
||||
}
|
||||
|
||||
private async void CreateSpatialAnchor()
|
||||
{
|
||||
var result = await PXR_MixedReality.CreateSpatialAnchorAsync(transform.position, transform.rotation);
|
||||
if (result.result == PxrResult.SUCCESS)
|
||||
{
|
||||
anchorHandle = result.anchorHandle;
|
||||
anchorUuid = result.uuid;
|
||||
Created = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> Persist()
|
||||
{
|
||||
var result = await PXR_MixedReality.PersistSpatialAnchorAsync(anchorHandle);
|
||||
if (result == PxrResult.SUCCESS)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
PLog.e(TAG, "PersistSpatialAnchor Fail: " + result, false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> UnPersist()
|
||||
{
|
||||
var result = await PXR_MixedReality.UnPersistSpatialAnchorAsync(anchorHandle);
|
||||
if (result == PxrResult.SUCCESS)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
PLog.e(TAG, "UnPersistSpatialAnchor Fail: " + result, false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void DestroySpatialAnchor()
|
||||
{
|
||||
var result = PXR_MixedReality.DestroyAnchor(anchorHandle);
|
||||
if (result == PxrResult.SUCCESS)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
PLog.e(TAG, "DestroySpatialAnchor Fail: " + result, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3cf43f92875ac6a41be5c5fea4a7ed53
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,109 @@
|
||||
/*******************************************************************************
|
||||
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
|
||||
|
||||
NOTICE:All information contained herein is, and remains the property of
|
||||
PICO Technology Co., Ltd. The intellectual and technical concepts
|
||||
contained herein are proprietary to PICO Technology Co., Ltd. and may be
|
||||
covered by patents, patents in process, and are protected by trade secret or
|
||||
copyright law. Dissemination of this information or reproduction of this
|
||||
material is strictly forbidden unless prior written permission is obtained from
|
||||
PICO Technology Co., Ltd.
|
||||
*******************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.XR.PXR
|
||||
{
|
||||
[System.Serializable]
|
||||
public class PXR_SpatialMeshColorSetting : ScriptableObject
|
||||
{
|
||||
public List<Color> colorLists = new List<Color>();
|
||||
|
||||
public static PXR_SpatialMeshColorSetting GetSpatialMeshColorSetting()
|
||||
{
|
||||
PXR_SpatialMeshColorSetting colorSetting = Resources.Load<PXR_SpatialMeshColorSetting>("PXR_SpatialMeshColorSetting");
|
||||
#if UNITY_EDITOR
|
||||
if (colorSetting == null)
|
||||
{
|
||||
colorSetting = CreateInstance<PXR_SpatialMeshColorSetting>();
|
||||
colorSetting.colorLists = new List<Color>
|
||||
{
|
||||
//Unknown
|
||||
Color.white,
|
||||
//Floor
|
||||
Color.grey,
|
||||
//Ceiling
|
||||
Color.grey,
|
||||
//Wall
|
||||
Color.blue,
|
||||
//Door
|
||||
Color.cyan,
|
||||
//Window
|
||||
Color.magenta,
|
||||
//Opening
|
||||
Color.yellow,
|
||||
//Table
|
||||
Color.red,
|
||||
//Sofa
|
||||
Color.green,
|
||||
//Chair
|
||||
new Color(0.5f, 0f, 0f),
|
||||
|
||||
//Human
|
||||
new Color(0f, 0.5f, 0f),
|
||||
//Curtain
|
||||
new Color(0f, 0f, 0.5f),
|
||||
//Cabinet
|
||||
new Color(1f, 0.5f, 0f),
|
||||
//Bed
|
||||
new Color(1f, 0.75f, 0.8f),
|
||||
//Plant
|
||||
new Color(0.5f, 0f, 0.5f),
|
||||
//Screen
|
||||
new Color(0.5f, 0.25f, 0f),
|
||||
//VirtualWall
|
||||
Color.white,
|
||||
//Refrigerator
|
||||
new Color(0.5f, 0.5f, 0f),
|
||||
//WashingMachine
|
||||
new Color(1f, 0.84f, 0f),
|
||||
//AirConditioner
|
||||
new Color(0.75f, 0.75f, 0.75f),
|
||||
//Lamp
|
||||
new Color(0.5f, 1f, 0.5f),
|
||||
//WallArt
|
||||
new Color(0.5f, 0f, 0.25f),
|
||||
//Stairway
|
||||
new Color(0.25f, 0f, 0.25f),
|
||||
|
||||
};
|
||||
string path = Application.dataPath + "/Resources";
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
AssetDatabase.CreateFolder("Assets", "Resources");
|
||||
AssetDatabase.CreateAsset(colorSetting, "Assets/Resources/PXR_SpatialMeshColorSetting.asset");
|
||||
}
|
||||
else
|
||||
{
|
||||
AssetDatabase.CreateAsset(colorSetting, "Assets/Resources/PXR_SpatialMeshColorSetting.asset");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
return colorSetting;
|
||||
}
|
||||
#if UNITY_EDITOR
|
||||
public static void SaveAssets()
|
||||
{
|
||||
EditorUtility.SetDirty(GetSpatialMeshColorSetting());
|
||||
AssetDatabase.SaveAssets();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2db0983a9e79077449a08d20fa535166
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,337 @@
|
||||
/*******************************************************************************
|
||||
Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
|
||||
|
||||
NOTICE:All information contained herein is, and remains the property of
|
||||
PICO Technology Co., Ltd. The intellectual and technical concepts
|
||||
contained herein are proprietary to PICO Technology Co., Ltd. and may be
|
||||
covered by patents, patents in process, and are protected by trade secret or
|
||||
copyright law. Dissemination of this information or reproduction of this
|
||||
material is strictly forbidden unless prior written permission is obtained from
|
||||
PICO Technology Co., Ltd.
|
||||
*******************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
#if PICO_OPENXR_SDK
|
||||
using Unity.XR.OpenXR.Features.PICOSupport;
|
||||
#endif
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.XR;
|
||||
using UnityEngine.XR.Management;
|
||||
|
||||
namespace Unity.XR.PXR
|
||||
{
|
||||
|
||||
[DisallowMultipleComponent]
|
||||
public class PXR_SpatialMeshManager : MonoBehaviour
|
||||
{
|
||||
public GameObject meshPrefab;
|
||||
private Dictionary<Guid, GameObject> meshIDToGameobject;
|
||||
private Dictionary<Guid, PxrSpatialMeshInfo> spatialMeshNeedingDraw;
|
||||
private Dictionary<PxrSemanticLabel, Color> colorMappings;
|
||||
private Mesh mesh;
|
||||
private XRMeshSubsystem subsystem;
|
||||
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;
|
||||
public UnityEvent<Guid, GameObject> OnSpatialMeshAdded;
|
||||
|
||||
/// <summary>
|
||||
/// The drawing the updated spatial mesh is complete.
|
||||
/// </summary>
|
||||
public static Action<Guid, GameObject> MeshUpdated;
|
||||
public UnityEvent<Guid, GameObject> OnSpatialMeshUpdated;
|
||||
|
||||
/// <summary>
|
||||
/// The deletion of the disappeared spatial mesh is complete.
|
||||
/// </summary>
|
||||
public static Action<Guid> MeshRemoved;
|
||||
public UnityEvent<Guid> OnSpatialMeshRemoved;
|
||||
static List<XRMeshSubsystem> s_SubsystemsReuse = new List<XRMeshSubsystem>();
|
||||
void Awake()
|
||||
{
|
||||
InitMeshColor();
|
||||
}
|
||||
|
||||
void Start()
|
||||
{
|
||||
spatialMeshNeedingDraw = new Dictionary<Guid, PxrSpatialMeshInfo>();
|
||||
meshIDToGameobject = new Dictionary<Guid, GameObject>();
|
||||
meshObjectsPool = new Queue<GameObject>();
|
||||
|
||||
PXR_Manager.EnableVideoSeeThrough = true;
|
||||
InitializePool();
|
||||
}
|
||||
void GetXRMeshSubsystem()
|
||||
{
|
||||
if (subsystem != null)
|
||||
return;
|
||||
SubsystemManager.GetSubsystems(s_SubsystemsReuse);
|
||||
|
||||
if (s_SubsystemsReuse.Count == 0)
|
||||
return;
|
||||
subsystem = s_SubsystemsReuse[0];
|
||||
subsystem.Start();
|
||||
|
||||
}
|
||||
void Update()
|
||||
{
|
||||
GetXRMeshSubsystem();
|
||||
}
|
||||
void OnEnable()
|
||||
{
|
||||
GetXRMeshSubsystem();
|
||||
if (subsystem != null)
|
||||
{
|
||||
if (!subsystem.running)
|
||||
{
|
||||
subsystem.Start();
|
||||
}
|
||||
|
||||
|
||||
if (subsystem.running)
|
||||
{
|
||||
#if PICO_OPENXR_SDK
|
||||
OpenXRExtensions.SpatialMeshDataUpdated += SpatialMeshDataUpdated;
|
||||
#else
|
||||
PXR_Manager.SpatialMeshDataUpdated += SpatialMeshDataUpdated;
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
if (subsystem != null && subsystem.running)
|
||||
{
|
||||
subsystem.Stop();
|
||||
#if PICO_OPENXR_SDK
|
||||
OpenXRExtensions.SpatialMeshDataUpdated -= SpatialMeshDataUpdated;
|
||||
#else
|
||||
PXR_Manager.SpatialMeshDataUpdated -= SpatialMeshDataUpdated;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SpatialMeshDataUpdated(List<PxrSpatialMeshInfo> meshInfos)
|
||||
{
|
||||
if (meshPrefab != null)
|
||||
{
|
||||
for (int i = 0; i < meshInfos.Count; i++)
|
||||
{
|
||||
switch (meshInfos[i].state)
|
||||
{
|
||||
case MeshChangeState.Added:
|
||||
{
|
||||
CreateMeshRoutine(meshInfos[i]);
|
||||
}
|
||||
break;
|
||||
case MeshChangeState.Updated:
|
||||
{
|
||||
CreateMeshRoutine(meshInfos[i]);
|
||||
}
|
||||
break;
|
||||
case MeshChangeState.Removed:
|
||||
{
|
||||
MeshRemoved?.Invoke(meshInfos[i].uuid);
|
||||
OnSpatialMeshRemoved?.Invoke(meshInfos[i].uuid);
|
||||
|
||||
if (meshIDToGameobject.TryGetValue(meshInfos[i].uuid, out var go))
|
||||
{
|
||||
if (meshObjectsPool.Count < objectPoolMaxSize)
|
||||
{
|
||||
go.SetActive(false);
|
||||
meshObjectsPool.Enqueue(go);
|
||||
}
|
||||
else
|
||||
{
|
||||
Destroy(go);
|
||||
}
|
||||
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);
|
||||
OnSpatialMeshAdded?.Invoke(block.uuid, meshGameObject);
|
||||
}
|
||||
break;
|
||||
case MeshChangeState.Updated:
|
||||
{
|
||||
MeshUpdated?.Invoke(block.uuid, meshGameObject);
|
||||
OnSpatialMeshUpdated?.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 void InitMeshColor()
|
||||
{
|
||||
PXR_SpatialMeshColorSetting colorSetting = PXR_SpatialMeshColorSetting.GetSpatialMeshColorSetting();
|
||||
PxrSemanticLabel[] labels = (PxrSemanticLabel[])Enum.GetValues(typeof(PxrSemanticLabel));
|
||||
colorMappings = new Dictionary<PxrSemanticLabel, Color>();
|
||||
for (int i = 0; i < labels.Length; i++)
|
||||
{
|
||||
var label = labels[i];
|
||||
var color = colorSetting.colorLists[i];
|
||||
colorMappings.Add(label,color);
|
||||
}
|
||||
}
|
||||
|
||||
private Color GetMeshColorBySemanticLabel(PxrSemanticLabel label)
|
||||
{
|
||||
if (colorMappings != null && colorMappings.Count > 0)
|
||||
{
|
||||
if (colorMappings.ContainsKey(label))
|
||||
{
|
||||
return colorMappings[label];
|
||||
}
|
||||
else
|
||||
{
|
||||
return Color.white;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return label switch
|
||||
{
|
||||
PxrSemanticLabel.Unknown => Color.white,
|
||||
PxrSemanticLabel.Floor => Color.grey,
|
||||
PxrSemanticLabel.Ceiling => Color.grey,
|
||||
PxrSemanticLabel.Wall => Color.blue,
|
||||
PxrSemanticLabel.Door => Color.cyan,
|
||||
PxrSemanticLabel.Window => Color.magenta,
|
||||
PxrSemanticLabel.Opening => Color.yellow,
|
||||
PxrSemanticLabel.Table => Color.red,
|
||||
PxrSemanticLabel.Sofa => Color.green,
|
||||
//Dark Red
|
||||
PxrSemanticLabel.Chair => new Color(0.5f, 0f, 0f),
|
||||
//Dark Green
|
||||
PxrSemanticLabel.Human => new Color(0f, 0.5f, 0f),
|
||||
//Dark Blue
|
||||
PxrSemanticLabel.Curtain => new Color(0f, 0f, 0.5f),
|
||||
//Orange
|
||||
PxrSemanticLabel.Cabinet => new Color(1f, 0.5f, 0f),
|
||||
//Pink
|
||||
PxrSemanticLabel.Bed => new Color(1f, 0.75f, 0.8f),
|
||||
//Purple
|
||||
PxrSemanticLabel.Plant => new Color(0.5f, 0f, 0.5f),
|
||||
//Brown
|
||||
PxrSemanticLabel.Screen => new Color(0.5f, 0.25f, 0f),
|
||||
//Olive Green
|
||||
PxrSemanticLabel.Refrigerator => new Color(0.5f, 0.5f, 0f),
|
||||
//Gold
|
||||
PxrSemanticLabel.WashingMachine => new Color(1f, 0.84f, 0f),
|
||||
//Silver
|
||||
PxrSemanticLabel.AirConditioner => new Color(0.75f, 0.75f, 0.75f),
|
||||
//Mint Green
|
||||
PxrSemanticLabel.Lamp => new Color(0.5f, 1f, 0.5f),
|
||||
//Dark Purple
|
||||
PxrSemanticLabel.WallArt => new Color(0.5f, 0f, 0.25f),
|
||||
PxrSemanticLabel.Stairway => new Color(0.25f, 0f, 0.25f),
|
||||
_ => Color.white,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 551d50f46be2e15418380110aaeeb3ba
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user