Hololens2运行时获取空间映射网格失败问题求助
HoloLens2 空间映射网格获取失败问题解决(MRTK 2.8.3 + Unity 2022.3)
核心问题分析
你的代码存在几个关键问题导致无法获取网格:
- 执行时机过早:
Start()在场景加载后立即执行,此时空间扫描尚未启动或生成网格;Updater()的count逻辑一旦触发(哪怕未获取到网格)就会停止后续检测。 - 未监听网格异步事件:MRTK空间网格是异步生成/更新的,主动轮询无法保证在网格就绪时获取数据。
- 可能的配置缺失:空间感知服务、Mesh Observer未正确启用,或缺少设备权限。
分步解决方案
1. 检查项目基础配置
- MRTK空间感知配置:
选中场景中的MixedRealityToolkit对象,打开Spatial Awareness标签页:- 勾选
Enable Spatial Awareness启用服务 - 在
Spatial Mesh Observer配置中,设置Mesh Density为Medium或更高,Update Interval设为非0值(如0.1秒),Start Behavior选择StartAutomatic
- 勾选
- Unity权限配置:
打开Player Settings→Windows→Capabilities,勾选SpatialPerception权限,这是HoloLens获取空间数据的必要权限。
2. 修正代码:监听网格更新事件
替换原有代码,通过MRTK的网格事件监听机制,确保在网格就绪时获取数据,并实现OBJ导出功能:
using System.Collections.Generic; using UnityEngine; using Microsoft.MixedReality.Toolkit; using Microsoft.MixedReality.Toolkit.SpatialAwareness; using TMPro; public class Scanner_new : MonoBehaviour { public TextMeshPro statusText; private IMixedRealitySpatialAwarenessMeshObserver meshObserver; private List<Mesh> collectedMeshes = new List<Mesh>(); void Start() { // 初始化空间感知服务与观察者 var spatialService = CoreServices.SpatialAwarenessSystem; var providerAccess = spatialService as IMixedRealityDataProviderAccess; meshObserver = providerAccess?.GetDataProvider<IMixedRealitySpatialAwarenessMeshObserver>(); if (meshObserver == null) { statusText.text = "无法获取Mesh Observer"; Debug.LogError("无法获取Mesh Observer"); return; } // 注册网格事件监听 meshObserver.MeshAdded += OnMeshReady; meshObserver.MeshUpdated += OnMeshReady; statusText.text = "正在扫描空间,请移动设备...\n"; } void OnDestroy() { // 销毁时移除监听,避免内存泄漏 if (meshObserver != null) { meshObserver.MeshAdded -= OnMeshReady; meshObserver.MeshUpdated -= OnMeshReady; } } // 网格新增/更新时触发 private void OnMeshReady(object sender, SpatialAwarenessMeshEventArgs args) { var targetMesh = args.MeshObject.Filter.mesh; if (targetMesh == null) return; // 更新状态文本 statusText.text = $"已捕获网格:顶点数={targetMesh.vertexCount} | 三角面数={targetMesh.triangles.Length/3}\n"; // 收集网格(如需合并导出可在此累积) if (!collectedMeshes.Contains(targetMesh)) { collectedMeshes.Add(targetMesh); } } // 手动触发导出(可绑定到UI按钮) public void ExportAllMeshesToOBJ() { if (collectedMeshes.Count == 0) { statusText.text = "无可用网格可导出\n"; return; } // 合并所有网格为单个Mesh(可选,按需使用) Mesh mergedMesh = MergeMeshes(collectedMeshes); string exportPath = Application.persistentDataPath + "/RoomScan.obj"; // 写入OBJ文件 WriteMeshToOBJ(mergedMesh, exportPath); statusText.text += $"导出完成:{exportPath}\n"; Debug.Log($"OBJ导出路径:{exportPath}"); } // 合并多个Mesh为单个Mesh的工具方法 private Mesh MergeMeshes(List<Mesh> meshes) { Mesh merged = new Mesh(); List<Vector3> vertices = new List<Vector3>(); List<int> triangles = new List<int>(); foreach (Mesh mesh in meshes) { int vertexOffset = vertices.Count; vertices.AddRange(mesh.vertices); foreach (int tri in mesh.triangles) { triangles.Add(tri + vertexOffset); } } merged.vertices = vertices.ToArray(); merged.triangles = triangles.ToArray(); merged.RecalculateNormals(); return merged; } // 将Mesh写入OBJ文件的工具方法 private void WriteMeshToOBJ(Mesh mesh, string filePath) { string objContent = "o RoomScan\n"; // 写入顶点数据 foreach (Vector3 vert in mesh.vertices) { objContent += $"v {vert.x:F6} {vert.y:F6} {vert.z:F6}\n"; } // 写入三角面数据(OBJ索引从1开始) int[] tris = mesh.triangles; for (int i = 0; i < tris.Length; i += 3) { objContent += $"f {tris[i]+1} {tris[i+1]+1} {tris[i+2]+1}\n"; } System.IO.File.WriteAllText(filePath, objContent); } }
3. 额外注意事项
- 设备测试:需在HoloLens设备上测试,移动设备扫描周围环境10-30秒,等待系统生成完整空间网格。
- 导出触发:建议将
ExportAllMeshesToOBJ()绑定到UI按钮,由用户手动触发导出,避免频繁写入文件影响性能。 - 网格合并:如果不需要合并网格,可直接遍历
collectedMeshes逐个导出单独的OBJ文件。
内容的提问来源于stack exchange,提问作者Cytox_99
相关产品推荐
相关产品推荐

