Panduan memulai untuk Google Cardboard untuk Android NDK

Panduan ini menunjukkan cara menggunakan Cardboard SDK untuk Android guna membuat pengalaman Virtual Reality (VR) Anda sendiri.

Anda dapat menggunakan Cardboard SDK untuk mengubah smartphone menjadi platform VR. Smartphone dapat menampilkan adegan 3D dengan rendering stereoskopis, melacak dan bereaksi terhadap gerakan kepala, serta berinteraksi dengan aplikasi dengan mendeteksi kapan pengguna menekan tombol penampil.

Untuk memulai, Anda akan menggunakan HelloCardboard, game demo yang menunjukkan fitur inti dari Cardboard SDK. Dalam game, pengguna melihat-lihat dunia virtual untuk menemukan dan mengumpulkan objek. Ini menunjukkan kepada Anda cara:

  • Menyiapkan lingkungan pengembangan
  • Mendownload dan membuat aplikasi demo
  • Pindai kode QR penampil Cardboard untuk menyimpan parameternya
  • Melacak gerakan kepala pengguna
  • Render gambar stereoskopis dengan menyetel matriks proyeksi tampilan yang benar untuk setiap mata

HelloCardboard menggunakan Android NDK. Setiap metode native:

  • Diikat secara unik ke metode class HelloCardboardApp, atau
  • Membuat atau menghapus instance class tersebut

Menyiapkan lingkungan pengembangan

Persyaratan hardware:

  • Perangkat Android yang menjalankan Android 8.0 "Oreo" (API level 26) atau yang lebih tinggi
  • Penampil kardus

Persyaratan perangkat lunak:

  • Android Studio versi 2022.1.1 "Electric Eel" atau yang lebih baru
  • Android SDK 13.0 "Tiramisu" (API level 33) atau yang lebih tinggi
  • Framework Android NDK versi terbaru

    Untuk meninjau atau mengupdate SDK yang terinstal, buka Preferensi > Tampilan dan Perilaku

    Setelan Sistem > Android SDK di Android Studio.

Mendownload dan membuat aplikasi demo

Cardboard SDK dibuat menggunakan file header Vulkan yang telah dikompilasi sebelumnya untuk setiap shader. Langkah-langkah untuk mem-build file header dari awal dapat ditemukan di sini.

  1. Jalankan perintah berikut untuk meng-clone Cardboard SDK dan aplikasi demo HelloCardboard dari GitHub:

    git clone https://github.com/googlevr/cardboard.git
  2. Di Android Studio, pilih Open an existing Android Studio Project, lalu pilih direktori tempat Cardboard SDK dan aplikasi demo HelloCardboard di-clone.

    Kode Anda akan muncul di jendela Project di Android Studio.

  3. Untuk merakit Cardboard SDK, klik dua kali opsi assemble dalam folder Cardboard/:sdk/Tasks/build di tab Gradle (View > Tool Windows > Gradle).

  4. Jalankan aplikasi demo HelloCardboard di ponsel dengan memilih Run > Run... dan pilih target hellocardboard-android.

Pindai kode QR

Untuk menyimpan parameter perangkat, pindai kode QR di penampil Cardboard:

Jika pengguna menekan "LEWATI" dan tidak ada parameter yang disimpan sebelumnya, Cardboard menyimpan parameter Google Cardboard v1 (diluncurkan di Google I/O 2014).

Coba demo

Di HelloCardboard, Anda akan mencari dan mengumpulkan bola geodesi dalam ruang 3D.

Untuk menemukan dan mengumpulkan bola dunia:

  1. Gerakkan kepala ke segala arah sampai Anda melihat bentuk mengambang.

  2. Lihat langsung bola dunia. Hal ini menyebabkannya berubah warna.

  3. Tekan tombol penampil Cardboard untuk "mengumpulkan" bola.

Mengonfigurasi perangkat

Ketika pengguna mengetuk ikon roda gigi untuk beralih penampil Cardboard, metode nativeSwitchViewer akan dipanggil. nativeSwitchViewer memanggil CardboardQrCode_scanQrCodeAndSaveDeviceParams, yang membuka jendela untuk memindai kode QR penonton. Distorsi lensa penampil dan parameter lainnya diupdate setelah kode QR dipindai.

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

Mengaktifkan emulator Android Studio x86

Untuk mem-build emulator Android Studio x86, hapus baris berikut dari file build.gradle di SDK dan Contoh:

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

Tindakan ini akan mengaktifkan semua ABI dan akan secara signifikan meningkatkan ukuran file .aar yang dihasilkan. Lihat ABI Android untuk informasi selengkapnya.

Pelacakan gerak kepala

Buat pelacak kepala

Pelacak head dibuat satu kali dalam konstruktor HelloCardboardApp:

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

Saat VrActivity dibuat, instance class HelloCardboardApp akan dibuat dengan memanggil metode nativeOnCreate:

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

Menjeda dan melanjutkan pelacak kepala

Untuk menjeda, melanjutkan, dan menghancurkan pelacak kepala, CardboardHeadTracker_pause(head_tracker_), CardboardHeadTracker_resume(head_tracker_), dan CardboardHeadTracker_destroy(head_tracker_) masing-masing harus dipanggil. Di aplikasi "HelloCardboard", kita memanggilnya dalam nativeOnPause, nativeOnResume, dan nativeOnDestroy:

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

Distorsi lensa

Setiap kali Cardboard memindai kode QR baru, kode berikut membaca parameter yang disimpan dan menggunakannya untuk membuat objek distorsi lensa, yang menerapkan distorsi lensa yang tepat ke konten yang dirender:

CardboardQrCode_getSavedDeviceParams(&buffer, &size);

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

CardboardQrCode_destroy(buffer);

Rendering

Merender konten di Cardboard melibatkan hal berikut:

  • Membuat tekstur
  • Mendapatkan matriks tampilan dan proyeksi untuk mata kiri dan kanan
  • Membuat perender dan menyetel mesh distorsi
  • Merender setiap frame

Membuat tekstur

Semua konten digambar di atas tekstur, yang dibagi menjadi beberapa bagian untuk mata kiri dan kanan. Bagian ini masing-masing diinisialisasi di _leftEyeTexture dan _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");
}

Tekstur ini diteruskan sebagai parameter ke CardboardDistortionRenderer_renderEyeToDisplay.

Mendapatkan matriks tampilan dan proyeksi untuk mata kiri dan kanan

Pertama, ambil matriks mata untuk mata kiri dan kanan:

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

Selanjutnya, dapatkan mesh distorsi untuk setiap mata dan teruskan ke perender distorsi:

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

Membuat perender dan menyetel mesh distorsi yang benar

Perender hanya perlu diinisialisasi sekali. Setelah perender dibuat, setel mesh distorsi baru untuk mata kiri dan kanan sesuai dengan nilai mesh yang ditampilkan dari fungsi CardboardLensDistortion_getDistortionMesh.

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

Merender konten

Untuk setiap frame, ambil orientasi kepala saat ini dari CardboardHeadTracker_getPose:

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

Gunakan orientasi kepala saat ini dengan matriks tampilan dan proyeksi untuk menyusun matriks proyeksi tampilan untuk setiap mata dan merender konten ke layar:

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

Gunakan CardboardDistortionRenderer_renderEyeToDisplay untuk menerapkan koreksi distorsi pada konten, dan merender konten ke layar.

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