该项目地址: 地址
克隆地址为 https://github.com/rsanchezsaez/CardboardSDK-iOS.git
目前如果想在iOS设备上实现双目VR的功能,Google 已经提供了官方的sdk,上手简单,但是由于在实际使用中有其他需求,GVR的源码无法修改,所以还是使用这个野生的SDK来开发。这篇文章主要就是简单分析一下这个sdk的ViewController 的代码,至于内部的复杂数学计算,暂时无法涉及。
CBDViewController
主要要分析的就是 CBDViewController
这个类,其继承了 GLKViewController
并实现樂 GLKViewControllerDelegate
这个接口。成员:stereoRendererDelegate
负责实现若干个回调函数,比如在Cardboard各个设置完成后进行所需的绘制工作。
1. Init
初始化各个成员变量,设置GLKViewController的delegate为self,启动设备的传感器,开始监听。
2. ViewDidLoad
创建OpenGL的Context 并回调 [self.stereoRendererDelegate setupRendererWithView:self.view]
此时设置Context为 glview.context
,可以进行绘制的准备工作,比如创建program 上传attribute,uniform的数据。
3. glkViewControllerUpdate:(GLKViewController *)controller
Called before each frame is displayed, 所以此处所做的事情主要是根据传感器数据计算出绘制所需的参数,主要是变换矩阵,fov和viewport仅需要在更新视窗的时候更新。
调用 calculateFrameParametersWithHeadTransform...
函数,该函数主要功能:
- (VR模式下) 根据当前传感器数据计算出各变换矩阵,存入
leftEye
和rightEye
对象中去。 - (非VR模式下)
monocularEye
更新viewport - (若需要时)更新左右眼的fov:
updateFovsWithLeftEyeFov:leftEye->fov() rightEyeFov:rightEye->fov()
然后调用_distortionRenderer->fovDidChange(...)
计算结果存储在传入的leftEye
rightEye
参数中。具体内容为:-
updateFovsWithLeftEyeFov...
:计算出上下左右四个方向的fov角
-
-
fovDidChange(...)
: 根据fov值计算出两个眼的viewport具体数值。
-
-
_distortionRenderer->updateViewports(leftEye->viewport(), rightEye->viewport())
更新左右眼的viewport
4. glkView:(GLKView *)view drawInRect:(CGRect)rect
绘制的回调函数。
_distortionRenderer->beforeDrawFrame()
- (需要时)
updateTextureAndDistortionMesh()
(See [1]) glBindFramebuffer
-
drawFrameWithHeadTransform(...)
回调:
[self.stereoRendererDelegate prepareNewFrameWithHeadViewMatrix:headTransform->headView()];
// ...
[self.stereoRendererDelegate drawEyeWithEye:_leftEyeWrapper];
// ...
[self.stereoRendererDelegate drawEyeWithEye:_rightEyeWrapper];
Rebind original framebuffer
_distortionRenderer->afterDrawFrame()
--->undistortTexture(_textureID)
(See [2])
5)finishFrameWithViewPort
: callback: stereoRendererDelegate finishFrameWithViewportRect:
需要分析说明的如下
[1] DistortionRenderer::updateTextureAndDistortionMesh()
:
- create mesh
- setup rendertexture and renderbuffer
首先创建两个program用于绘制畸变校正。这两个program的区别在于纹理,无矫正只有一个纹理sampler,带矫正的分别有RGB三个纹理sampler. 然后计算畸变矫正所需参数然后创建 DistortionMesh 对象: 创建对象时生成所需的vertexData和indexData 并绑定到相应的array buffer上面去。 再之后创建纹理、renderbuffer和framebuffer.这里创建的就是用于off-screen render的framebuffer,所以这里创建的纹理,其内容是空的,glTexImage2D(GL_TEXTURE_2D, 0, textureFormat, width, height, 0, textureFormat, textureType, nil);
因为这个SDK的功能就是留出这么一块framebuffer来给调用者绘制,绘制完了以后他自己将其当作纹理经过矫正后分别绘制到两个眼睛上面去。
[2] undistortTexture(_textureID)
:
做一OpenGL状态的备份:将所有的OpenGL状态相关信息统统保存下来。若需要时,仍然是调用一遍 updateTextureAndDistortionMesh
. 调用 renderDistortionMesh(_leftEyeDistortionMesh, textureID)
内部实现:目前已知vertexData indexData以及TextureId 将这些数据统统上传至畸变矫正用的program上,并绘制。完成后将保存的gl信息统统设置回去。
简单使用
分析提供的例子可知,简单使用时只需要继承这个CBDViewController类,并实现几个GLKViewController的方法,设置好stereoRendererDelegate 即可。主要的工作就是stereoRendererDelegate完成的,回调函数一览:
@protocol CBDStereoRendererDelegate <NSObject>
- (void)setupRendererWithView:(GLKView *)glView;
- (void)shutdownRendererWithView:(GLKView *)glView;
- (void)renderViewDidChangeSize:(CGSize)size;
- (void)prepareNewFrameWithHeadViewMatrix:(GLKMatrix4)headViewMatrix;
- (void)drawEyeWithEye:(CBDEye *)eye;
- (void)finishFrameWithViewportRect:(CGRect)viewPort;
@optional
- (void)triggerPressed;
@end
最后
我fork樂这个工程,做了一点点自己的修改,欢迎围观:
地址