Kurzanleitung für Google PNG für Android NDK

In diesem Leitfaden wird erläutert, wie du mit dem Cardboard SDK für Android eigene Virtual-Reality-Erlebnisse (VR) erstellen kannst.

Mit dem Cardboard SDK kannst du dein Smartphone in eine VR-Plattform verwandeln. Ein Smartphone kann 3D-Szenen mit stereoskopischem Rendering darstellen, Kopfbewegungen erfassen und darauf reagieren sowie mit Apps interagieren, indem es erkennt, wenn der Nutzer die Taste des Betrachters drückt.

Als Erstes verwendest du das Demospiel HelloCardboard, in dem die Hauptfunktionen des Cardboard SDK veranschaulicht werden. Im Spiel schauen sich Nutzer eine virtuelle Welt an, um Objekte zu finden und zu sammeln. Darin erfahren Sie, wie Sie

  • Entwicklungsumgebung einrichten
  • Demo-App herunterladen und erstellen
  • Scanne den QR-Code eines Cardboard, um seine Parameter zu speichern
  • Kopfbewegungen des Nutzers erfassen
  • Stereoskopische Bilder durch Festlegen der richtigen Projektionsmatrix für jedes Auge rendern

HelloCardboard verwendet das Android-NDK. Alle nativen Methoden sind:

  • Abhängig von einer HelloCardboardApp-Klassenmethode oder
  • Erstellt oder löscht eine Instanz dieser Klasse

Entwicklungsumgebung einrichten

Hardwareanforderungen:

  • Android-Geräte mit Android 7.0 (Nougat) (API-Level 24) oder höher
  • Brillenkarton

Softwareanforderungen:

  • Android Studio 4.2.2 oder höher
  • Android SDK 11.0 „R“ (API-Level 30) oder höher
  • Die aktuelle Version des Android NDK-Frameworks

    Wenn Sie installierte SDKs prüfen oder aktualisieren möchten, gehen Sie zu Einstellungen > Darstellung und Verhalten.

    Gehen Sie zu Systemeinstellungen > Android SDK in Android Studio.

Demo-App herunterladen und erstellen

Das Cardboard SDK wird für jeden Shader mit einer vorkompilierten Vulkan-Header-Datei erstellt. Eine Anleitung dazu, wie Sie die Headerdateien neu erstellen, finden Sie hier.

  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 Bestehendes Android Studio-Projekt öffnen und dann das Verzeichnis aus, in dem das Cardboard SDK und die Demo-App „HelloCardboard“ geklont wurden.

    Der Code wird in Android Studio im Projektfenster angezeigt.

  3. Du kannst das Cardboard SDK zusammenstellen, indem du im Tab Gradle (<Ansicht > Tool-Fenster > Gradle)doppelt auf die Option cardboard/:sdk/Tasks/buildzusammenbaust.

  4. Führen Sie die Demo-App „HelloCardboard“ auf Ihrem Smartphone aus. Wählen Sie dazu Run > Run... (Ausführen > Ausführen...) und das Ziel hellocardboard-android aus.

QR-Code scannen

Wenn du die Geräteparameter speichern möchtest, scanne den QR-Code auf der Cardboard-Brille:

Wenn der Nutzer auf „SKIP“ drückt und keine zuvor gespeicherten Parameter vorhanden sind, speichert Cardboard die Parameter von Google Cardboard v1 (wird bei Google I/O 2014 eingeführt).

Demo ausprobieren

In HelloCardboard suchen und sammeln Sie geodätische Kugeln in 3D.

So finden und sammeln Sie eine Kugel:

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

  2. Sieh die Kugel direkt an. Dadurch werden die Farben geändert.

  3. Drücken Sie die Cardboard-Brille, um die Kugel zu „sammeln“.

Gerät konfigurieren

Wenn der Nutzer auf das Zahnradsymbol tippt, um zur Cardboard-Brille zu wechseln, wird die Methode nativeSwitchViewer aufgerufen. nativeSwitchViewer ruft CardboardQrCode_scanQrCodeAndSaveDeviceParams auf. Dadurch wird das Fenster geöffnet, in dem der QR-Code des Betrachters gescannt werden kann. 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 die folgende Zeile aus den build.gradle-Dateien im SDK und Beispiel, um Builds für den Android Studio x86-Emulator zu erstellen:

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-ABAB.

Erfassung von Kopfbewegungen

Kopf-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 eine Instanz der Klasse HelloCardboardApp durch Aufrufen der Methode nativeOnCreate generiert:

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

„Tracker starten“ pausieren und fortsetzen

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

// 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 und verwendet sie, um ein Objektivverzeichnungsobjekt zu erstellen, das die richtige Objektivverzeichnung auf den gerenderten Inhalt anwendet:

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 Folgendes:

  • Texturen erstellen
  • Matrixs für das linke und rechte Auge werden angezeigt
  • Renderer erstellen und verzerrtes Mesh einrichten
  • Rendering für jeden Frame

Texturen erstellen

Der gesamte Inhalt wird auf eine Textur gezeichnet, die in Abschnitte für das linke und rechte Auge aufgeteilt 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.

Matrix für Ansicht und Projektion für linkes und rechtes Auge

Zuerst werden Augenmatrize für das linke und rechte Auge abgerufen:

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

Als Nächstes rufen Sie das Verzerrungsnetz für jedes Auge ab und übergeben es an den Verzerrungsrenderer:

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. Nachdem der Renderer erstellt wurde, legen Sie das neue Verzerrungsnetz für das linke und rechte Auge gemäß den von der CardboardLensDistortion_getDistortionMesh-Funktion zurückgegebenen Mesh-Werten fest.

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

Inhalte rendern

Rufen Sie für jeden Frame die aktuelle Ausrichtung des Kopfes aus CardboardHeadTracker_getPose ab:

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

Verwenden Sie die aktuelle Kopfausrichtung mit der Ansichts- und Projektionsmatrizen, um für jedes Auge eine Matrix für die Darstellung 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();
}

Mit CardboardDistortionRenderer_renderEyeToDisplay können Sie die Verzerrung auf den Inhalt anwenden und den Inhalt auf dem Bildschirm 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_);