Android NDK 用 Google Cardboard のクイックスタート

このガイドでは、Cardboard SDK の使用方法について説明します 独自のバーチャル リアリティ(VR)体験を作成できます。

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

まずは、HelloCardboard をデモゲームで使ってみましょう。 主な機能を見てみましょうユーザーはこのゲームで仮想世界を見回し、 収集します。次の方法について説明します。

  • 開発環境を設定する
  • デモアプリをダウンロードしてビルドする
  • Cardboard ビューアの QR コードをスキャンしてパラメータを保存します
  • ユーザーの頭の動きをトラッキングする
  • それぞれの目に対して正しいビュー投影行列を設定して、立体画像をレンダリングする

HelloCardboard は、Android NDK を使用しています。すべてのネイティブ メソッドは次のとおりです。

  • HelloCardboardApp クラスメソッドに一意にバインドされている。
  • そのクラスのインスタンスを作成または削除する

開発環境を設定する

ハードウェア要件:

  • Android 8.0「Oreo」を搭載した Android デバイス(API レベル 26)以降
  • Cardboard ビューア
で確認できます。

ソフトウェア要件:

  • Android Studio バージョン 2022.1.1「Electric Eel」以上
  • Android SDK 13.0「Tiramisu」(API レベル 33)以降
  • 最新バージョンの Android NDK フレームワーク

    インストールされている SDK を確認または更新するには、[設定] >外観と動作

    システム設定 >Android Studio の Android SDK

デモアプリをダウンロードしてビルドする

Cardboard SDK は、プリコンパイル済みの Vulkan を使用してビルドされています。 各シェーダーのヘッダー ファイルが作成されます。ヘッダー ファイルをゼロから作成する手順については、 こちらをご覧ください。

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

    git clone https://github.com/googlevr/cardboard.git
  2. Android Studio で [Open an existing Android Studio Project] を選択し、 Cardboard SDK と HelloCardboard デモアプリのクローンが作成されたディレクトリです。

    Android Studio のプロジェクト ウィンドウにコードが表示されます。

  3. Cardboard SDK を組み立てるには、画面内の [組み立て] オプションを [Gradle] タブ([View] > [Tool Windows] > [Gradle])の cardboard/:sdk/Tasks/build フォルダ

  4. スマートフォンで [実行] を選択して、HelloCardboard デモアプリを実行します。実行... hellocardboard-android ターゲットを選択します。

QR コードをスキャンする

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

ユーザーが [スキップ] を押した場合以前に保存したパラメータがない場合 Google Cardboard v1(Google I/O 2014 でリリース済み)のパラメータ。

デモを試す

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

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

  1. 浮かぶ図形が表示されるまで、頭をいずれかの方向に動かします。

  2. 球体を正面から見てください。これにより、色が変化します。

  3. Cardboard ビューアのボタンを押して「収集」してくださいあります。

デバイスを設定する

ユーザーが歯車アイコンをタップして Cardboard ビューアを切り替えると、nativeSwitchViewer メソッドが呼び出されます。nativeSwitchViewer 件の通話 CardboardQrCode_scanQrCodeAndSaveDeviceParams: スキャンするウィンドウを開きます クリックします。視聴者のレンズの歪みなどのパラメータが更新されると、 QR コードがスキャンされます。

// Called by JNI method
void HelloCardboardApp::SwitchViewer() {
  CardboardQrCode_scanQrCodeAndSaveDeviceParams();
}

Android Studio x86 エミュレータを有効にする

Android Studio x86 エミュレータ用にビルドするには、次の行を削除します。 SDK 内の build.gradle ファイル サンプル:

abiFilters 'armeabi-v7a', 'arm64-v8a'

これにより、すべての ABI が有効になり、生成されるファイルのサイズが大幅に増加します。 .aar ファイル。Android ABI をご覧ください。 をご覧ください。

ヘッド トラッキング

ヘッド トラッカーを作成

ヘッド トラッカーは、HelloCardboardApp のコンストラクタで一度作成されます。

HelloCardboardApp::HelloCardboardApp(JavaVM* vm, jobject obj, jobject asset_mgr_obj) {
  Cardboard_initializeAndroid(vm, obj); // Must be called in constructor
  head_tracker_ = CardboardHeadTracker_create();
}

VrActivity が作成されると、HelloCardboardApp クラスのインスタンスが生成されます。 nativeOnCreate メソッドを呼び出します。

public void onCreate(Bundle savedInstance) {
  super.onCreate(savedInstance);
  nativeApp = nativeOnCreate(getAssets());
  //...
}

ヘッド トラッカーの一時停止と再開

ヘッド トラッカーを一時停止、再開、破棄するには、 CardboardHeadTracker_pause(head_tracker_) さん、CardboardHeadTracker_resume(head_tracker_) さん、 と CardboardHeadTracker_destroy(head_tracker_) をそれぞれ呼び出す必要があります。 "HelloCardboard"nativeOnPausenativeOnResumenativeOnDestroy:

// Code to pause head tracker in hello_cardboard_app.cc

void HelloCardboardApp::OnPause() { CardboardHeadTracker_pause(head_tracker_); }

// Call nativeOnPause in VrActivity
@Override
protected void onPause() {
  super.onPause();
  nativeOnPause(nativeApp);
  //...
}

// Code to resume head tracker in hello_cardboard_app.cc
void HelloCardboardApp::onResume() {
  CardboardHeadTracker_resume(head_tracker_);
  //...
}

// Call nativeOnResume in VrActivity
@Override
protected void onResume() {
  super.onResume();
  //...
  nativeOnResume(nativeApp);
}

// Code to destroy head tracker in hello_cardboard_app.cc
HelloCardboardApp::~HelloCardboardApp() {
  CardboardHeadTracker_destroy(head_tracker_);
  //...
}

// Call nativeOnDestroy in VrActivity
@Override
protected void onDestroy() {
  super.onDestroy();
  nativeOnDestroy(nativeApp);
  nativeApp = 0;
}

レンズの歪み

Cardboard が新しい QR コードをスキャンするたびに、保存されたパラメータが以下のコードで読み取られます 適切なレンズ歪みを適用するレンズ歪みオブジェクトを作成します 追加します。

CardboardQrCode_getSavedDeviceParams(&buffer, &size);

CardboardLensDistortion_destroy(lens_distortion_);
lens_distortion_ = CardboardLensDistortion_create(
    buffer, size, screen_width_, screen_height_);

CardboardQrCode_destroy(buffer);

レンダリング

Cardboard でコンテンツをレンダリングする手順は次のとおりです。

  • テクスチャの作成
  • 左右の目のビュー行列と投影行列の取得
  • レンダラの作成と歪みメッシュの設定
  • 各フレームのレンダリング

テクスチャを作成する

すべてのコンテンツはテクスチャに描画され、テクスチャは左目用と右目用のセクションに分割されます。 これらのセクションは、それぞれ _leftEyeTexture_rightEyeTexture で初期化されます。

void HelloCardboardApp::GlSetup() {
  LOGD("GL SETUP");

  if (framebuffer_ != 0) {
    GlTeardown();
  }

  // Create render texture.
  glGenTextures(1, &texture_);
  glBindTexture(GL_TEXTURE_2D, texture_);
  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, screen_width_, screen_height_, 0,
               GL_RGB, GL_UNSIGNED_BYTE, 0);

  left_eye_texture_description_.texture = texture_;
  left_eye_texture_description_.left_u = 0;
  left_eye_texture_description_.right_u = 0.5;
  left_eye_texture_description_.top_v = 1;
  left_eye_texture_description_.bottom_v = 0;

  right_eye_texture_description_.texture = texture_;
  right_eye_texture_description_.left_u = 0.5;
  right_eye_texture_description_.right_u = 1;
  right_eye_texture_description_.top_v = 1;
  right_eye_texture_description_.bottom_v = 0;

  //...
  CHECKGLERROR("GlSetup");
}

これらのテクスチャは、パラメータとして CardboardDistortionRenderer_renderEyeToDisplay に渡されます。

左右の目のビュー行列と投影行列を取得する

まず、左右の目の行列を取得します。

CardboardLensDistortion_getEyeFromHeadMatrix(
    lens_distortion_, kLeft, eye_matrices_[0]);
CardboardLensDistortion_getEyeFromHeadMatrix(
    lens_distortion_, kRight, eye_matrices_[1]);
CardboardLensDistortion_getProjectionMatrix(
    lens_distortion_, kLeft, kZNear, kZFar, projection_matrices_[0]);
CardboardLensDistortion_getProjectionMatrix(
    lens_distortion_, kRight, kZNear, kZFar, projection_matrices_[1]);

次に、それぞれの目のディストーション メッシュを取得し、ディストーション レンダラに渡します。

CardboardLensDistortion_getDistortionMesh(lens_distortion_, kLeft, &left_mesh);
CardboardLensDistortion_getDistortionMesh(lens_distortion_, kRight, &right_mesh);

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

レンダラの初期化は 1 回だけで済みます。レンダラを作成したら、新しい から返されたメッシュ値に従って、左右の目の歪みメッシュが CardboardLensDistortion_getDistortionMesh 関数を使用します。

distortion_renderer_ = CardboardOpenGlEs2DistortionRenderer_create();
CardboardDistortionRenderer_setMesh(distortion_renderer_, &left_mesh, kLeft);
CardboardDistortionRenderer_setMesh(distortion_renderer_, &right_mesh, kRight);

コンテンツのレンダリング

フレームごとに、CardboardHeadTracker_getPose から現在のヘッドの向きを取得します。

CardboardHeadTracker_getPose(head_tracker_, monotonic_time_nano, &out_position[0], &out_orientation[0]);

現在の頭の向きをビュー行列と射影行列とともに使用してビューを作成する 投影行列を作成し、画面にコンテンツをレンダリングします。

// Draw eyes views
for (int eye = 0; eye < 2; ++eye) {
  glViewport(eye == kLeft ? 0 : screen_width_ / 2, 0, screen_width_ / 2,
             screen_height_);

  Matrix4x4 eye_matrix = GetMatrixFromGlArray(eye_matrices_[eye]);
  Matrix4x4 eye_view = eye_matrix * head_view_;

  Matrix4x4 projection_matrix =
      GetMatrixFromGlArray(projection_matrices_[eye]);
  Matrix4x4 modelview_target = eye_view * model_target_;
  modelview_projection_target_ = projection_matrix * modelview_target;
  modelview_projection_room_ = projection_matrix * eye_view;

  // Draw room and target. Replace this to render your own content.
  DrawWorld();
}

CardboardDistortionRenderer_renderEyeToDisplay を使用して歪みを適用する 画面にコンテンツをレンダリングします

// Render
CardboardDistortionRenderer_renderEyeToDisplay(
    distortion_renderer_, /* target_display = */ 0, /* x = */ 0, /* y = */ 0,
    screen_width_, screen_height_, &left_eye_texture_description_,
    &right_eye_texture_description_);