La Web inmersiva se refiere a experiencias de mundos virtuales alojados a través del navegador. Todas estas experiencias de realidad virtual aparecían en el navegador o en visores compatibles con RV.
La Web envolvente implica experiencias de mundos virtuales alojadas a través del navegador. Esto abarca experiencias de realidad virtual (RV) completas que aparecen en el navegador o en visores compatibles con RV, como Daydream de Google, Oculus Rift, Samsung Gear VR, HTC Vive y visores de Windows Mixed Reality, así como experiencias de realidad aumentada desarrolladas para dispositivos móviles compatibles con RA.
Si bien usamos dos términos para describir las experiencias envolventes, se deben considerar como un espectro que va desde la realidad completa hasta un entorno de RA completamente envolvente, con varios niveles de RA en el medio.
Estos son algunos ejemplos de experiencias envolventes:
- Videos envolventes en 360°
- Videos tradicionales en 2D (o 3D) presentados en entornos envolventes
- Visualizaciones de datos
- Compras en casa
- Arte
- Algo genial que nadie haya pensado antes
¿Cómo llego hasta ahí?
La Web inmersiva lleva casi un año disponible en forma embrionaria. Esto se hizo a través de la API de WebVR 1.1, que estuvo disponible en una prueba de origen desde Chrome 62. Esa API también es compatible con Firefox y Edge, así como con un polyfill para Safari.
Pero es hora de seguir adelante.
La prueba de origen finalizó el 24 de julio de 2018, y la especificación se reemplazó por la API de WebXR Device y una nueva prueba de origen.
¿Qué sucedió con WebVR 1.1?
Aprendimos mucho de WebVR 1.1, pero con el tiempo, quedó claro que se necesitaban algunos cambios importantes para admitir los tipos de aplicaciones que los desarrolladores quieren compilar. La lista completa de lecciones aprendidas es demasiado larga para explicarla aquí, pero incluye problemas como que la API esté vinculada de forma explícita al subproceso principal de JavaScript, demasiados oportunidades para que los desarrolladores configuren parámetros de configuración claramente incorrectos, y usos comunes, como que la ventana mágica sea un efecto secundario en lugar de una función intencional. (La ventana mágica es una técnica para ver contenido envolvente sin visores, en la que la app renderiza una sola vista según el sensor de orientación del dispositivo).
El nuevo diseño facilita implementaciones más simples y grandes mejoras de rendimiento. Al mismo tiempo, surgieron la RA y otros casos de uso, y se volvió importante que la API fuera extensible para admitirlos en el futuro.
La API de WebXR Device se diseñó y nombró teniendo en cuenta estos casos de uso expandidos y proporciona una mejor opción para el futuro. Los implementadores de WebVR se comprometieron a migrar a la API de WebXR Device.
¿Qué es la API de WebXR Device?
Al igual que la especificación de WebVR anterior, la API de WebXR Device es un producto del Immersive Web Community Group, que cuenta con colaboradores de Google, Microsoft, Mozilla y otros. La "X en XR se diseñó como una especie de variable algebraica que representa cualquier cosa en el espectro de experiencias envolventes. Está disponible en la prueba de origen mencionada anteriormente, así como a través de un polyfill.
Cuando se publicó este artículo originalmente durante el período de la versión beta de Chrome 67, solo se habilitaron las funciones de RV. La realidad aumentada llegó a Chrome 69. Obtén información al respecto en Realidad aumentada para la Web.
Esta nueva API tiene más funciones de las que puedo explicar en un artículo como este. Quiero darte suficiente información para que comiences a comprender las muestras de WebXR. Puedes encontrar más información en la explicación original y en nuestra Guía para usuarios pioneros de la Web Imersiva. Ampliaré la segunda a medida que avance la prueba de origen. No dudes en abrir problemas o enviar solicitudes de extracción.
En este artículo, hablaré sobre cómo iniciar, detener y ejecutar una sesión de XR, además de algunos conceptos básicos sobre el procesamiento de entradas.
No explicaré cómo dibujar contenido de RA/RV en la pantalla. La API de WebXR Device no proporciona funciones de renderización de imágenes. Eso depende de ti. El dibujo se realiza con las APIs de WebGL. Puedes hacerlo si tienes mucha ambición. Sin embargo, te recomendamos que uses un framework. Los ejemplos de la Web inmersiva usan uno que se creó solo para las demostraciones, llamado Cottontail. Three.js admite WebXR desde mayo. No he escuchado nada sobre A-Frame.
Cómo iniciar y ejecutar una app
El proceso básico es el siguiente:
- Solicita un dispositivo de realidad extendida.
- Si está disponible, solicita una sesión de XR. Si quieres que el usuario coloque su teléfono en auriculares, se denomina sesión envolvente y requiere un gesto del usuario para ingresar.
- Usa la sesión para ejecutar un bucle de renderización que proporcione 60 fotogramas de imagen por segundo. Dibuja el contenido adecuado en la pantalla en cada fotograma.
- Ejecuta el bucle de renderización hasta que el usuario decida salir.
- Finaliza la sesión de XR.
Veamos esto con más detalle y, luego, incluiremos un código. No podrás ejecutar una app con lo que te mostraré a continuación. Pero, una vez más, esto es solo para darte una idea.
Cómo solicitar un dispositivo de XR
Aquí, reconocerás el código de detección de características estándar. Puedes unir esto en una función llamada checkForXR()
.
Si no usas una sesión envolvente, puedes omitir la publicidad de la funcionalidad y obtener un gesto del usuario para ir directamente a solicitar una sesión. Una sesión envolvente es aquella que requiere auriculares. Una sesión no envolvente solo muestra contenido en la pantalla del dispositivo. La primera es lo que la mayoría de las personas piensan cuando se hace referencia a la realidad virtual o a la realidad aumentada. Esta última se denomina a veces "ventana mágica".
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.");
}
Cómo solicitar una sesión de XR
Ahora que tenemos nuestro dispositivo y nuestro gesto del usuario, es hora de obtener una sesión. Para crear una sesión, el navegador necesita un lienzo en el que dibujar.
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
})
Ejecuta el bucle de renderización
El código de este paso requiere un poco de desenredo. Para desenredarlo, te voy a decir muchas palabras. Si quieres echar un vistazo al código final, ve al final para verlo rápidamente y, luego, vuelve para obtener la explicación completa. Es posible que no puedas inferir mucho.
El proceso básico de un bucle de renderización es el siguiente:
- Solicita un fotograma de animación.
- Consulta la posición del dispositivo.
- Dibuja contenido en la posición del dispositivo según su posición.
- Realiza el trabajo necesario para los dispositivos de entrada.
- Repite 60 veces por segundo hasta que el usuario decida salir.
Cómo solicitar un marco de presentación
La palabra "marco" tiene varios significados en un contexto de XR web. El primero es el marco de referencia, que define desde dónde se calcula el origen del sistema de coordenadas y qué sucede con ese origen cuando el dispositivo se mueve. (¿la vista permanece igual cuando el usuario se mueve o cambia como lo haría en la vida real?).
El segundo tipo de marco es el marco de presentación, representado por un objeto XRFrame
. Este objeto contiene la información necesaria para renderizar un solo fotograma de una escena de RA/VR en el dispositivo. Esto es un poco confuso porque se recupera un marco de presentación llamando a requestAnimationFrame()
.
Esto lo hace compatible con window.requestAnimationFrame()
.
Antes de darte más información, te ofreceré un código. En el siguiente ejemplo, se muestra cómo se inicia y se mantiene el bucle de renderización. Observa el uso doble del marco de palabras. Observa la llamada recursiva a requestAnimationFrame()
. Se llamará a esta función 60 veces por segundo.
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);
}
});
Posiciones
Antes de dibujar algo en la pantalla, debes saber hacia dónde apunta el dispositivo de visualización y debes tener acceso a la pantalla. En general, la posición y orientación de un objeto en la RA/VR se denomina pose. Tanto los visores como los dispositivos de entrada tienen una pose. (Más adelante, hablaré de los dispositivos de entrada). Las posiciones del visor y del dispositivo de entrada se definen como una matriz de 4 por 4 almacenada en un Float32Array
en orden mayor de columna. Para obtener la pose del usuario, llama a XRFrame.getDevicePose()
en el objeto de fotograma de animación actual.
Siempre prueba para ver si recibiste una pose. Si algo sale mal, no querrás dibujar en la pantalla.
let pose = xrFrame.getDevicePose(xrFrameOfRef);
if (pose) {
// Draw something to the screen.
}
Vistas
Después de verificar la pose, es hora de dibujar algo. El objeto al que dibujas se llama vista (XRView
). Aquí es donde el tipo de sesión se vuelve importante. Las vistas se recuperan del objeto XRFrame
como un array. Si estás en una sesión no inmersiva, el array tiene una vista. Si estás en una sesión immersiva, el array tiene dos, uno para cada ojo.
for (let view of xrFrame.views) {
// Draw something to the screen.
}
Esta es una diferencia importante entre WebXR y otros sistemas envolventes. Si bien puede parecer inútil iterar a través de una vista, hacerlo te permite tener una sola ruta de renderización para una variedad de dispositivos.
Todo el bucle de renderización
Si junto todo esto, obtengo el siguiente código. Dejé un marcador de posición para los dispositivos de entrada, que analizaré en una sección posterior.
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);
}
}
Finaliza la sesión de XR
Una sesión de XR puede finalizar por varios motivos, incluido el hecho de que tu propio código la finalice a través de una llamada a XRSession.end()
. Otras causas incluyen que los auriculares estén desconectados o que otra aplicación tome el control de ellos. Es por eso que una aplicación que se comporta bien debe supervisar el evento de finalización y, cuando se produzca, descartar la sesión y los objetos del renderizador. Una vez finalizada, una sesión de XR no se puede reanudar.
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);
}
¿Cómo funciona la interacción?
Al igual que con el ciclo de vida de la aplicación, solo te daré una idea de cómo interactuar con objetos en RA o RV.
La API de WebXR Device adopta un enfoque de "apuntar y hacer clic" para la entrada del usuario. Con este enfoque, cada fuente de entrada tiene un rayo de puntero definido para indicar hacia dónde apunta un dispositivo de entrada y eventos para indicar cuándo se seleccionó algo.
Tu app dibuja el rayo del puntero y muestra hacia dónde está dirigido. Cuando el usuario hace clic en el dispositivo de entrada, se activan los eventos select
, selectStart
y selectEnd
, específicamente. Tu app determina en qué se hizo clic y responde de manera adecuada.
El dispositivo de entrada y el rayo del puntero
Para los usuarios, el rayo del puntero es solo una línea tenue entre el controlador y cualquier cosa a la que apunten. Sin embargo, tu app debe dibujarlo. Eso significa obtener la posición del dispositivo de entrada y dibujar una línea desde su ubicación hasta un objeto en el espacio de RA/VR. Ese proceso se ve de la siguiente manera:
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.
}
}
Esta es una versión reducida del ejemplo de seguimiento de entradas del grupo de la comunidad de Web inmersiva. Al igual que con la renderización de fotogramas, puedes dibujar el rayo del puntero y el dispositivo. Como se mencionó anteriormente, este código se debe ejecutar como parte del bucle de renderización.
Cómo seleccionar elementos en el espacio virtual
Simplemente apuntar a elementos en la RA/RV es bastante inútil. Para hacer algo útil,
los usuarios deben poder seleccionar elementos. La API de WebXR Device proporciona tres eventos para responder a las interacciones del usuario: select
, selectStart
y selectEnd
. Tienen un inconveniente que no esperaba: solo te indican que se hizo clic en un dispositivo de entrada. No te indican en qué elemento del entorno se hizo clic. Los controladores de eventos se agregan al objeto XRSession
y deben agregarse
en cuanto estén 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);
});
Este código se basa en un ejemplo de selección de entrada, en caso de que quieras obtener más contexto.
Para averiguar en qué se hizo clic, usa una pose. (¿Te sorprende? No lo creo.) Los detalles son específicos de tu app o cualquier framework que uses y, por lo tanto, exceden el alcance de este artículo. El enfoque de Cottontail se encuentra en el ejemplo de selección de entrada.
function onSelect(ev) {
let inputPose = ev.frame.getInputPose(ev.inputSource, xrFrameOfRef);
if (!inputPose) {
return;
}
if (inputPose.pointerMatrix) {
// Figure out what was clicked and respond.
}
}
Conclusión: De cara al futuro
Como dije antes, se espera que la realidad aumentada esté disponible en Chrome 69 (Canary en algún momento de junio de 2018). Sin embargo, te recomiendo que pruebes lo que tenemos hasta ahora. Necesitamos comentarios para mejorarlo. Para seguir su progreso, consulta WebXR Hit Test en ChromeStatus.com. También puedes seguir las anclas de WebXR, que mejorarán el seguimiento de poses.