La réalité virtuelle arrive sur le Web

Voici quelques bases pour vous préparer à un large éventail d'expériences immersives : la réalité virtuelle, la réalité augmentée et tout ce qui se trouve entre les deux.

Joe Medley
Joe Medley

Les expériences immersives sont arrivées sur le Web dans Chrome 79. L'API WebXR Device apporte la réalité virtuelle, tandis que la compatibilité avec la réalité augmentée arrive dans Chrome 81. Une mise à jour de l'API GamePad étend l'utilisation avancée des commandes à la VR. D'autres navigateurs seront bientôt compatibles avec ces spécifications, y compris Firefox Reality, le navigateur Oculus, Edge et le navigateur Helio de Magic Leap, entre autres.

Cet article est le premier d'une série sur le Web immersif. Cette partie explique comment configurer une application WebXR de base, ainsi que comment démarrer et arrêter une session XR. Les articles suivants aborderont la boucle de frame (le moteur de l'expérience WebXR), les spécificités de la réalité augmentée et l'API WebXR Hit Test, un moyen de détecter les surfaces dans une session de RA. Sauf indication contraire, tout ce que je couvre dans cet article et les suivants s'applique aussi bien à la RA qu'à la RV.

Qu'est-ce que le Web immersif ?

Bien que nous utilisions deux termes pour décrire les expériences immersives (réalité augmentée et réalité virtuelle), beaucoup les considèrent comme un spectre allant de la réalité complète au virtuel complet, avec des degrés d'immersion intermédiaires. Le "X" de XR est censé refléter cette idée en étant une sorte de variable algébrique qui représente tout ce qui se trouve dans le spectre des expériences immersives.

Graphique illustrant le spectre des expériences visuelles, de la réalité complète à l'immersion totale.
Le spectre des expériences immersives

Voici quelques exemples d'expériences immersives :

  • Jeux
  • Vidéo à 360°
  • Vidéos 2D (ou 3D) traditionnelles présentées dans un environnement immersif
  • Achat d'un logement
  • Visualiser des produits chez vous avant de les acheter
  • Art immersif
  • Une idée géniale à laquelle personne n'a encore pensé

Concepts et utilisation

Je vais vous expliquer quelques principes de base de l'utilisation de l'API WebXR Device. Si vous avez besoin de plus de détails que ceux que je vous ai fournis, consultez les exemples WebXR du groupe de travail Immersive Web ou les documents de référence MDN en constante évolution. Si vous connaissez les premières versions de l'API WebXR Device, vous devriez parcourir l'ensemble de ce contenu. Des modifications ont été apportées.

Le code de cet article est basé sur l'exemple minimaliste du groupe de travail Immersive Web (démo, source), mais il a été modifié pour plus de clarté et de simplicité.

L'élaboration de la spécification WebXR a permis de développer des mesures de sécurité et de confidentialité pour protéger les utilisateurs. Par conséquent, les implémentations doivent respecter certaines exigences. Une page Web ou une application doivent être actives et sélectionnées avant de pouvoir demander des informations sensibles au spectateur. Les pages Web ou les applications doivent être diffusées via HTTPS. L'API elle-même est conçue pour protéger les informations obtenues à partir des capteurs et des caméras, dont elle a besoin pour fonctionner.

Demander une session

Le lancement d'une session XR nécessite un geste de l'utilisateur. Pour ce faire, utilisez la détection de fonctionnalités pour tester XRSystem (via navigator.xr) et appelez XRSystem.isSessionSupported(). Notez que dans les versions 79 et 80 de Chrome, l'objet XRSystem était appelé XR.

Dans l'exemple ci-dessous, j'ai indiqué que je souhaitais une session de réalité virtuelle avec le type de session 'immersive-vr'. Les autres types de sessions sont 'immersive-ar' et 'inline'. Une session intégrée permet de présenter du contenu dans HTML. Elle est principalement utilisée pour les teasers. L'exemple de session AR immersive illustre ce point. J'expliquerai cela dans un prochain article.

Une fois que je sais que les sessions de réalité virtuelle sont prises en charge, j'active un bouton qui me permet d'acquérir un geste de l'utilisateur.

if (navigator.xr) {
  const supported = await navigator.xr.isSessionSupported('immersive-vr');
  if (supported) {
    xrButton.addEventListener('click', onButtonClicked);
    xrButton.textContent = 'Enter VR';
    xrButton.enabled = supported; // supported is Boolean
  }
}

Après avoir activé le bouton, j'attends un événement de clic, puis je demande une session.

let xrSession = null;
function onButtonClicked() {
  if (!xrSession) {
    navigator.xr.requestSession('immersive-vr')
    .then((session) => {
      xrSession = session;
      xrButton.textContent = 'Exit XR';
      onSessionStarted(xrSession);
    });
  } else {
    xrSession.end();
  }
}

Notez la hiérarchie des objets dans ce code. Il passe de navigator à xr, puis à une instance XRSession. Dans les premières versions de l'API, un script devait demander un appareil avant de demander une session. L'appareil est désormais acquis de manière implicite.

Saisir une session

Une fois la session obtenue, je dois la démarrer et y accéder. Mais avant cela, je dois configurer quelques éléments. Une session a besoin d'un gestionnaire d'événements onend pour que l'application ou la page Web puissent être réinitialisées lorsque l'utilisateur quitte.

J'aurai également besoin d'un élément <canvas> pour dessiner ma scène. Il doit s'agir d'un WebGLRenderingContext ou d'un WebGL2RenderingContext compatible avec XR. Tous les dessins sont réalisés à l'aide de ces éléments ou d'un framework basé sur WebGL tel que Three.js.

Maintenant que j'ai un endroit où dessiner, j'ai besoin d'une source de contenu sur laquelle dessiner. Pour ce faire, je crée une instance de XRWebGLLayer. Je l'associe au canevas en appelant XRSession.updateRenderState().

Une fois dans une session, j'ai besoin de savoir où se trouvent les éléments dans la réalité virtuelle. J'ai besoin d'un espace de référence. Un espace de référence 'local-floor' est un espace où l'origine est située près du spectateur et où l'axe Y est à 0 au niveau du sol et ne devrait pas bouger. Il existe d'autres types d'espaces de référence, mais il s'agit d'un sujet plus complexe que je ne peux aborder ici. J'enregistre l'espace de référence dans une variable, car j'en aurai besoin lorsque je dessinerai à l'écran.

function onSessionStarted(xrSession) {
  xrSession.addEventListener('end', onSessionEnded);

  let canvas = document.createElement('canvas');
  webGLRenContext = canvas.getContext('webgl', { xrCompatible: true });

  xrSession.updateRenderState({
    baseLayer: new XRWebGLLayer(xrSession, webGLRenContext)
  });

  xrSession.requestReferenceSpace('local-floor')
  .then((refSpace) => {
    xrRefSpace = refSpace;
    xrSession.requestAnimationFrame(onXRFrame);
  });
}

Après avoir obtenu un espace de référence, j'appelle XRSession.requestAnimationFrame(). C'est le début de la présentation du contenu virtuel, qui se fait dans la boucle de frame.

Exécuter une boucle de frames

La boucle de frame est une boucle infinie contrôlée par l'agent utilisateur dans laquelle le contenu est dessiné à plusieurs reprises sur l'écran. Le contenu est dessiné dans des blocs distincts appelés frames. La succession d'images crée l'illusion du mouvement. Pour les applications de réalité virtuelle, le nombre d'images par seconde peut varier de 60 à 144. La RA pour Android fonctionne à 30 images par seconde. Votre code ne doit pas supposer une fréquence d'images particulière.

Le processus de base pour la boucle de frame est le suivant :

  1. Appelez XRSession.requestAnimationFrame(). En réponse, l'agent utilisateur appelle XRFrameRequestCallback, que vous avez défini.
  2. Dans votre fonction de rappel :
    1. Rappelez XRSession.requestAnimationFrame().
    2. Obtenez la pose du spectateur.
    3. Transmettez (liez) le WebGLFramebuffer du XRWebGLLayer au WebGLRenderingContext.
    4. Itérez sur chaque objet XRView, en récupérant son XRViewport à partir de XRWebGLLayer et en le transmettant à WebGLRenderingContext.
    5. Dessinez quelque chose dans le framebuffer.

Le reste de cet article décrit l'étape 1 et une partie de l'étape 2, à savoir la configuration et l'appel de XRFrameRequestCallback. Les éléments restants de l'étape 2 sont abordés dans la partie II.

XRFrameRequestCallback

C'est vous qui définissez XRFrameRequestCallback. Il utilise deux paramètres : une instance DOMHighResTimeStamp et une instance XRFrame. L'objet XRFrame fournit les informations nécessaires pour afficher un seul frame. L'argument DOMHighResTimeStamp est réservé pour une utilisation ultérieure.

Avant toute chose, je vais demander le prochain frame d'animation. Comme indiqué précédemment, le timing des frames est déterminé par l'agent utilisateur en fonction du matériel sous-jacent. Le fait de demander d'abord le frame suivant garantit que la boucle de frames se poursuit si une erreur se produit lors du rappel.

function onXRFrame(hrTime, xrFrame) {
  let xrSession = xrFrame.session;
  xrSession.requestAnimationFrame(onXRFrame);
  // Render a frame.
}

À ce stade, il est temps de dessiner quelque chose pour le spectateur. Nous en parlerons dans la deuxième partie. Avant d'y aller, je vais vous montrer comment mettre fin à une session.

Mettre fin à la session

Une session immersive peut se terminer pour plusieurs raisons, y compris par votre propre code via un appel à XRSession.end(). D'autres causes peuvent être à l'origine de ce problème, comme la déconnexion du casque ou la prise de contrôle par une autre application. C'est pourquoi une application bien conçue doit surveiller l'événement end. Dans ce cas, supprimez la session et les objets de rendu associés. Il est impossible de reprendre une session immersive terminée. Pour revenir à l'expérience immersive, mon application doit démarrer une nouvelle session.

Rappelez-vous que, dans la section Entrer dans une session, j'ai ajouté un gestionnaire d'événements onend lors de la configuration.

function onSessionStarted(xrSession) {
  xrSession.addEventListener('end', onSessionEnded);
  // More setup…
}

Dans le gestionnaire d'événements, restaurez l'état de l'application avant que l'utilisateur n'ouvre une session.

function onSessionEnded(event) {
  xrSession = null;
  xrButton.textContent = 'Enter VR';
}

Conclusion

Je n'ai pas tout expliqué pour écrire une application Web XR ou AR. J'espère vous avoir donné suffisamment d'informations pour que vous puissiez commencer à comprendre le code par vous-même et à faire vos propres tests. Dans le prochain article, je vais vous expliquer la boucle de frame, qui est l'endroit où le contenu est dessiné à l'écran.