您的位置:首页 > 移动开发

Hololens Spatial Mapping功能实现

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

本文主要通过源码研究其中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

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

[代码]:

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
}
接下来是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对象操作。

[代码]:

view
source

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}"
,
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Hololens AR Spatial Mapping