博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
HoloToolkit项目源码剖析 - Spatial Mapping功能实现
阅读量:6235 次
发布时间:2019-06-22

本文共 4756 字,大约阅读时间需要 15 分钟。

就像我之前所描述的,HoloToolkit项目是微软基于Unity内置的底层API封装的一套工具集合,帮助我们快速使用Unity集成开发HoloLens应用。

本文主要通过源码研究其中Spatial Mapping的实现,关于底层的API细节,请阅读我前一篇文章:

 

0x00 组件结构


 

Spatial Mapping目录下有很多内容,其中Prefabs目录里有我们可以直接使用的预置组件,本文关注的重点是Scripts目录的脚本。组件目录结构如下:

 

 

本文重点研究SpatialMappingObserver.cs和SpatialMappingSource.cs,这是当前组件的核心内容。

 

 

0x01 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
surfaces = new Dictionary
(); //SurfaceData队列,用于生成空间mesh private Queue
surfaceWorkQueue = new Queue
(); //为了避免同一时刻生成太多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
(); 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
(); // 将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; } }

 

转载地址:http://rcqna.baihongyu.com/

你可能感兴趣的文章
flutter中的异步
查看>>
IoC容器初始化过程(下)
查看>>
Python GIL
查看>>
DataWorks数据开发模块大改版灰度发布
查看>>
云吞铺子国际版 Mr.Cloud S1E3《Release Instances & Downgrade Configurations》
查看>>
《Groovy极简教程》第8章 Groovy:领域特定语言(DSL)
查看>>
第197天:js---caller、callee、constructor和prototype用法
查看>>
打造人才“云”梯,阿里云联合各高校开展云计算进校园系列活动
查看>>
vm12 安装ubuntu15.10详细图文教程 虚拟机安装ubuntu安装 ubuntu更新软件 ubuntu一直卡在下载语言怎么办?...
查看>>
vi/vim的三种基本工作模式
查看>>
程维:滴滴希望未来出行选择和调用飞机一样方便
查看>>
windows中使用Git创建分支(branch)?
查看>>
Zabbix3.0学习笔记
查看>>
【最佳实践】OSS开源工具ossutil-增量上传
查看>>
Python | Python学习之深浅拷贝
查看>>
初识Avro
查看>>
中国在人工智能领域成为全球最‘吸金’的国家
查看>>
Kubeflow实战系列:阿里云上使用JupyterHub
查看>>
研究人员成功从地面入侵飞行中的飞机
查看>>
关于代码的那些低级错误,都是血泪的教训
查看>>