Algunos conceptos básicos para prepararte para un espectro de experiencias inmersivas: realidad virtual, realidad aumentada y todo lo que hay entre ellas.
Las experiencias inmersivas llegaron a la Web en Chrome 79. La API de WebXR Device ofrece realidad virtual, mientras que la compatibilidad con la realidad aumentada llega en Chrome 81. Además, una actualización de la API de Gamepad extiende el uso avanzado de los controles a la RV. Otros navegadores admitirán estas especificaciones pronto, incluidos Firefox Reality, Oculus Browser, Edge y el navegador Helio de Magic Leap, entre otros.
Este artículo inicia una serie sobre la Web inmersiva. En esta entrega, se explica cómo configurar una aplicación básica de WebXR, así como cómo entrar y salir de una sesión de XR. En artículos posteriores, se abordará el bucle de fotogramas (el motor de la experiencia de WebXR), los detalles específicos de la realidad aumentada y la API de WebXR Hit Test, un medio para detectar superficies en una sesión de RA. A menos que se indique lo contrario, todo lo que abarco en este y los siguientes artículos se aplica por igual a la RA y la RV.
¿Qué es la Web inmersiva?
Si bien usamos dos términos para describir las experiencias inmersivas (realidad aumentada y realidad virtual), muchas personas las consideran un espectro que va desde la realidad completa hasta la realidad completamente virtual, con grados de inmersión intermedios. La "X" en XR pretende reflejar ese pensamiento al ser una especie de variable algebraica que representa cualquier cosa en el espectro de experiencias inmersivas.
Estos son algunos ejemplos de experiencias inmersivas:
- Videojuegos
- videos panorámicos de 360º
- Videos tradicionales en 2D (o 3D) presentados en entornos envolventes
- Compra de casas
- Ver los productos en tu casa antes de comprarlos
- Arte inmersivo
- Algo genial en lo que nadie pensó aún
Conceptos y uso
Te explicaré algunos conceptos básicos para usar la API de WebXR Device. Si necesitas más información de la que te proporcioné, consulta los ejemplos de WebXR del Grupo de trabajo de la Web inmersiva o los materiales de referencia cada vez más amplios de MDN. Si conoces las primeras versiones de la API de WebXR Device, deberías echar un vistazo a todo este material. Hubo cambios.
El código de este artículo se basa en la muestra básica del Grupo de trabajo de la Web Immersiva (demostración, fuente), pero se editó para mayor claridad y simplicidad.
Parte de la creación de la especificación de WebXR consistió en desarrollar medidas de seguridad y privacidad para proteger a los usuarios. Por lo tanto, las implementaciones deben cumplir con ciertos requisitos. Una página web o una app deben estar activas y enfocadas para poder solicitarle al usuario cualquier información sensible. Las páginas web o las aplicaciones deben publicarse a través de HTTPS. La API en sí está diseñada para proteger la información obtenida de los sensores y las cámaras, que necesita para funcionar.
Solicita una sesión
Para iniciar una sesión de XR, se requiere un gesto del usuario. Para obtenerlo, usa la detección de funciones para probar XRSystem (a través de navigator.xr) y haz una llamada a XRSystem.isSessionSupported(). Ten en cuenta que, en las versiones 79 y 80 de Chrome, el objeto XRSystem se llamaba XR.
En el siguiente ejemplo, indiqué que quiero una sesión de realidad virtual con el tipo de sesión 'immersive-vr'. Los otros tipos de sesión son 'immersive-ar' y 'inline'. Una sesión intercalada se usa para presentar contenido dentro de HTML y se utiliza principalmente para el contenido de avance. En la muestra de Sesión de RA inmersiva, se demuestra esto. Lo explicaré en un artículo posterior.
Una vez que sé que se admiten las sesiones de realidad virtual, habilito un botón que me permite adquirir un gesto del usuario.
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
}
}
Después de habilitar el botón, espero un evento de clic y, luego, solicito una sesión.
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();
}
}
Observa la jerarquía de objetos en este código. Se mueve de navigator a xr y, luego, a una instancia de XRSession. En las primeras versiones de la API, una secuencia de comandos debía solicitar un dispositivo antes de solicitar una sesión. Ahora, el dispositivo se adquiere de forma implícita.
Cómo ingresar a una sesión
Después de obtener una sesión, debo iniciarla y entrar en ella. Pero primero, debo configurar algunas cosas. Una sesión necesita un controlador de eventos onend para que la app o la página web se puedan restablecer cuando el usuario salga.
También necesitaré un elemento <canvas> para dibujar mi escena. Debe ser un WebGLRenderingContext o un WebGL2RenderingContext compatible con XR.
Todo el dibujo se realiza con ellos o con un framework basado en WebGL, como Three.js.
Ahora que tengo un lugar para dibujar, necesito una fuente de contenido para hacerlo. Para ello, creo una instancia de XRWebGLLayer. Para asociarlo con el lienzo, llamo a XRSession.updateRenderState().
Una vez que estoy en una sesión, necesito una forma de determinar dónde están las cosas en la realidad virtual. Necesitaré un espacio de referencia. Un espacio de referencia 'local-floor' es aquel en el que el origen se encuentra cerca del usuario, el eje Y es 0 a nivel del piso y no se espera que se mueva. Existen otros tipos de espacios de referencia, pero ese es un tema más complicado que no puedo abordar aquí. Guardo el espacio de referencia en una variable porque lo necesitaré cuando dibuje en la pantalla.
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);
});
}
Después de obtener un espacio de referencia, llamo a XRSession.requestAnimationFrame().
Este es el inicio de la presentación de contenido virtual, que se realiza en el bucle de fotogramas.
Ejecuta un bucle de fotogramas
El bucle de fotogramas es un bucle infinito controlado por el agente de usuario en el que el contenido se dibuja repetidamente en la pantalla. El contenido se dibuja en bloques discretos llamados fotogramas. La sucesión de fotogramas crea la ilusión de movimiento. En el caso de las aplicaciones de RV, los fotogramas por segundo pueden variar entre 60 y 144. La RA para Android se ejecuta a 30 fotogramas por segundo. Tu código no debe suponer una velocidad de fotogramas específica.
El proceso básico del bucle de fotogramas es el siguiente:
- Llamar a
XRSession.requestAnimationFrame()En respuesta, el agente de usuario invoca elXRFrameRequestCallback, que tú defines. - Dentro de la función de devolución de llamada, haz lo siguiente:
- Vuelve a llamar a
XRSession.requestAnimationFrame(). - Obtén la postura del usuario.
- Pasa (víncula) el
WebGLFramebufferdelXRWebGLLayeralWebGLRenderingContext. - Itera sobre cada objeto
XRView, recupera suXRViewportdelXRWebGLLayery pásalo alWebGLRenderingContext. - Dibuja algo en el búfer de fotogramas.
- Vuelve a llamar a
En el resto de este artículo, se describen el paso 1 y parte del paso 2, es decir, la configuración y la llamada a XRFrameRequestCallback. Los elementos restantes del paso 2 se abordan en la parte II.
XRFrameRequestCallback
Tú defines el XRFrameRequestCallback. Toma dos parámetros: un DOMHighResTimeStamp y una instancia de XRFrame. El objeto XRFrame proporciona la información necesaria para renderizar un solo fotograma en la pantalla. El argumento DOMHighResTimeStamp se reserva para uso futuro.
Antes de hacer cualquier otra cosa, solicitaré el siguiente fotograma de animación. Como se mencionó anteriormente, el tiempo de los fotogramas lo determina el agente de usuario en función del hardware subyacente. Solicitar el siguiente fotograma primero garantiza que el bucle de fotogramas continúe si algo durante la devolución de llamada arroja un error.
function onXRFrame(hrTime, xrFrame) {
let xrSession = xrFrame.session;
xrSession.requestAnimationFrame(onXRFrame);
// Render a frame.
}
En este punto, es hora de dibujar algo para el usuario. Ese es un debate para la parte II. Antes de ir allí, te mostraré cómo finalizar una sesión.
Finaliza la sesión
Una sesión envolvente puede finalizar por varios motivos, incluido el final de la sesión por tu propio código a través de una llamada a XRSession.end(). Otras causas incluyen que los auriculares estén desconectados o que otra aplicación los controle. Por este motivo, una aplicación que se comporta correctamente debe supervisar el evento end. Cuando esto ocurre, descarta la sesión y sus objetos de renderización relacionados. No se puede reanudar una sesión inmersiva finalizada. Para volver a ingresar a la experiencia inmersiva, mi app debe iniciar una sesión nueva.
Recuerda de Cómo ingresar a una sesión que, durante la configuración, agregué un controlador de eventos onend.
function onSessionStarted(xrSession) {
xrSession.addEventListener('end', onSessionEnded);
// More setup…
}
Dentro del controlador de eventos, restablece el estado de la app antes de que el usuario ingresara a una sesión.
function onSessionEnded(event) {
xrSession = null;
xrButton.textContent = 'Enter VR';
}
Conclusión
No expliqué todo lo que necesitas para escribir una aplicación de WebXR o RA. Espero que te haya brindado suficiente información para que puedas comprender el código por tu cuenta y comenzar a experimentar. En el próximo artículo, explicaré el bucle de fotogramas, que es donde se dibuja el contenido en la pantalla.