Hololens Spatial Mapping功能实现

HoloToolkit项目是一组开发包,是微软基于unity内置的底层API封装的一套工具集合,帮助我们快速使用Unity集成开发hololens应用。

本文主要通过源码研究其中Spatial Mapping的实现,学会如何使用实现自己的三维空间重建。

 Hololens Spatial Mapping功能实现

0x00 组件结构


 

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

 

Hololens Spatial Mapping功能实现

 

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

 

Hololens Spatial Mapping功能实现

 

0x01 SpatialMappingObserver.cs


 

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

 我们先分析其属性,如下:

[代码]:

01 //每立方米网格三角形数量,控制mesh质量
02         public float TrianglesPerCubicMeter = 500f;
03  
04        //当前Observer检测的空间范围
05         public Vector3 Extents = Vector3.one * 10.0f;
06  
07         //刷新时间间隔
08         public float TimeBetweenUpdates = 3.5f;
09  
10         //用于扫描空间平面的核心组件
11         private SurfaceObserver observer;
12  
13         //存储已构建的空间网格对象
14         private Diction<a href="http://www.52vr.com/armr/" style="font-weight: bold;color: ;" target="_blank">AR</a>y<int, gameobject=""> surfaces = new Dictionary<int, gameobject="">();
15  
16         //SurfaceData队列,用于生成空间mesh
17         private Queue<surfacedata> surfaceWorkQueue = new Queue<surfacedata>();
18  
19         //为了避免同一时刻生成太多mesh,保证同一时刻只生成一个mesh,这个变量用于判断当前时刻是否有mesh正在创建
20         private bool surfaceWorkOutstanding = false;
21  
22         //用于追踪Observer对象上次更新时间
23         private float updateTime;
24  
25         //表示当前扫描状态,Running和Stopped两种状态
26         public ObserverStates ObserverState { getprivate set; }</surfacedata></surfacedata></int,></int,>


 再分析其程序逻辑及流程:

  • Awake()方法最先被执行,这里对SurfaceObserver对象进行了初始化。

 

[代码]:

1 private void Awake()
2        {
3            observer = new SurfaceObserver();
4            ObserverState = ObserverStates.Stopped;
5        }

  • 接下来是Start()方法,里面设定了扫描的空间范围。

 

[代码]:

1 private void Start()
2         {
3             observer.SetVolumeAsAxisAlignedBox(Vector3.zero, Extents);
4         }

  • Update()方法中则会根据当前状态来调用API请求空间表面信息或者生成mesh对象

 

[代码]:

01 private void Update()
02         {
03              
04             if (ObserverState == ObserverStates.Running)
05             {
06                 // 如果当前没有再生成mesh,且SurfaceData中有需要生成mesh的对象
07                 if (surfaceWorkOutstanding == false && surfaceWorkQueue.Count > 0)
08                 {
09                      
10                     SurfaceData surfaceData = surfaceWorkQueue.Dequeue();
11  
12                     // 如果能成功请求到mesh对象,当前任务状态变为生成mesh中
13                     surfaceWorkOutstanding = observer.RequestMeshAsync(surfaceData, SurfaceObserver_OnDataReady);
14                 }
15                 //如果当前没有任务运行且上次更新距现在大于时间间隔,则重新请求SurfaceData数据
16                 else if (surfaceWorkOutstanding == false && (Time.time - updateTime) >= TimeBetweenUpdates)
17                 {
18                     observer.Update(SurfaceObserver_OnSurfaceChanged);
19                     updateTime = Time.time;
20                 }
21             }
22         }

  • SurfaceObserver_OnDataReady()事件方法用于处理使用SurfaceData请求到的mesh对象信息,用于后续的使用,比如处理其材质效果等。

 

[代码]:

01 private void SurfaceObserver_OnDataReady(SurfaceData cookedData, bool outputWritten, float elapsedCookTimeSeconds)
02         {
03             GameObject surface;
04             if (surfaces.TryGetValue(cookedData.id.handle, out surface))
05             {
06                 // 设置 renderer组件的材质.
07                 MeshRenderer renderer = surface.GetComponent<meshrenderer>();
08                 renderer.sharedMaterial = SpatialMappingManager.Instance.SurfaceMaterial;
09                 //是否渲染mesh对象
10                 renderer.enabled = SpatialMappingManager.Instance.DrawVisualMeshes;
11  
12                 if (SpatialMappingManager.Instance.CastShadows == false)
13                 {
14                     renderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
15                 }
16             }
17  
18             surfaceWorkOutstanding = false;
19         }</meshrenderer>

  • SurfaceObserver_OnSurfaceChanged()事件方法用于处理SurfaceObserver获取到的空间表面数据,用于后续的请求mesh对象操作。

 

[代码]:

01 private void SurfaceObserver_OnSurfaceChanged(SurfaceId id, SurfaceChange changeType, Bounds bounds, System.DateTime updateTime)
02         {
03             // 判断当前扫描状态
04             if (ObserverState != ObserverStates.Running)
05             {
06                 return;
07             }
08  
09             GameObject surface;
10  
11             switch (changeType)
12             {
13                  
14                 case SurfaceChange.Added:
15                 case SurfaceChange.Updated:
16                     // 检测当前表面是否已被扫描过
17                     if (!surfaces.TryGetValue(id.handle, out surface))
18                     {
19                         // 创建一个和当前表面关联的mesh对象
20                         surface = AddSurfaceObject(nullstring.Format("Surface-{0}", id.handle), transform);
21  
22                         surface.AddComponent<worldanchor>();
23  
24                         // 将surface对象加入已知空间表面字典
25                         surfaces.Add(id.handle, surface);
26                     }
27  
28                     // 请求生成或更新对应的mesh对象
29                     QueueSurfaceDataRequest(id, surface);
30                     break;
31  
32                 case SurfaceChange.Removed:
33                     // 移除关联的mesh对象
34                     if (surfaces.TryGetValue(id.handle, out surface))
35                     {
36                         surfaces.Remove(id.handle);
37                         Destroy(surface);
38                     }
39                     break;
40             }
41         }</worldanchor>
本文转自:52VR.com  Hololens http://www.52vr.com/article-794-1.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值