Guide de démarrage rapide pour Google Cardboard pour le NDK Android

Ce guide explique comment utiliser le SDK Cardboard pour Android afin de créer vos propres expériences de réalité virtuelle (RV).

Vous pouvez utiliser le SDK Cardboard pour transformer un smartphone en plate-forme de réalité virtuelle. Un smartphone peut afficher des scènes 3D avec rendu stéréoscopique, suivre les mouvements de la tête et y réagir, et interagir avec les applications en détectant quand l'utilisateur appuie sur le bouton de la visionneuse.

Pour commencer, vous allez utiliser HelloCardboard, un jeu de démonstration qui présente les principales fonctionnalités du SDK Cardboard. Dans ce jeu, les utilisateurs regardent un monde virtuel pour trouver et collecter des objets. Il vous explique comment:

  • Configurer l'environnement de développement
  • Télécharger et créer l'application de démonstration
  • Scannez le code QR d'une visionneuse Cardboard pour enregistrer ses paramètres
  • Suivre les mouvements de la tête de l'utilisateur
  • Améliorez le rendu d'images stéréoscopiques en définissant la matrice de projection de vue adaptée pour chaque œil

HelloCardboard utilise le NDK Android. Chaque méthode native est:

  • Limité de manière unique à une méthode de classe HelloCardboardApp ; ou
  • Crée ou supprime une instance de cette classe.

Configurer l'environnement de développement

Configuration matérielle requise:

  • Appareil Android fonctionnant sous Android 8.0 Oreo (niveau d'API 26) ou version ultérieure
  • Visionneuse cardboard

Configuration logicielle requise:

  • Android Studio version 2022.1.1 "Electric Eel" ou ultérieure
  • SDK Android 13.0 "Tiramisu" (niveau d'API 33) ou version ultérieure
  • La dernière version du framework Android NDK

    Pour examiner ou mettre à jour les SDK installés, accédez à Préférences > Apparence et comportement

    System Settings > Android SDK (Paramètres système > SDK Android) dans Android Studio.

Télécharger et créer l'application de démonstration

Le SDK Cardboard est créé à l'aide d'un fichier d'en-tête Vulkan précompilé pour chaque nuanceur. Pour connaître les étapes permettant de créer entièrement les fichiers d'en-tête, consultez cette page.

  1. Exécutez la commande suivante pour cloner le SDK Cardboard et l'application de démonstration HelloCardboard à partir de GitHub:

    git clone https://github.com/googlevr/cardboard.git
  2. Dans Android Studio, sélectionnez Open an existing Android Studio Project (Ouvrir un projet Android Studio existant), puis sélectionnez le répertoire dans lequel le SDK Cardboard et l'application de démonstration HelloCardboard ont été clonés.

    Votre code s'affiche dans la fenêtre "Project" (Projet) d'Android Studio.

  3. Pour assembler le SDK Cardboard, double-cliquez sur l'option assemble dans le dossier cardboard/:sdk/Tasks/build de l'onglet Gradle (Vue > Fenêtres d'outil > Gradle).

  4. Exécutez l'application de démonstration HelloCardboard sur votre téléphone en sélectionnant Run > Run (Exécuter > Exécuter), puis sélectionnez la cible hellocardboard-android.

Scanner le code QR

Pour enregistrer les paramètres de l'appareil, scannez le code QR dans la visionneuse Cardboard :

Si l'utilisateur appuie sur "PASSER" et qu'aucun paramètre n'a été enregistré précédemment, Carton enregistre les paramètres de la version 1 de Google Cardboard (lancée lors de Google I/O 2014).

Essayer la version de démonstration

Dans HelloCardboard, vous allez rechercher et collecter des sphères géodésiques dans l'espace 3D.

Pour trouver et collecter une sphère:

  1. Bougez la tête dans n'importe quelle direction jusqu'à ce qu'une forme flottante apparaisse.

  2. Regardez directement la sphère. Elle change alors de couleur.

  3. Appuyez sur le bouton de la visionneuse Cardboard pour "collecter" la sphère.

Configurer l'appareil

Lorsque l'utilisateur appuie sur l'icône en forme de roue dentée pour changer de visionneuse Carton, la méthode nativeSwitchViewer est appelée. nativeSwitchViewer appelle CardboardQrCode_scanQrCodeAndSaveDeviceParams, qui ouvre la fenêtre pour scanner le code QR du lecteur. La distorsion de l'objectif du spectateur et d'autres paramètres sont mis à jour une fois le code QR scanné.

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

Activer l'émulateur Android Studio x86

Pour compiler pour l'émulateur Android Studio x86, supprimez la ligne suivante des fichiers build.gradle dans le SDK et l'exemple:

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

Cela active toutes les ABI et augmente considérablement la taille du fichier .aar généré. Pour en savoir plus, consultez la section ABI Android.

Suivi des mouvements de la tête

Créer un moniteur de tête

Le suivi des mouvements de la tête est créé une fois dans le constructeur de HelloCardboardApp:

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

Lorsque l'élément VrActivity est créé, une instance de la classe HelloCardboardApp est générée en appelant la méthode nativeOnCreate:

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

Mettre en pause et réactiver le suivi des mouvements de la tête

Pour suspendre, reprendre et détruire le suivi des mouvements de la tête, CardboardHeadTracker_pause(head_tracker_), CardboardHeadTracker_resume(head_tracker_) et CardboardHeadTracker_destroy(head_tracker_) doivent être appelés respectivement. Dans l'application "HelloCardboard", nous les appelons dans nativeOnPause, nativeOnResume et 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;
}

Distorsion de l'objectif

Chaque fois que Carton scanne un nouveau code QR, le code suivant lit les paramètres enregistrés et les utilise pour créer l'objet de distorsion de l'objectif, qui applique la distorsion optique appropriée au contenu rendu:

CardboardQrCode_getSavedDeviceParams(&buffer, &size);

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

CardboardQrCode_destroy(buffer);

Affichage

Voici ce que vous devez faire pour rendre du contenu dans Carton:

  • Créer des textures
  • Obtenir des matrices de vue et de projection pour les yeux gauche et droit
  • Créer le moteur de rendu et définir le maillage de distorsion
  • Le rendu de chaque image

Créer des textures

Tout le contenu est dessiné sur une texture, qui est divisée en sections pour les yeux gauche et droit. Ces sections sont initialisées dans _leftEyeTexture et _rightEyeTexture, respectivement.

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

Ces textures sont transmises en tant que paramètres à CardboardDistortionRenderer_renderEyeToDisplay.

Obtenir les matrices de vue et de projection pour l'œil gauche et l'œil droit

Tout d'abord, récupérez les matrices des yeux pour les yeux gauche et droit:

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

Ensuite, récupérez les maillages de distorsion pour chacun des yeux et transmettez-les au moteur de rendu de distorsion:

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

Créer le moteur de rendu et définir le maillage de distorsion approprié

Le moteur de rendu ne doit être initialisé qu'une seule fois. Une fois le moteur de rendu créé, définissez le nouveau maillage de distorsion pour les yeux gauche et droit en fonction des valeurs de maillage renvoyées par la fonction CardboardLensDistortion_getDistortionMesh.

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

Afficher le contenu

Pour chaque image, récupérez l'orientation actuelle de la tête à partir de CardboardHeadTracker_getPose:

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

Utilisez l'orientation actuelle de la tête avec les matrices de vue et de projection pour composer une matrice de projection de vue pour chacun des yeux et afficher le contenu à l'écran:

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

Utilisez CardboardDistortionRenderer_renderEyeToDisplay pour appliquer la correction de distorsion au contenu et afficher ce dernier à l'écran.

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