HoloToolkit項目源碼剖析 - Spatial Mapping功能實現

來源:互聯網
上載者:User

標籤:

就像我之前所描述的,HoloToolkit項目是微軟基於Unity內建的底層API封裝的一套工具集合,協助我們快速使用Unity整合開發HoloLens應用。

本文主要通過源碼研究其中Spatial Mapping的實現,關於底層的API細節,請閱讀我前一篇文章:HoloLens開發手記 - Unity之Spatial mapping 空間映射

 

0x00 組件結構 

Spatial Mapping目錄下有很多內容,其中Prefabs目錄裡有我們可以直接使用的預置組件,本文關注的重點是Scripts目錄的指令碼。組件目錄結構如下:

 

 

本文重點研究SpatialMappingObserver.cs和SpatialMappingSource.cs,這是當前組件的核心內容。

 

 

0x01 SpatialMappingObserver.cs 

源碼地址:https://github.com/Microsoft/HoloToolkit-Unity/blob/master/Assets/HoloToolkit/SpatialMapping/Scripts/SpatialMappingObserver.cs

 我們先分析其屬性,如下:

 

        //每立方米網格三角形數量,控制mesh品質        public float TrianglesPerCubicMeter = 500f;       //當前Observer檢測的空間範圍        public Vector3 Extents = Vector3.one * 10.0f;        //重新整理時間間隔        public float TimeBetweenUpdates = 3.5f;        //用於掃描空間平面的核心組件        private SurfaceObserver observer;        //儲存已構建的空間網格對象        private Dictionary<int, GameObject> surfaces = new Dictionary<int, GameObject>();        //SurfaceData隊列,用於產生空間mesh        private Queue<SurfaceData> surfaceWorkQueue = new Queue<SurfaceData>();        //為了避免同一時刻產生太多mesh,保證同一時刻只產生一個mesh,這個變數用於判斷當前時刻是否有mesh正在建立        private bool surfaceWorkOutstanding = false;        //用於追蹤Observer對象上次更新時間        private float updateTime;        //表示當前掃描狀態,Running和Stopped兩種狀態        public ObserverStates ObserverState { get; private set; }

 

 再分析其程式邏輯及流程:

  • Awake()方法最先被執行,這裡對SurfaceObserver對象進行了初始化。

 

 private void Awake()        {            observer = new SurfaceObserver();            ObserverState = ObserverStates.Stopped;        }

 

  • 接下來是Start()方法,裡面設定了掃描的空間範圍。

 

private void Start()        {            observer.SetVolumeAsAxisAlignedBox(Vector3.zero, Extents);        }

 

  • Update()方法中則會根據目前狀態來調用API請求空間表面資訊或者產生mesh對象

 

private void Update()        {                        if (ObserverState == ObserverStates.Running)            {                // 如果當前沒有再產生mesh,且SurfaceData中有需要產生mesh的對象                if (surfaceWorkOutstanding == false && surfaceWorkQueue.Count > 0)                {                                        SurfaceData surfaceData = surfaceWorkQueue.Dequeue();                    // 如果能成功請求到mesh對象,當前任務狀態變為產生mesh中                    surfaceWorkOutstanding = observer.RequestMeshAsync(surfaceData, SurfaceObserver_OnDataReady);                }                //如果當前沒有任務運行且上次更新距現在大於時間間隔,則重新請求SurfaceData資料                else if (surfaceWorkOutstanding == false && (Time.time - updateTime) >= TimeBetweenUpdates)                {                    observer.Update(SurfaceObserver_OnSurfaceChanged);                    updateTime = Time.time;                }            }        }

 

  • SurfaceObserver_OnDataReady()事件方法用於處理使用SurfaceData請求到的mesh對象資訊,用於後續的使用,比如處理其材質效果等。

 

private void SurfaceObserver_OnDataReady(SurfaceData cookedData, bool outputWritten, float elapsedCookTimeSeconds)        {            GameObject surface;            if (surfaces.TryGetValue(cookedData.id.handle, out surface))            {                // 設定 renderer組件的材質.                MeshRenderer renderer = surface.GetComponent<MeshRenderer>();                renderer.sharedMaterial = SpatialMappingManager.Instance.SurfaceMaterial;
//是否渲染mesh對象 renderer.enabled = SpatialMappingManager.Instance.DrawVisualMeshes; if (SpatialMappingManager.Instance.CastShadows == false) { renderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; } } surfaceWorkOutstanding = false; }

 

  • SurfaceObserver_OnSurfaceChanged()事件方法用於處理SurfaceObserver擷取到的空間表面資料,用於後續的請求mesh對象操作。

 

  private void SurfaceObserver_OnSurfaceChanged(SurfaceId id, SurfaceChange changeType, Bounds bounds, System.DateTime updateTime)        {            // 判斷當前掃描狀態            if (ObserverState != ObserverStates.Running)            {                return;            }            GameObject surface;            switch (changeType)            {                                case SurfaceChange.Added:                case SurfaceChange.Updated:                    // 檢測當前表面是否已被掃描過                    if (!surfaces.TryGetValue(id.handle, out surface))                    {                        // 建立一個和當前表面關聯的mesh對象                        surface = AddSurfaceObject(null, string.Format("Surface-{0}", id.handle), transform);                        surface.AddComponent<WorldAnchor>();                        // 將surface對象加入已知空間表面字典                        surfaces.Add(id.handle, surface);                    }                    // 請求產生或更新對應的mesh對象                    QueueSurfaceDataRequest(id, surface);                    break;                case SurfaceChange.Removed:                    // 移除關聯的mesh對象                    if (surfaces.TryGetValue(id.handle, out surface))                    {                        surfaces.Remove(id.handle);                        Destroy(surface);                    }                    break;            }        }

 

HoloToolkit項目源碼剖析 - Spatial Mapping功能實現

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.