Kurzanleitung für Google Cardboard für Android – NDK

In diesem Leitfaden erfährst du, wie du mit dem Cardboard SDK for Android deine eigenen Virtual-Reality-Erlebnisse erstellen kannst.

Mit dem Cardboard SDK kannst du ein Smartphone in eine VR-Plattform verwandeln. Ein Smartphone kann 3D-Szenen mit stereoskopischem Rendering anzeigen, Kopfbewegungen verfolgen und darauf reagieren und mit Apps interagieren, indem es erkennt, wann der Nutzer auf die Schaltfläche des Betrachters drückt.

Verwende als Erstes HelloCardboard, ein Demospiel, in dem die wichtigsten Funktionen des Cardboard SDK demonstriert werden. In dem Spiel sehen sich Nutzer in einer virtuellen Welt um, um Objekte zu finden und zu sammeln. Sie erfahren, wie Sie:

  • Entwicklungsumgebung einrichten
  • Demo-App herunterladen und erstellen
  • QR-Code eines Cardboard scannen, um dessen Parameter zu speichern
  • Die Kopfbewegungen der Nutzenden erfassen
  • Stereoskopische Bilder rendern, indem für jedes Auge die richtige Matrix für die Ansichtsprojektion festgelegt wird

HelloCardboard verwendet den Android NDK. Für jede native Methode gilt:

  • Eindeutiger Begrenzung auf eine HelloCardboardApp-Klassenmethode oder
  • Erstellt oder löscht eine Instanz dieser Klasse

Entwicklungsumgebung einrichten

Hardwareanforderungen:

  • Android-Gerät mit Android 8.0 Oreo (API-Level 26) oder höher
  • Cardboard-Brille

Softwareanforderungen:

  • Android Studio 2022.1.1 „Electric Eel“ oder höher
  • Android SDK 13.0 „Tiramisu“ (API-Level 33) oder höher
  • Die aktuelle Version des Android NDK-Frameworks

    Installierte SDKs kannst du unter Einstellungen > Darstellung und Verhalten prüfen oder aktualisieren.

    Systemeinstellungen > Android SDK in Android Studio.

Demo-App herunterladen und erstellen

Das Cardboard SDK wird mithilfe einer vorkompilierten Vulkan-Header-Datei für jeden Shader erstellt. Hier finden Sie eine Anleitung dazu, wie Sie Headerdateien von Grund auf neu erstellen.

  1. Führe den folgenden Befehl aus, um das Cardboard SDK und die Demo-App HelloCardboard von GitHub zu klonen:

    git clone https://github.com/googlevr/cardboard.git
  2. Wähle in Android Studio Vorhandenes Android Studio-Projekt öffnen und dann das Verzeichnis aus, in das das Cardboard SDK und die HelloCardboard-Demo-App geklont wurden.

    Ihr Code wird im Projektfenster in Android Studio angezeigt.

  3. Um das Cardboard SDK zusammenzustellen, klicke im Ordner cardboard/:sdk/Tasks/build auf dem Gradle-Tab (View > Tool Windows > Gradle) auf die Option configure.

  4. Führe die Demo-App HelloCardboard auf deinem Smartphone aus. Wähle dazu Ausführen > Ausführen... und das Ziel hellocardboard-android aus.

Scanne den QR-Code.

Scanne den QR-Code auf der Cardboard-Brille, um die Geräteparameter zu speichern:

Wenn der Nutzer auf „ÜBERSPRINGEN“ klickt und keine zuvor gespeicherten Parameter vorhanden sind, speichert Cardboard die Parameter von Google Cardboard Version 1, die bei der Google I/O 2014 eingeführt wurde.

Zur Demo

In HelloCardboard suchen und sammeln Sie geodätische Kugeln im 3D-Raum.

So finden und erfassen Sie eine Kugel:

  1. Bewegen Sie den Kopf in eine beliebige Richtung, bis Sie eine schwebende Form sehen.

  2. Blicken Sie direkt in die Kugel. Dadurch ändert es die Farbe.

  3. Drücken Sie die Taste des Cardboard, um die Kugel einzusammeln.

Gerät konfigurieren

Wenn der Nutzer auf das Zahnradsymbol tippt, um das Cardboard zu wechseln, wird die Methode nativeSwitchViewer aufgerufen. nativeSwitchViewer ruft CardboardQrCode_scanQrCodeAndSaveDeviceParams auf, um das Fenster zum Scannen des QR-Codes des Zuschauers zu öffnen. Die Objektivverzeichnung des Betrachters und andere Parameter werden aktualisiert, sobald der QR-Code gescannt wurde.

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

Android Studio x86-Emulator aktivieren

Entfernen Sie zum Erstellen von Builds für den Android Studio x86-Emulator im SDK und im Beispiel die folgende Zeile aus den build.gradle-Dateien:

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

Dadurch werden alle ABIs aktiviert und die Größe der generierten .aar-Datei wird erheblich erhöht. Weitere Informationen finden Sie unter Android-ABIs.

Erfassung von Kopfbewegungen

Head Tracker erstellen

Der Head-Tracker wird einmal im Konstruktor von HelloCardboardApp erstellt:

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

Beim Erstellen von VrActivity wird durch Aufrufen der Methode nativeOnCreate eine Instanz der Klasse HelloCardboardApp generiert:

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

Head Tracker pausieren und fortsetzen

Zum Pausieren, Fortsetzen und Löschen des Head Trackers müssen CardboardHeadTracker_pause(head_tracker_), CardboardHeadTracker_resume(head_tracker_) bzw. CardboardHeadTracker_destroy(head_tracker_) aufgerufen werden. In der App „HelloCardboard“ rufen wir sie in nativeOnPause, nativeOnResume und nativeOnDestroy auf:

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

Objektivverzeichnung

Jedes Mal, wenn Cardboard einen neuen QR-Code scannt, liest der folgende Code die gespeicherten Parameter aus und verwendet sie, um das Objekt zur Objektivverzeichnung zu erstellen. Dadurch wird die richtige Objektivverzeichnung auf den gerenderten Inhalt angewendet:

CardboardQrCode_getSavedDeviceParams(&buffer, &size);

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

CardboardQrCode_destroy(buffer);

Rendering

Das Rendern von Inhalten in Cardboard umfasst die folgenden Schritte:

  • Texturen erstellen
  • Ansichts- und Projektionsmatrizen für das linke und rechte Auge abrufen
  • Renderer erstellen und Verzerrungsnetz festlegen
  • Frames rendern

Texturen erstellen

Der gesamte Inhalt wird auf eine Textur gezeichnet, die in Abschnitte für das linke und das rechte Auge unterteilt ist. Diese Abschnitte werden in _leftEyeTexture bzw. _rightEyeTexture initialisiert.

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");
}

Diese Texturen werden als Parameter an CardboardDistortionRenderer_renderEyeToDisplay übergeben.

Ansichts- und Projektionsmatrizen für linkes und rechtes Auge abrufen

Rufen Sie zuerst die Augenmatrizen für das linke und das rechte Auge ab:

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

Rufen Sie als Nächstes die Verzerrungsmaschen für jedes der Augen ab und übergeben Sie sie an den Verzerrungs-Renderer:

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

Renderer erstellen und das richtige Verzerrungsnetz festlegen

Der Renderer muss nur einmal initialisiert werden. Legen Sie nach dem Erstellen des Renderers das neue Verzerrungsnetz für das linke und rechte Auge gemäß den Mesh-Werten fest, die von der Funktion CardboardLensDistortion_getDistortionMesh zurückgegeben werden.

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

Inhalt rendern

Rufen Sie für jeden Frame die aktuelle Kopfausrichtung von CardboardHeadTracker_getPose ab:

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

Verwenden Sie die aktuelle Kopfausrichtung mit den Ansichts- und Projektionsmatrizen, um eine Ansichtsprojektionsmatrix für jedes der Augen zu erstellen und Inhalte auf dem Bildschirm zu rendern:

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

Verwenden Sie CardboardDistortionRenderer_renderEyeToDisplay, um die Verzerrungskorrektur auf den Inhalt anzuwenden und ihn auf dem Bildschirm zu rendern.

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