Bienvenue dans le Web immersif

Le Web immersif désigne les expériences de monde virtuel hébergées via le navigateur. Toutes ces expériences de réalité virtuelle s'affichent dans le navigateur ou dans les casques compatibles avec la RV.

Joe Medley
Joe Medley

Le Web immersif désigne les expériences de monde virtuel hébergées via le navigateur. Cela couvre l'ensemble des expériences de réalité virtuelle (RV) affichées dans le navigateur ou dans des casques compatibles avec la RV, comme Daydream de Google, Oculus Rift, Samsung Gear VR, HTC Vive et les casques Windows Mixed Reality, ainsi que les expériences de réalité augmentée développées pour les appareils mobiles compatibles avec la RA.

Bien que nous utilisions deux termes pour décrire les expériences immersives, ils doivent être considérés comme un spectre allant de la réalité complète à un environnement de RV complètement immersif, avec différents niveaux de RA entre les deux.

Voici quelques exemples d'expériences immersives :

  • Vidéos immersives à 360°
  • Vidéos 2D (ou 3D) traditionnelles présentées dans un environnement immersif
  • Visualisations des données
  • Shopping à dom
  • Art
  • Une idée géniale que personne n'a encore eue

Comment on y va ?

Le Web immersif est disponible depuis près d'un an, sous une forme embryonnaire. Cela a été fait via l'API WebVR 1.1, qui est disponible en phase d'évaluation pour les origines depuis Chrome 62. Cette API est également compatible avec Firefox et Edge, ainsi qu'avec un polyfill pour Safari.

Mais il est temps de passer à autre chose.

La phase d'évaluation de l'origine a pris fin le 24 juillet 2018. La spécification a été remplacée par l'API WebXR Device et une nouvelle phase d'évaluation de l'origine.

Qu'est devenu WebVR 1.1 ?

WebVR 1.1 nous a beaucoup appris, mais il est devenu évident que des modifications majeures étaient nécessaires pour prendre en charge les types d'applications que les développeurs souhaitaient créer. La liste complète des leçons apprises est trop longue pour être traitée ici, mais elle inclut des problèmes tels que l'association explicite de l'API au thread JavaScript principal, un trop grand nombre d'opportunités pour les développeurs de configurer des configurations manifestement incorrectes et des utilisations courantes telles que la fenêtre magique qui est un effet secondaire plutôt qu'une fonctionnalité intentionnelle. (La fenêtre magique est une technique permettant d'afficher du contenu immersif sans casque. L'application affiche une seule vue en fonction du capteur d'orientation de l'appareil.)

La nouvelle interface facilite les implémentations et améliore considérablement les performances. Au même moment, la RA et d'autres cas d'utilisation émergeaient, et il devenait important que l'API soit extensible pour les prendre en charge à l'avenir.

L'API WebXR Device a été conçue et nommée en tenant compte de ces cas d'utilisation étendus et offre une meilleure voie à suivre. Les implémentations de WebVR se sont engagées à migrer vers l'API WebXR Device.

Qu'est-ce que l'API WebXR Device ?

Comme la spécification WebVR avant elle, l'API WebXR Device est un produit du groupe de la communauté Web immersive, qui compte des contributeurs de Google, Microsoft, Mozilla et d'autres. La lettre X dans XR est conçue comme une sorte de variable algébrique qui représente tout ce qui se trouve dans le spectre des expériences immersives. Il est disponible dans la phase d'évaluation de l'origine mentionnée précédemment, ainsi que via un polyfill.

Lorsque cet article a été publié pour la première fois pendant la période bêta de Chrome 67, seules les fonctionnalités de réalité virtuelle étaient activées. La réalité augmentée est arrivée dans Chrome 69. Pour en savoir plus, consultez Réalité augmentée pour le Web.

Cette nouvelle API est bien plus complexe que ce que je peux décrire dans un article comme celui-ci. Je veux vous donner suffisamment d'informations pour commencer à comprendre les exemples WebXR. Pour en savoir plus, consultez l'explication d'origine et notre guide pour les utilisateurs de la première heure du Web immersif. Je vais développer ce dernier au fur et à mesure de l'avancement de l'essai. N'hésitez pas à signaler les problèmes ou à envoyer des demandes d'extraction.

Dans cet article, je vais expliquer comment démarrer, arrêter et exécuter une session XR, ainsi que quelques principes de base sur le traitement des entrées.

Je ne vais pas vous expliquer comment dessiner du contenu RA/RV à l'écran. L'API WebXR Device ne fournit pas de fonctionnalités de rendu d'image. La décision vous appartient. Le dessin est effectué à l'aide des API WebGL. Vous pouvez le faire si vous êtes vraiment ambitieux. Toutefois, nous vous recommandons d'utiliser un framework. Les exemples Web immersifs en utilisent un créé uniquement pour les démonstrations, appelé Cottontail. Three.js est compatible avec WebXR depuis mai. Je n'ai rien entendu à propos d'A-Frame.

Démarrer et exécuter une application

Le processus de base est le suivant:

  1. Demandez un appareil XR.
  2. S'il est disponible, demandez une session XR. Si vous souhaitez que l'utilisateur mette son téléphone dans un casque, il s'agit d'une session immersive qui nécessite un geste de l'utilisateur pour y accéder.
  3. Utilisez la session pour exécuter une boucle de rendu qui fournit 60 images par seconde. Dessinez le contenu approprié à l'écran dans chaque frame.
  4. Exécutez la boucle de rendu jusqu'à ce que l'utilisateur décide de quitter.
  5. Mettez fin à la session XR.

Examinons cela plus en détail et incluons du code. Vous ne pourrez pas exécuter d'application à partir de ce que je vais vous montrer. Mais encore une fois, il ne s'agit que d'une idée.

Demander un appareil XR

Vous reconnaîtrez ici le code de détection de caractéristiques standard. Vous pouvez encapsuler cela dans une fonction appelée checkForXR().

Si vous n'utilisez pas de session immersive, vous pouvez ignorer la publicité de la fonctionnalité et l'obtention d'un geste de l'utilisateur et passer directement à la demande d'une session. Une session immersive nécessite un casque. Une session non immersive affiche simplement le contenu sur l'écran de l'appareil. Le premier est ce à quoi la plupart des gens pensent quand on parle de réalité virtuelle ou de réalité augmentée. Ce dernier est parfois appelé "fenêtre magique".

if (navigator.xr) {
    navigator.xr.requestDevice()
    .then(xrDevice => {
    // Advertise the AR/VR functionality to get a user gesture.
    })
    .catch(err => {
    if (err.name === 'NotFoundError') {
        // No XRDevices available.
        console.error('No XR devices available:', err);
    } else {
        // An error occurred while requesting an XRDevice.
        console.error('Requesting XR device failed:', err);
    }
    })
} else{
    console.log("This browser does not support the WebXR API.");
}

Demander une session XR

Maintenant que nous avons notre appareil et notre geste de l'utilisateur, il est temps d'obtenir une session. Pour créer une session, le navigateur a besoin d'un canevas sur lequel dessiner.

xrPresentationContext = htmlCanvasElement.getContext('xrpresent');
let sessionOptions = {
    // The immersive option is optional for non-immersive sessions; the value
    //   defaults to false.
    immersive: false,
    outputContext: xrPresentationContext
}
xrDevice.requestSession(sessionOptions)
.then(xrSession => {
    // Use a WebGL context as a base layer.
    xrSession.baseLayer = new XRWebGLLayer(session, gl);
    // Start the render loop
})

Exécuter la boucle de rendu

Le code de cette étape nécessite un peu de démêlage. Pour vous aider à comprendre, je vais vous bombarder de mots. Si vous souhaitez jeter un œil au code final, passez à l'étape suivante pour avoir un aperçu, puis revenez pour obtenir une explication complète. Vous ne pourrez peut-être pas déduire grand-chose.

Le processus de base d'une boucle de rendu est le suivant :

  1. Demander une image d'animation
  2. Interrogez la position de l'appareil.
  3. Dessinez du contenu à l'emplacement de l'appareil en fonction de sa position.
  4. Effectuez le travail nécessaire pour les périphériques d'entrée.
  5. Répétez cette opération 60 fois par seconde jusqu'à ce que l'utilisateur décide de quitter l'application.

Demander un frame de présentation

Le mot "cadre" a plusieurs significations dans un contexte Web XR. Le premier est le cadre de référence, qui définit d'où l'origine du système de coordonnées est calculée et ce qu'il advient de cette origine lorsque l'appareil est déplacé. (La vue reste-t-elle la même lorsque l'utilisateur se déplace ou change-t-elle comme dans la vraie vie ?)

Le deuxième type de frame est le frame de présentation, représenté par un objet XRFrame. Cet objet contient les informations nécessaires pour afficher un seul frame d'une scène AR/VR sur l'appareil. Cela peut prêter à confusion, car un frame de présentation est récupéré en appelant requestAnimationFrame(). Il est ainsi compatible avec window.requestAnimationFrame().

Avant de vous laisser le temps de les assimiler, je vais vous proposer un code. L'exemple ci-dessous montre comment la boucle de rendu est démarrée et gérée. Remarquez la double utilisation de la trame de mot. Notez l'appel récursif de requestAnimationFrame(). Cette fonction sera appelée 60 fois par seconde.

xrSession.requestFrameOfReference('eye-level')
.then(xrFrameOfRef => {
    xrSession.requestAnimationFrame(onFrame(time, xrFrame) {
    // The time argument is for future use and not implemented at this time.
    // Process the frame.
    xrFrame.session.requestAnimationFrame(onFrame);
    }
});

Postures

Avant de dessiner quoi que ce soit à l'écran, vous devez savoir où pointe l'appareil d'affichage et vous devez y avoir accès. En général, en RA/RV, la position et l'orientation d'un élément sont appelées "pose". Les lecteurs et les appareils d'entrée ont une pose. (Nous aborderons les périphériques d'entrée plus tard.) Les positions du lecteur et de l'appareil d'entrée sont définies comme une matrice 4 x 4 stockée dans un Float32Array dans l'ordre des colonnes. Vous obtenez la position du spectateur en appelant XRFrame.getDevicePose() sur l'objet de frame d'animation actuel. Testez toujours si vous avez reçu une pose en retour. Si quelque chose ne va pas, vous ne voulez pas dessiner à l'écran.

let pose = xrFrame.getDevicePose(xrFrameOfRef);
if (pose) {
    // Draw something to the screen.
}

Vues

Après avoir vérifié la pose, il est temps de dessiner quelque chose. L'objet sur lequel vous dessinez s'appelle une vue (XRView). C'est là que le type de session devient important. Les vues sont extraites de l'objet XRFrame sous la forme d'un tableau. Si vous êtes dans une session non immersive, le tableau comporte une seule vue. Dans une session immersive, le tableau en comporte deux, un pour chaque œil.

for (let view of xrFrame.views) {
    // Draw something to the screen.
}

Il s'agit d'une différence importante entre WebXR et les autres systèmes immersifs. Bien qu'il puisse sembler inutile d'itérer sur une seule vue, cela vous permet d'avoir un seul chemin de rendu pour divers appareils.

L'ensemble de la boucle de rendu

En rassemblant tout cela, j'obtiens le code ci-dessous. J'ai laissé un espace réservé pour les périphériques d'entrée, que nous aborderons dans une section ultérieure.

xrSession.requestFrameOfReference('eye-level')
.then(xrFrameOfRef => {
    xrSession.requestAnimationFrame(onFrame(time, xrFrame) {
    // The time argument is for future use and not implemented at this time.
    let pose = xrFrame.getDevicePose(xrFrameOfRef);
    if (pose) {
        for (let view of xrFrame.views) {
        // Draw something to the screen.
        }
    }
    // Input device code will go here.
    frame.session.requestAnimationFrame(onFrame);
    }
}

Arrêter la session XR

Une session XR peut se terminer pour plusieurs raisons, y compris par votre propre code via un appel à XRSession.end(). Le casque peut également être déconnecté ou une autre application peut le contrôler. C'est pourquoi une application bien gérée doit surveiller l'événement de fin et, lorsqu'il se produit, supprimer les objets de session et de rendu. Une fois qu'une session XR est terminée, elle ne peut plus être reprise.

xrDevice.requestSession(sessionOptions)
.then(xrSession => {
    // Create a WebGL layer and initialize the render loop.
    xrSession.addEventListener('end', onSessionEnd);
});

// Restore the page to normal after immersive access has been released.
function onSessionEnd() {
    xrSession = null;

    // Ending the session stops executing callbacks passed to the XRSession's
    // requestAnimationFrame(). To continue rendering, use the window's
    // requestAnimationFrame() function.
    window.requestAnimationFrame(onDrawFrame);
}

Comment fonctionne l'interaction ?

Comme pour la durée de vie de l'application, je vais juste vous donner un aperçu de la façon d'interagir avec des objets en RA ou en RV.

L'API WebXR Device adopte une approche "pointer-cliquer" pour la saisie utilisateur. Avec cette approche, chaque source d'entrée dispose d'un rayon de pointeur défini pour indiquer où pointe un périphérique d'entrée et d'événements pour indiquer le moment où quelque chose a été sélectionné. Votre application dessine le rayon du pointeur et indique où il est pointé. Lorsque l'utilisateur clique sur le périphérique d'entrée, des événements sont déclenchés, en particulier select, selectStart et selectEnd. Votre application détermine l'élément sur lequel l'utilisateur a cliqué et répond de manière appropriée.

Périphérique d'entrée et rayon du pointeur

Pour les utilisateurs, le rayon du pointeur n'est qu'une ligne faible entre le contrôleur et l'élément qu'ils pointent. Mais votre application doit le dessiner. Cela signifie obtenir la position de l'appareil d'entrée et tracer une ligne entre son emplacement et un objet dans l'espace AR/VR. Ce processus ressemble à peu près à ceci:

let inputSources = xrSession.getInputSources();
for (let xrInputSource of inputSources) {
    let inputPose = frame.getInputPose(inputSource, xrFrameOfRef);
    if (!inputPose) {
    continue;
    }
    if (inputPose.gripMatrix) {
    // Render a virtual version of the input device
    //   at the correct position and orientation.
    }
    if (inputPose.pointerMatrix) {
    // Draw a ray from the gripMatrix to the pointerMatrix.
    }
}

Il s'agit d'une version allégée de l'exemple de suivi des entrées du groupe de la communauté Web immersif. Comme pour le rendu de frame, le dessin du rayon du pointeur et de l'appareil vous appartient. Comme mentionné précédemment, ce code doit être exécuté dans la boucle de rendu.

Sélectionner des éléments dans un espace virtuel

Se contenter de pointer du doigt des éléments en RA/RV n'a aucune utilité. Pour effectuer des actions utiles, les utilisateurs doivent pouvoir sélectionner des éléments. L'API WebXR Device fournit trois événements pour répondre aux interactions utilisateur: select, selectStart et selectEnd. Ils présentent une particularité à laquelle je ne m'attendais pas : ils ne vous indiquent que qu'un appareil d'entrée a été cliqué. Ils ne vous indiquent pas sur quel élément de l'environnement l'utilisateur a cliqué. Les gestionnaires d'événements sont ajoutés à l'objet XRSession et doivent être ajoutés dès qu'ils sont disponibles.

xrDevice.requestSession(sessionOptions)
.then(xrSession => {
    // Create a WebGL layer and initialize the render loop.
    xrSession.addEventListener('selectstart', onSelectStart);
    xrSession.addEventListener('selectend', onSelectEnd);
    xrSession.addEventListener('select', onSelect);
});

Ce code est basé sur un exemple de sélection des entrées, au cas où vous auriez besoin de plus de contexte.

Pour déterminer sur quoi l'utilisateur a cliqué, vous utilisez une pose. (Êtes-vous surpris ? Je ne pensais pas.) Les détails de ce processus sont spécifiques à votre application ou au framework que vous utilisez, et ne relèvent donc pas du champ d'application de cet article. L'approche de Cottontail est illustrée dans l'exemple de sélection des entrées.

function onSelect(ev) {
    let inputPose = ev.frame.getInputPose(ev.inputSource, xrFrameOfRef);
    if (!inputPose) {
    return;
    }
    if (inputPose.pointerMatrix) {
    // Figure out what was clicked and respond.
    }
}

Conclusion: regarder vers l'avenir

Comme indiqué précédemment, la réalité augmentée est attendue dans Chrome 69 (Canary vers juin 2018). Je vous encourage toutefois à essayer ce que nous avons mis en place jusqu'à présent. Nous avons besoin de vos commentaires pour l'améliorer. Suivez sa progression sur ChromeStatus.com pour le test de positionnement WebXR. Vous pouvez également suivre WebXR Anchors pour améliorer le suivi des postures.