You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 09:34:51