Hololens Spatial Mapping功能实现
2017-02-22 15:52
309 查看
HoloToolkit项目是一组开发包,是微软基于unity内置的底层API封装的一套工具集合,帮助我们快速使用Unity集成开发hololens应用。
本文主要通过源码研究其中Spatial Mapping的实现,学会如何使用实现自己的三维空间重建。
Spatial Mapping目录下有很多内容,其中Prefabs目录里有我们可以直接使用的预置组件,本文关注的重点是Scripts目录的脚本。组件目录结构如下:
本文重点研究SpatialMappingObserver.cs和SpatialMappingSource.cs,这是当前组件的核心内容。
源码地址:https://github.com/Microsoft/HoloToolkit-Unity/blob/master/Assets/HoloToolkit/SpatialMapping/Scripts/SpatialMappingObserver.cs
我们先分析其属性,如下:
再分析其程序逻辑及流程:
Awake()方法最先被执行,这里对SurfaceObserver对象进行了初始化。
接下来是Start()方法,里面设定了扫描的空间范围。
Update()方法中则会根据当前状态来调用API请求空间表面信息或者生成mesh对象
SurfaceObserver_OnDataReady()事件方法用于处理使用SurfaceData请求到的mesh对象信息,用于后续的使用,比如处理其材质效果等。
SurfaceObserver_OnSurfaceChanged()事件方法用于处理SurfaceObserver获取到的空间表面数据,用于后续的请求mesh对象操作。
source
print?
本文主要通过源码研究其中Spatial Mapping的实现,学会如何使用实现自己的三维空间重建。
0x00 组件结构
本文重点研究SpatialMappingObserver.cs和SpatialMappingSource.cs,这是当前组件的核心内容。
0x01 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 { get ; private set ; }</surfacedata></surfacedata></ int ,></ int ,> |
Awake()方法最先被执行,这里对SurfaceObserver对象进行了初始化。
[代码]:
1 | private void Awake() |
2 | { |
3 | observer = new SurfaceObserver(); |
4 | ObserverState = ObserverStates.Stopped; |
5 | } |
[代码]:
1 | private void Start() |
2 | { |
3 | observer.SetVolumeAsAxisAlignedBox(Vector3.zero, Extents); |
4 | } |
[代码]:
01 | private void Update() |
02 | { |
03 |
04 | if (ObserverState == ObserverStates.Running) |
05 | { |
06 | // 如果当前没有再生成mesh,且SurfaceData中有需要生成mesh的对象 |
07 | if (surfaceWorkOutstanding == false && |
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 | } |
[代码]:
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> |
[代码]:
viewsource
print?
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( null , string .Format( "Surface-{0}" , |
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 |
相关文章推荐
- HoloLens开发——Hololens Spatial mapping(空间映射)中移动子模型后父模型移动的实现方法
- HoloToolkit项目源码剖析 - Spatial Mapping功能实现
- Unity中实现Hololens的三维空间映射Spatial mapping
- HoloLens开发笔记-瞬移功能实现
- 如何在Java应用程序中实现copy图像功能。
- Js中实现拼音和UrlEncode的功能(利用GB和Unicode对照表)
- 实现类似IE的打印网页功能
- 在java中实现对FORM的打印功能
- 用ASP实现论坛的UBB功能
- 用VJ++实现FTP的功能
- 实现网络蚂蚁的实时监视剪贴板功能
- C语言使用openSSL库DES模块实现加密功能详解
- 一组实现邮件发送功能的c++封装类(附源码)
- 利用C++Builder 中OLE自动化功能实现调用Word进行报表制作
- 在JAVA应用程序中如何实现FTP的功能
- 设计模式:利用Command模式实现无限次数的Undo/Redo功能
- 用delphi实现冰河的远程屏幕操作功能
- 完全用 VB 6.0 自身功能实现对 Windows 消息的拦截!
- 在VB中实现PickList功能
- 我在开发过程总结的一套实现常用功能的函数