Krótkie wprowadzenie do Google Cardboard na Androida NDK

Z tego przewodnika dowiesz się, jak za pomocą pakietu SDK Cardboard na Androida tworzyć własne rozwiązania VR.

Za pomocą pakietu SDK Cardboard możesz zmienić smartfona w platformę VR. Smartfon może wyświetlać sceny 3D z renderowaniem stereoskopowym, śledzić ruchy głowy i reagować na nie, a także wchodzić w interakcje z aplikacjami, wykrywając, kiedy użytkownik naciśnie przycisk gogli.

Na początek użyj HelloCardboard – gry demonstracyjnej, która prezentuje główne funkcje pakietu Cardboard SDK. Użytkownicy rozglądają się po wirtualnym świecie, aby znajdować i zbierać obiekty. Pokazuje ono, jak:

  • Konfigurowanie środowiska programistycznego
  • Pobierz i stwórz aplikację demonstracyjną
  • Zeskanuj kod QR gogli Cardboard, aby zapisać jej parametry
  • Śledź ruchy głową użytkownika
  • Renderuj stereoskopowe obrazy, ustawiając odpowiednią macierz projekcji obrazu dla każdego oka.

HelloCardboard korzysta z pakietu NDK Androida. Każda metoda natywna:

  • Ograniczony jednoznacznie do metody klasy HelloCardboardApp lub
  • Tworzy lub usuwa instancję tej klasy

Konfigurowanie środowiska programistycznego

Wymagania sprzętowe:

Wymagania dotyczące oprogramowania:

  • Android Studio w wersji 2022.1.1 „Electric Eel” lub nowszy,
  • Android SDK 13.0 „Tiramisu” (poziom interfejsu API 33) lub nowszy
  • Najnowsza wersja platformy Android NDK

    Aby przejrzeć lub zaktualizować zainstalowane pakiety SDK, kliknij Ustawienia > Wygląd i działanie.

    Ustawienia systemu > Android SDK w Android Studio.

Pobierz i stwórz aplikację demonstracyjną

Pakiet Cardboard SDK został utworzony na podstawie wstępnie skompilowanego pliku nagłówka Vulkan dla każdego programu do cieniowania. Instrukcje tworzenia plików nagłówkowych od zera znajdziesz tutaj.

  1. Uruchom to polecenie, aby skopiować pakiet SDK Cardboard i wersję demonstracyjną aplikacji HelloCardboard z GitHuba:

    git clone https://github.com/googlevr/cardboard.git
  2. W Android Studio wybierz Otwórz istniejący projekt Android Studio, a potem wybierz katalog, w którym sklonowano pakiet SDK Cardboard i aplikację demonstracyjną HelloCardboard.

    Kod pojawi się w oknie projektu w Android Studio.

  3. Aby złożyć pakiet SDK Cardboard, kliknij dwukrotnie opcję montuj w folderze cardboard/:sdk/Tasks/build (Widok > Okna narzędzi > Gradle).

  4. Uruchom demonstracyjną aplikację HelloCardboard na telefonie, wybierając Uruchom > Uruchom... i wybierz hellocardboard-android środowisko docelowe.

Zeskanuj kod QR

Aby zapisać parametry urządzenia, zeskanuj kod QR za pomocą gogli Cardboard:

Jeśli użytkownik naciśnie „POMIŃ” bez zapisanych wcześniej parametrów, Cardboard zapisze parametry Google Cardboard v1 (udostępnionej na konferencji Google I/O 2014).

Wypróbuj wersję demonstracyjną

W HelloCardboard wyszukujesz i gromadzisz sfery geodetyczne w przestrzeni 3D.

Aby znaleźć i zebrać sferę:

  1. Poruszaj głową w dowolnym kierunku, aż zobaczysz unoszący się kształt.

  2. Spójrz bezpośrednio na sferę. Powoduje to zmianę koloru.

  3. Naciśnij przycisk gogli Cardboard, aby „zbierać” sferę.

Skonfiguruj urządzenie

Gdy użytkownik kliknie ikonę koła zębatego, aby przełączyć gogle Cardboard, wywołana jest metoda nativeSwitchViewer. nativeSwitchViewer wywołuje CardboardQrCode_scanQrCodeAndSaveDeviceParams, co otwiera okno, w którym można zeskanować kod QR widza. Zniekształcenie obiektywu i inne parametry gogli zostaną zaktualizowane po zeskanowaniu kodu QR.

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

Włącz emulator Androida Studio x86

Aby utworzyć kompilację do emulatora Androida Studio x86, usuń ten wiersz z plików build.gradle w pakietach SDK i Przykład:

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

Spowoduje to włączenie wszystkich interfejsów ABI i znacznie zwiększy rozmiar wygenerowanego pliku .aar. Więcej informacji znajdziesz w sekcji na temat interfejsów ABI Androida.

Monitorowanie ruchów głowy

Utwórz urządzenie śledzące ruchy głowy

Monitorowanie ruchów głowy tworzony jest raz w konstruktorze HelloCardboardApp:

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

Po utworzeniu klasy VrActivity instancja klasy HelloCardboardApp jest generowana przez wywołanie metody nativeOnCreate:

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

Wstrzymywanie i wznawianie śledzenia ruchów głowy

Aby wstrzymać, wznowić i zniszczyć urządzenie śledzące, należy wywołać odpowiednio CardboardHeadTracker_pause(head_tracker_), CardboardHeadTracker_resume(head_tracker_) i CardboardHeadTracker_destroy(head_tracker_). W aplikacji „HelloCardboard” wywołujemy je w językach nativeOnPause, nativeOnResume i 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;
}

Zniekształcenie obiektywu

Za każdym razem, gdy Cardboard skanuje nowy kod QR, poniższy kod odczytuje zapisane parametry i wykorzystuje je do utworzenia obiektu zniekształconego obiektywu, który stosuje odpowiednie zniekształcenia obiektywu do renderowanych treści:

CardboardQrCode_getSavedDeviceParams(&buffer, &size);

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

CardboardQrCode_destroy(buffer);

renderowanie,

Renderowanie treści w goglach Cardboard:

  • Tworzenie tekstur
  • Uzyskiwanie macierzy wyświetlania i odwzorowania dla lewego i prawego oka
  • Tworzenie mechanizmu renderowania i konfigurowanie siatki zniekształceń
  • Renderowanie każdej klatki.

Tworzenie tekstur

Cała zawartość jest rysowana na teksturze, która jest podzielona na sekcje dla lewego i prawego oka. Inicjowane sekcje są odpowiednio _leftEyeTexture i _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");
}

Te tekstury są przekazywane jako parametry do funkcji CardboardDistortionRenderer_renderEyeToDisplay.

Pobierz macierze widoku i odwzorowania dla lewego i prawego oka

Najpierw pobierz macierze oka dla lewego i prawego oka:

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

Następnie pobierz sieci zniekształceń dla każdego oczu i przekaż je do mechanizmu renderowania zniekształceń:

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

Utwórz mechanizm renderowania i ustaw prawidłową siatkę zniekształceń

Mechanizm renderowania wystarczy zainicjować tylko raz. Po utworzeniu mechanizmu renderowania ustaw nową siatkę zniekształceń dla lewego i prawego oka zgodnie z wartościami sieci typu mesh zwróconymi przez funkcję CardboardLensDistortion_getDistortionMesh.

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

Renderowanie treści

Dla każdej klatki pobierz bieżącą orientację głowicy z CardboardHeadTracker_getPose:

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

Użyj bieżącej orientacji głowy z matrycami widoku i projekcji, aby utworzyć macierz projekcji widoków dla każdego oczu i renderować zawartość na ekran:

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

Użyj narzędzia CardboardDistortionRenderer_renderEyeToDisplay, aby zastosować korektę zniekształceń do treści i wyrenderować ją na ekranie.

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