本指南將說明如何使用適用於 iOS 的 Cardboard SDK 建立自己的虛擬 實境 (VR) 體驗。
您可以使用 Cardboard SDK 讓智慧型手機搖身一變,成為 VR 平台。智慧型手機 能夠顯示立體聲算繪 3D 場景,追蹤頭部動作並做出回應。 與應用程式互動的方式,偵測使用者何時按下檢視器按鈕。
首先,請使用 HelloCardboard,這是示範核心功能的示範遊戲 正是 Cardboard SDK 的一部分在遊戲中,使用者會環遊虛擬世界,尋找並收集 如需儲存大量結構化物件 建議使用 Cloud Bigtable這項工具將說明如何:
- 設定開發環境
- 下載並建構試用版應用程式
- 掃描 Cardboard 觀影盒的 QR 圖碼,即可儲存參數
- 追蹤使用者的頭部動作
- 設定正確的視線扭曲變形,即可呈現立體聲圖片
設定開發環境
硬體需求:
- 搭載 iOS 12.0 以上版本的 iPhone
- Cardboard 觀影盒
軟體需求:
- Xcode 12.5 以上版本
- CocoaPods 1.9 以上版本
下載並建構試用版應用程式
Cardboard SDK 是以預先編譯的通訊協定緩衝區建構而成 C++ 來源檔案。瞭解從頭開始建構來源檔案的步驟 請按這裡。
- 從 GitHub 複製 Cardboard SDK 和 Hello Cardboard 試用版應用程式,方法如下: 執行下列指令: - git clone https://github.com/googlevr/cardboard.git 
- 在存放區根目錄執行下列指令,將通訊協定緩衝區依附元件安裝到 Xcode 專案: - pod install 
- 在 Xcode 中開啟 Cardboard 工作區 ( - Cardboard.xcworkspace)。
- 變更應用程式的軟體包 ID,以便與團隊成員簽署應用程式。 
- 依序前往「SDK」>「建構階段」>連結二進位檔與程式庫 - 請選取「libPods-sdk.a」並從清單中移除,並按一下「-」按鈕。
- 按一下「+」將「libProtobuf-C++.a」加入清單並選取該按鈕。如果系統出現建議使用 XCFramework 彈出式視窗的訊息,請點選「Add Anyway」。
 
- 請選取「
- 按一下「執行」。 
掃描 QR code
如要儲存裝置參數,請掃描 Cardboard 觀影盒上的 QR 圖碼:
立即試用
在 HelloCardboard 中,我們會在 3D 空間中尋找並收集測地球體。
如何尋找及收集球體:
- 朝任何方向移動頭部,直到看見浮動的球體為止。 
- 直視球體。這會改變顏色。 
- 按下 Cardboard 觀影盒按鈕即可「收集」進行研究 
設定裝置
當使用者輕觸齒輪圖示來切換 Cardboard 觀影盒時,didTapSwitchButton
方法是在 HelloCardboardOverlayView 中呼叫
- (void)didTapSwitchButton:(id)sender {
  if ([self.delegate respondsToSelector:@selector(didTapBackButton)]) {
    [self.delegate didChangeViewerProfile];
  }
  self.settingsBackgroundView.hidden = YES;
}
這會呼叫 CardboardQrCode_scanQrCodeAndSaveDeviceParams,利用
視窗,用於掃描觀眾的 QR code。使用者掃描 QR code 時,
變形參數會更新。
- (void)switchViewer {
  CardboardQrCode_scanQrCodeAndSaveDeviceParams();
}
- (void)didChangeViewerProfile {
  [self pauseCardboard];
  [self switchViewer];
  [self resumeCardboard];
}
頭部追蹤
建立頭部追蹤工具
頭部追蹤程式會在 HelloCardboardViewController 的 viewDidLoad 方法中建立一次:
_cardboardHeadTracker = CardboardHeadTracker_create();
暫停及恢復頭部追蹤工具
程式碼中的 pauseCardboard 和 resumeCardboard 方法
HelloCardboardViewController 類別暫停並恢復頭部追蹤器,
。resumeCardboard 也會設定 _updateParams 標記,這會導致
要在下一個繪製呼叫中更新的裝置參數。
- (void)pauseCardboard {
  self.paused = true;
  CardboardHeadTracker_pause(_cardboardHeadTracker);
}
- (void)resumeCardboard {
  // Parameters may have changed.
  _updateParams = YES;
  // Check for device parameters existence in app storage. If they're missing,
  // we must scan a Cardboard QR code and save the obtained parameters.
  uint8_t *buffer;
  int size;
  CardboardQrCode_getSavedDeviceParams(&buffer, &size);
  if (size == 0) {
    [self switchViewer];
  }
  CardboardQrCode_destroy(buffer);
  CardboardHeadTracker_resume(_cardboardHeadTracker);
  self.paused = false;
}
鏡頭變形
每當 Cardboard 掃描新的 QR 圖碼時,下列程式碼就會讀取已儲存的參數 並用於製作鏡頭扭曲失真物件,藉此套用適當的鏡頭扭曲失真 添加到轉譯內容:
CardboardQrCode_getSavedDeviceParams(&encodedDeviceParams, &size);
// Create CardboardLensDistortion.
CardboardLensDistortion_destroy(_cardboardLensDistortion);
_cardboardLensDistortion =
    CardboardLensDistortion_create(encodedDeviceParams, size, width, height);
// Initialize HelloCardboardRenderer.
_renderer.reset(new cardboard::hello_cardboard::HelloCardboardRenderer(
      _cardboardLensDistortion, _cardboardHeadTracker, width, height));
轉譯
使用 Cardboard 轉譯內容時,請考量下列事項:
- 建立紋理
- 取得左右眼睛的檢視和投影矩陣
- 建立轉譯器及設定變形網格
- 算繪每個影格
建立紋理
內容是繪製在紋理上,並分為左右兩部分。
這些區段分別在 _leftEyeTexture 和 _rightEyeTexture 中初始化。
範例應用程式針對雙眼使用單一紋理,但您也可以建立個別的
為雙眼繪製紋理
// Generate texture to render left and right eyes.
glGenTextures(1, &_eyeTexture);
glBindTexture(GL_TEXTURE_2D, _eyeTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _width, _height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
_leftEyeTexture.texture = _eyeTexture;
_leftEyeTexture.left_u = 0;
_leftEyeTexture.right_u = 0.5;
_leftEyeTexture.top_v = 1;
_leftEyeTexture.bottom_v = 0;
_rightEyeTexture.texture = _eyeTexture;
_rightEyeTexture.left_u = 0.5;
_rightEyeTexture.right_u = 1;
_rightEyeTexture.top_v = 1;
_rightEyeTexture.bottom_v = 0;
CheckGLError("Create Eye textures");
這些紋理會以參數的形式傳入 CardboardDistortionRenderer_renderEyeToDisplay。
取得左右眼睛的矩陣投影和投影
首先,請擷取左右眼睛的眼睛矩陣:
CardboardLensDistortion_getEyeFromHeadMatrix(_lensDistortion, kLeft, _eyeMatrices[kLeft]);
CardboardLensDistortion_getEyeFromHeadMatrix(_lensDistortion, kRight, _eyeMatrices[kRight]);
CardboardLensDistortion_getProjectionMatrix(_lensDistortion, kLeft, kZNear, kZFar,
                                            _projMatrices[kLeft]);
CardboardLensDistortion_getProjectionMatrix(_lensDistortion, kRight, kZNear, kZFar,
                                            _projMatrices[kRight]);
接下來,取得每個眼睛的變形網格,並傳遞到變形轉譯器:
CardboardLensDistortion_getDistortionMesh(_lensDistortion, kLeft, &leftMesh);
CardboardLensDistortion_getDistortionMesh(_lensDistortion, kRight, &rightMesh);
建立轉譯器並設定正確的變形網格
轉譯器只需初始化一次。建立轉譯器後,請設定新的轉譯器
根據從感應器傳回的網格值,左右眼睛的扭曲網格
CardboardLensDistortion_getDistortionMesh 函式。
_distortionRenderer = CardboardOpenGlEs2DistortionRenderer_create();
CardboardDistortionRenderer_setMesh(_distortionRenderer, &leftMesh, kLeft);
CardboardDistortionRenderer_setMesh(_distortionRenderer, &rightMesh, kRight);
轉譯內容
從 CardboardHeadTracker_getPose 擷取目前的頭部方向:
CardboardHeadTracker_getPose(_headTracker, targetTime, position, orientation);
_headView =
    GLKMatrix4Multiply(GLKMatrix4MakeTranslation(position[0], position[1], position[2]),
                       GLKMatrix4MakeWithQuaternion(GLKQuaternionMakeWithArray(orientation)));
使用目前的頭部方向搭配檢視區塊和投影矩陣,建立檢視畫面 投影矩陣,並用它們呈現每個人的世界內容:
// Draw left eye.
glViewport(0, 0, _width / 2.0, _height);
glScissor(0, 0, _width / 2.0, _height);
DrawWorld(_leftEyeViewPose, GLKMatrix4MakeWithArray(_projMatrices[kLeft]));
// Draw right eye.
glViewport(_width / 2.0, 0, _width / 2.0, _height);
glScissor(_width / 2.0, 0, _width / 2.0, _height);
DrawWorld(_rightEyeViewPose, GLKMatrix4MakeWithArray(_projMatrices[kRight]));
使用 CardboardDistortionRenderer_renderEyeToDisplay 套用變形效果
將內容修正在畫面上
CardboardDistortionRenderer_renderEyeToDisplay(_distortionRenderer, renderTarget, /*x=*/0,
                                               /*y=*/0, _width, _height, &_leftEyeTexture,
                                               &_rightEyeTexture);