我目前遇到了与 HololLens2 相关的问题。 我尝试在运行时直接访问空间映射。所以我想实现一个扫描程序,用户必须扫描房间,然后我想导出这个网格。基本上我想像在设备门户中一样但在运行时创建房间扫描的 .obj。
因此我实施了一个解决方案,我在这里找到了它: https://learn.microsoft.com/en-us/windows/mixed-reality/mrtk-unity/mrtk2/features/spatial-awareness/usage-guide?view=mrtkunity-2022-05
现在的问题是我没有得到任何网格。
我目前使用MRTK 2.8.3.0和Unity 2022.3.10f1
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Microsoft.MixedReality.Toolkit;
using Microsoft.MixedReality.Toolkit.SpatialAwareness;
using TMPro;
using Unity.VisualScripting;
public class Scanner_new : MonoBehaviour
{
public GameObject txt;
static int count = 0;
// Start is called before the first frame update
void Start()
{
TextMeshPro textMesh = txt.GetComponent<TextMeshPro>();
// Use CoreServices to quickly get access to the IMixedRealitySpatialAwarenessSystem
var spatialAwarenessService = CoreServices.SpatialAwarenessSystem;
// Cast to the IMixedRealityDataProviderAccess to get access to the data providers
var dataProviderAccess = spatialAwarenessService as IMixedRealityDataProviderAccess;
var meshObserver = dataProviderAccess.GetDataProvider<IMixedRealitySpatialAwarenessMeshObserver>();
if(meshObserver == null){
count++;
textMesh.text = "No Observer! \n";
Debug.Log("No Observer! \n");
return;
}
textMesh.text += "Accessing all the meshes: \n";
// Loop through all known Meshes
foreach (SpatialAwarenessMeshObject meshObject in meshObserver.Meshes.Values)
{ textMesh.text = "here1 \n";
Mesh mesh = meshObject.Filter.mesh;
var triangles = mesh.GetTriangles(0);
foreach (var triangle in triangles){
textMesh.text = "here2 \n";
textMesh.text += triangle + "\n";
count++;
}
}
}
// Update is called once per frame
public void Updater()
{
TextMeshPro textMesh = txt.GetComponent<TextMeshPro>();
if(count == 0){
// Use CoreServices to quickly get access to the IMixedRealitySpatialAwarenessSystem
var spatialAwarenessService = CoreServices.SpatialAwarenessSystem;
// Cast to the IMixedRealityDataProviderAccess to get access to the data providers
var dataProviderAccess = spatialAwarenessService as IMixedRealityDataProviderAccess;
var meshObserver = dataProviderAccess.GetDataProvider<IMixedRealitySpatialAwarenessMeshObserver>();
if(meshObserver == null){
count++;
textMesh.text = "No Observer! \n";
Debug.Log("No Observer! \n");
return;
}
textMesh.text += "Accessing all the meshes: \n";
// Loop through all known Meshes
foreach (SpatialAwarenessMeshObject meshObject in meshObserver.Meshes.Values)
{
textMesh.text = "here1 \n";
Mesh mesh = meshObject.Filter.mesh;
var triangles = mesh.GetTriangles(0);
foreach (var triangle in triangles){
textMesh.text = "here2 \n";
textMesh.text += triangle + "\n";
count++;
}
}
}
}
}
感谢您的帮助:)
因为我忙了很长一段时间来寻找这个问题的解决方案,现在我也找到了一个我想在这里分享。
在 Unity 中,重要的是空间观察器“OpenXR 空间网格观察器”存在于空间感知选项卡下检查器中的混合现实工具包游戏对象中。
如果是这种情况,以下代码应该可以工作:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Microsoft.MixedReality.Toolkit;
using Microsoft.MixedReality.Toolkit.SpatialAwareness;
using TMPro;
using Unity.VisualScripting;
using System.Globalization;
using System.IO;
using System;
public class Scanner_new : MonoBehaviour
{
public GameObject txt;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
public void Updater()
{
TextMeshPro textMesh = txt.GetComponent<TextMeshPro>();
// Use CoreServices to quickly get access to the IMixedRealitySpatialAwarenessSystem
var spatialAwarenessService = CoreServices.SpatialAwarenessSystem;
// Cast to the IMixedRealityDataProviderAccess to get access to the data providers
var dataProviderAccess = spatialAwarenessService as IMixedRealityDataProviderAccess;
// Get the SpatialObjectMeshObserver specifically
var meshObserverName = "OpenXR Spatial Mesh Observer";
var spatialObjectMeshObserver = dataProviderAccess.GetDataProvider<IMixedRealitySpatialAwarenessMeshObserver>(meshObserverName);
if(spatialObjectMeshObserver == null){
textMesh.text += "No Observer! \n";
return;
}
textMesh.text += "Accessing all the meshes: \n";
List<MeshFilter> meshes = new List<MeshFilter>();
// Loop through all known Meshes
foreach (SpatialAwarenessMeshObject meshObject in spatialObjectMeshObserver.Meshes.Values)
{
meshes.Add(meshObject.Filter);
}
create_obj(meshes, "\\Hello_World.obj");
}
private void create_obj(List<MeshFilter> meshes, string targetFileName){
TextMeshPro textMesh = txt.GetComponent<TextMeshPro>();
int adjust = 1;
MeshFilter[] mf = meshes.ToArray();
int countVertex = 0;
System.Text.StringBuilder objFileContent = new System.Text.StringBuilder(4096);
objFileContent.Append("# Automatic export of Hololens 2 scanned mesh scan. \r\n\r\n");
// for each object gets the vertexes normals and faces
for (int i = 0; i < mf.Length; i++)
{
Mesh m = mf[i].sharedMesh;
objFileContent.Append("o Object." + (i + 1) + "\r\n");
// inverts x as the coordinates are different from the ones of regular obj
foreach (Vector3 v in m.vertices)
{
float x = -v.x;
float z = v.z;
objFileContent.Append("v " + x.ToString("0.000000", CultureInfo.InvariantCulture) + " " + v.y.ToString("0.000000", CultureInfo.InvariantCulture) + " " + z.ToString("0.000000", CultureInfo.InvariantCulture) + "\r\n");
}
objFileContent.Append("\r\n\r\n");
foreach (Vector3 n in m.normals)
{
float x = n.x;
float z = n.z;
objFileContent.Append("vn " + x.ToString("0.000000", CultureInfo.InvariantCulture) + " " + n.y.ToString("0.000000", CultureInfo.InvariantCulture) + " " + z.ToString("0.000000", CultureInfo.InvariantCulture) + "\r\n");
}
objFileContent.Append("\r\n\r\n");
// the count of the faces starts with 1 and is cumulative for
// all objects on the scene this is why it is add
// adjust + countVertex as the id of the vertexes
for (int ti = 0; ti < m.triangles.Length; ti += 3)
{
objFileContent.Append("f " + (m.triangles[ti] + adjust + countVertex ) + "//" + (m.triangles[ti] + adjust + countVertex) + " " + (m.triangles[ti + 1] + adjust + countVertex) + "//" + (m.triangles[ti + 1] + adjust + countVertex) + " " + (m.triangles[ti + 2] + adjust + countVertex) + "//" + (m.triangles[ti + 2] + adjust + countVertex) + "\r\n");
}
objFileContent.Append("\r\n\r\n");
countVertex += m.vertexCount;
}
try{
// string objPath = Path.Combine(sceneFolderPath, sceneName + ".obj");
using (StreamWriter sw = File.CreateText(Application.persistentDataPath + targetFileName))
{
sw.WriteLine(objFileContent.ToString());
}
textMesh.text += "SUCCESS: OBJ SAVED";
}
catch(Exception e){
textMesh.text += e;
}
}
}
如您所见,代码直接从保存的数据生成一个 .obj 文件。此代码的灵感来自以下问题的答案:MRTK 2.4 - 在运行时保存空间网格
然后可以通过设备门户->文件资源管理器以及应用程序的 localState 文件夹访问 .obj 文件:)