該項目地址: 地址
克隆地址為 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樂這個工程,做了一點點自己的修改,歡迎圍觀:
地址