Zion插件分析——ZionRender.cs
发表于2016-10-31
Zion渲染器,控制渲染流程。和ZionVR一样,也是以单例形式工作,它有一个存放ZionCamera的数组,在渲染协程中将这些相机的位置移动到眼睛的位置,然后看到的场景渲染到各自的共享渲染纹理中去。对于某些设备,在头显失去焦点的时候,暂停画面渲染,画面保持不动(例如Oculus游戏中,摘下头盔,游戏暂停)。
UML类图
字段
· _pauseRendering:是否暂停渲染
· timeScale:游戏暂停前的timeScale
· cameras:ZionCamera数组
· isQuitting:是否正在退出
· poses:保存3个跟踪设备的索引,分别是头显、左、右控制器
· tracker:跟踪器,用于更新跟踪设备位置
· PoseType:TODO 设置姿态
· behaviour:各平台自己的ZionMonoBehaviour实现对象
属性
· eye: 当前渲染的是左眼还是右眼
· instance: 单例,获取时会检测场景中是否存在ZionRender.cs脚本,如果不存在,会新建一个名为[ZionVR]的空对象,在上面添加组件ZionRender
· pauseRendering 是否暂停渲染
静态方法
Add(ZionCamera vrcam)
如果没有正在退出,就调用instance.AddInternal(vrcam);,添加一个ZionCamera。
Remove(ZionCamera vrcam)
如果没有正在退出,就调用instance.RemoveInternal(vrcam);,移除传入的ZionCamera。
Top()
如果没有正在退出,就调用instance.TopInternal();,返回顶层相机(最后渲染的相机)。
构造方法
ZionRender ()
实例化当前连接设备的MonoBehaviour。
1 2 3 4 | public ZionRender () { behaviour = ZionVR.CreateMonoBehaviour (); } |
MonoBehaviour相关方法
OnDestroy()
调用平台自己的MonoBehaviour实现方法behaviour.OnDestroy ();,并置当前单例为null。
OnApplicationQuit()
程序退出,调用ZionVR的方法,安全释放资源。
1 2 | isQuitting = true ; ZionVR.SafeDispose(); |
OnEnable()
脚本甫一可用,先实例化ZionVR,得到单例vr,如果实例化成功,那么ZionVR应该已经获知当前连接设备的类型,如果没有连接任何VR设备,那么ZionVR.instance.vrType == EVRType.None,此时直接禁用ZionRender.cs,因为既然没有连接VR设备,就不需要走VR渲染的流程了,直接进去2D模式,使用Unity缺省渲染流程即可。
接下来,获取平台的追踪器实现类。启动核心渲染协程,回调平台实现后的OnEnable()。
1 2 3 | StartCoroutine( "RenderLoop" ); … behaviour.OnEnable (); |
将脚本中的OnVRFocus加入到ZionEvent中的委托链。
1 | ZionEvent.Listen (ZionEvent.VR_FOCUS, OnVRFocus); |
OnDisable()
停止所有协程,回调平台实现的OnDisable ()。
1 2 3 | StopAllCoroutines(); … behaviour.OnDisable (); |
将OnVRFocus从ZionEvent的委托链移除
1 | ZionEvent.Remove (ZionEvent.VR_FOCUS, OnVRFocus); |
Update()
实时检测设备连接情况,一旦检测到未连接VR设备,禁用自身。更新手柄状态,最后回调平台实现的Update()。
1 | behaviour.Update (); |
FixedUpdate()
回调平台实现的FixedUpdate()。
1 | behaviour.FixedUpdate (); |
实例方法
AddInternal(ZionCamera vrcam)
将vrcam添加到脚本中的ZionCamera数组,但是不是直接添加,要根据相机组件的深度来排序数组。
Camera.depth 深度
var depth : float
Description描述
Camera’s depth in the camera rendering order.
相机在渲染顺序上的深度。
Cameras with lower depth are rendered before cameras with higher depth.
具有较低深度的相机将在较高深度的相机之前渲染。
1、得到vrcam上的相机组件camera。
2、获取目前的ZionCamera数组cameras的长度,用此长度加一,新建一个扩容数组sorted。
3、遍历cameras,一一与vrcam上的相机组件camera对比深度,如果cameras中的相机深度比camera的小,那么直接按同样的索引复制到sorted数组中。如果某相机的深度比camera的大,那么它这个位置就要腾给vrcam,然后剩余的位置就继续复制cameras中的ZionCamera。
4、对比复制完以后,更新当前ZionCamera数组为扩容数组sorted,使当前脚本可用。
RemoveInternal(ZionCamera vrcam)
将vrcam从ZionCamera数组cameras中移除。由于可能重复添加过,所以先计算数组中vrcam的数量,然后新建一个数组,长度为现在的长度减去这个数量。再按顺序遍历数组,将不是vrcam的ZionCamera复制到新数组中,将当前的cameras更新为新数组。如果最后得到的数组为空,就禁用当前脚本。
TopInternal()
获取顶层(最后渲染)的相机。由于存放的时候我们已经按照相机深度(渲染顺序)排序,所以此时取出cameras的最后一项即可。
1 | return cameras[cameras.Length - 1]; |
RenderLoop()
渲染协程,在每帧的最后调用。流程是
1、如果pauseRendering为true就忽略下面所有操作直接进行下一次流程。
2、获取跟踪设备的姿态,通知ZionEvent更新姿态。
3、执行手动渲染程序,如果是单眼模式,就渲染左眼,如果是双眼模式,渲染完左眼还要渲染右眼。
RenderEye(ZionVR vr, EEyeType eye)
手动渲染。一次只能渲染一只眼睛,取眼睛的位置时要注意。ZionVR中两只眼睛的存放数组,下标从0开始。但是EEyeType的定义里,
1 2 3 4 5 6 | public enum EEyeType { Left = 1, Right = 2, Both = 3, } |
所以,转成ZionVR的眼睛索引时,要减去一。
遍历cameras,逐个相机渲染,排在前面的深度小,先渲染。将相机的位置移动到眼睛的位置,然后把此时相机看到的场景渲染到共享渲染纹理上去,然后执行相机渲染。最后恢复相机位置。
1 2 3 | var camera = c.GetComponent(); camera.targetTexture = c.GetRenderTexture(eye, camera.hdr); camera.Render(); |
GetCurPoses()
获取所有跟踪器的位置,返回数组。
GetCurPose(uint index)
获取单个追踪器的位置
OnVRFocus(params object[] args)
action,实现暂停游戏逻辑,传入false时暂停。
1 2 | timeScale = Time.timeScale; //保存暂停前的timeScale Time.timeScale = 0.0f; |