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

Ce guide vous 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 un rendu stéréoscopique, suivre les mouvements de la tête et y réagir, et interagir avec les applications en détectant lorsque l'utilisateur appuie sur le bouton du casque.

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

  • Configurer l'environnement de développement
  • Télécharger et compiler l'application de démonstration
  • Scanner le QR code d'une visionneuse Cardboard pour enregistrer ses paramètres
  • Suivre les mouvements de la tête de l'utilisateur
  • Afficher des images stéréoscopiques en définissant la matrice de projection de vue appropriée pour chaque œil

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

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

Configurer l'environnement de développement

Configuration matérielle requise :

  • Appareil Android équipé d'Android 8.0 "Oreo" (niveau d'API 26) ou version ultérieure
  • Visionneuse Cardboard

Configuration logicielle requise :

  • Android Studio version 2024.1.2 "Koala Feature Drop" ou ultérieure
  • SDK Android 15.0 "Vanilla Ice Cream" (niveau d'API 35) ou version ultérieure
  • Dernière version du framework Android NDK

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

    System Settings > Android SDK dans Android Studio.

Télécharger et compiler l'application de démonstration

Le SDK Cardboard est conçu à l'aide d'un fichier d'en-tête Vulkan précompilé pour chaque nuanceur. Pour savoir comment créer les fichiers d'en-tête à partir de zéro, cliquez ici.

  1. Exécutez la commande suivante pour cloner le SDK Cardboard et l'application de démonstration HelloCardboard depuis 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 "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 (Affichage > Fenêtres d'outils > Gradle).

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

Scannez le QR code

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

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

Essayer la démo

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

Pour trouver et collecter une sphère :

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

  2. Regardez directement la sphère. La couleur change.

  3. Appuyez sur le bouton du casque Cardboard pour "collecter" la sphère.

Configurer l'appareil

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

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

Activer l'émulateur x86 d'Android Studio

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

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

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

Suivi de la tête

Créer un capteur de mouvements de la tête

Le capteur de tête est créé une seule 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 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 reprendre le suivi de la tête

Pour mettre en pause, reprendre et détruire le suivi 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 Cardboard 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 appropriée au contenu affiché :

CardboardQrCode_getSavedDeviceParams(&buffer, &size);

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

CardboardQrCode_destroy(buffer);

Affichage

L'affichage de contenu dans Cardboard implique les éléments suivants :

  • Créer des textures
  • Obtenir les matrices de vue et de projection pour l'œil gauche et l'œil droit
  • Créer le moteur de rendu et définir le maillage de distorsion
  • Rendu de chaque frame

Créer des textures

Tout le contenu est dessiné sur une texture, qui est divisée en sections pour l'œil gauche et l'œil 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 oculaires pour l'œil gauche et l'œil 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, obtenez 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 l'œil gauche et l'œil 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);

Affichage du contenu

Pour chaque frame, 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 vue/projection 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 la distorsion au contenu et l'afficher à 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_);