iOS 用 Google Cardboard のクイックスタート

このガイドでは、Cardboard SDK for iOS を使用して独自のバーチャル リアリティ(VR)エクスペリエンスを作成する方法について説明します。

Cardboard SDK を使ってスマートフォンを VR プラットフォームにすることができます。スマートフォンは、立体画像で 3D シーンを表示し、頭の動きをトラッキングして反応し、ユーザーがビューアのボタンを押したことを検出してアプリを操作できます。

まず、HelloCardboard を使用します。これは、Cardboard SDK のコア機能のデモゲームである HelloCardboard です。このゲームでは、ユーザーは仮想世界を見て回ってオブジェクトを見つけて収集します。以下の方法について説明しています。

  • 開発環境をセットアップする
  • デモアプリのダウンロードとビルド
  • Cardboard ビューアの QR コードをスキャンしてパラメータを保存します
  • ユーザーの頭の動きを追跡する
  • 左右の歪みを設定して立体画像をレンダリングします

開発環境をセットアップする

ハードウェア要件:

ソフトウェア要件:

デモアプリのダウンロードとビルド

Cardboard SDK は、コンパイル済みのプロトコル バッファ C++ ソースファイルを使用してビルドされています。ソースファイルをゼロからビルドする手順については、こちらをご覧ください。

  1. 次のコマンドを実行して、GitHub にある Cardboard SDK と Hello Cardboard デモアプリのクローンを作成します。

    git clone https://github.com/googlevr/cardboard.git
  2. リポジトリのルートで次のコマンドを実行して、プロトコル バッファの依存関係を Xcode プロジェクトにインストールします。

    pod install
  3. Xcode で Cardboard ワークスペース(Cardboard.xcworkspace)を開きます。

  4. チームでアプリに署名できるように、アプリのバンドル ID を変更します。

  5. [SDK] > [Build Phases] > [Link Binary With Libraries] に移動します。

    1. libPods-sdk.a を選択して [-] ボタンをクリックして、リストから libPods-sdk.a を削除します。
    2. [+] ボタンをクリックして libProtobuf-C++.a を選択し、リストに追加します。XCFramework の使用を提案するメッセージが表示されたら、[このまま追加] をクリックします。
  6. [実行] をクリックします。

QR コードをスキャンする

デバイスのパラメータを保存するには、Cardboard ビューアで QR コードをスキャンします。

デモを試す

HelloCardboard では、3D 空間で測地線的な球体を見つけて収集します。

球体を見つけて集めるには:

  1. 球体が浮かんで見えるまで、頭を任意の方向に動かします。

  2. 球体を直接見る。これにより、色が変化します。

  3. Cardboard ビューア ボタンを押して球体を「収集」します。

デバイスを設定する

ユーザーが歯車アイコンをタップして Cardboard ビューアを切り替えると、HelloCardboardOverlayViewdidTapSwitchButton メソッドが呼び出されます。

- (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];
}

ヘッド トラッキング

ヘッド トラッカーを作成

ヘッド トラッカーは、HelloCardboardViewControllerviewDidLoad メソッドで 1 回作成されます。

_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;
}

レンズ歪み

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 で初期化されます。サンプルアプリでは両目用に 1 つのテクスチャを使用していますが、両目用に別々のテクスチャを作成することもできます。

// 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);

レンダラを作成して正しい歪みメッシュを設定する

レンダラを初期化する必要があるのは 1 回だけです。レンダラが作成されたら、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);