本指南說明如何使用 iOS 版 Wear SDK,打造自己的虛擬實境 (VR) 體驗。
你可以使用 OpenGL SDK 將智慧型手機變成 VR 平台。智慧型手機可以顯示 3D 情境與立體成像的算繪、追蹤頭部動作並回應頭部動作,以及偵測使用者何時按下檢視器按鈕,來與應用程式互動。
如要開始使用,你會使用 HelloCardboard 示範遊戲,示範 Wear SDK 的核心功能。在遊戲中,使用者會探索虛擬世界,以便尋找和收集物件。其中說明如何:
- 設定開發環境
- 下載並建構試用版應用程式
- 掃描 VR 檢視器的 QR 圖碼來儲存參數
- 追蹤使用者的頭部動作
- 為每隻眼睛設定正確的變形問題,藉此算繪立體圖片
設定開發環境
硬體需求:
- 搭載 iOS 12.0 以上版本的 iPhone
- 資訊卡板檢視者
軟體相關規定:
- Xcode 12.5 以上版本
- CocoaPods 1.9 以上版本
下載並建構試用版應用程式
Wear SDK 是使用預先編譯的通訊協定緩衝區 C++ 來源檔案建構。請參閱這篇文章,瞭解如何從頭開始建立來源檔案。
執行下列指令,從 GitHub 複製 OpenGL SDK 和 Hello OpenGL 試用版應用程式:
git clone https://github.com/googlevr/cardboard.git
在存放區根目錄中執行下列指令,藉此將通訊協定緩衝區依附元件安裝到 Xcode 專案中:
pod install
在 Xcode 中開啟 VR 工作區 (
Cardboard.xcworkspace
)。變更應用程式的套件 ID,以便您與團隊簽署應用程式。
前往 SDK > Build Phases > Link Binary With libraries
- 如要從清單中移除該清單,請選取該項目並按一下
libPods-sdk.a
'-' 按鈕。 - 按一下「'+'」按鈕並選取該圖示,將
libProtobuf-C++.a
新增至清單。如果畫面上出現建議使用 XCFramework 的訊息,請按一下 [Add Anyway]。
- 如要從清單中移除該清單,請選取該項目並按一下
按一下「執行」。
掃描 QR code
如要儲存裝置參數,請掃描 Gboard 檢視器的 QR 圖碼:
立即試用
在 HelloCardboard 中,您將在 3D 空間中尋找並收集測地線球體。
如何尋找及收集球體:
朝任何方向移動頭部,直到出現浮球為止。
請直視球面。這樣會改變顏色。
按下 VR 檢視器按鈕來「收集」球體。
設定裝置
當使用者輕觸齒輪圖示來切換 OpenGL 檢視器時,HelloCardboardOverlayView
中會呼叫 didTapSwitchButton
方法。
- (void)didTapSwitchButton:(id)sender {
if ([self.delegate respondsToSelector:@selector(didTapBackButton)]) {
[self.delegate didChangeViewerProfile];
}
self.settingsBackgroundView.hidden = YES;
}
呼叫 CardboardQrCode_scanQrCodeAndSaveDeviceParams
即可開啟視窗,用來掃描檢視者的 QR 圖碼。使用者掃描 QR 圖碼後,裝置的變形參數已更新。
- (void)switchViewer {
CardboardQrCode_scanQrCodeAndSaveDeviceParams();
}
- (void)didChangeViewerProfile {
[self pauseCardboard];
[self switchViewer];
[self resumeCardboard];
}
頭部追蹤
建立頭部追蹤器
頭部追蹤器會在 HelloCardboardViewController
的 viewDidLoad
方法中建立一次:
_cardboardHeadTracker = CardboardHeadTracker_create();
暫停及繼續頭部追蹤器
HelloCardboardViewController
類別中的 pauseCardboard
和 resumeCardboard
方法會分別暫停及恢復頭部追蹤器。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;
}
鏡頭變形
每次 OpenGL 掃描新的 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));
轉譯
在 Gboard 中算繪內容涵蓋下列項目:
- 建立紋理
- 取得左眼和右眼的檢視和投影矩陣
- 建立轉譯器和設定變形網格
- 轉譯每個影格
建立紋理
內容會繪製在紋理上,分為左右左右各部分。這些部分會分別在 _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);