Confira alguns princípios básicos para prepará-lo para um espectro de experiências imersivas: realidade virtual, realidade aumentada e muito mais.
As experiências imersivas chegaram à Web no Chrome 79. A API WebXR Device traz a realidade virtual e o suporte à realidade aumentada chega ao Chrome 81. Embora uma atualização da API GamePad estenda o uso avançado de controles para RV. Outros navegadores serão compatíveis com essas especificações em breve, incluindo Firefox Reality, Oculus Browser, Edge e Helio do Magic Leap, entre outros.
Este artigo dá início a uma série sobre a Web imersiva. Esta parcela aborda a configuração de um aplicativo WebXR básico, bem como a entrada e a saída de uma sessão XR. Os próximos artigos vão abordar o loop de frames (o ponto de trabalho da experiência do WebXR), os detalhes da realidade aumentada e a API WebXR Hit Test, um meio de detecção de superfícies em uma sessão de RA. A menos que indicado de outra forma, tudo o que for abordado neste artigo e nos próximos artigos se aplica igualmente a RA e RV.
O que é a Web imersiva?
Embora usemos dois termos para descrever experiências imersivas (realidade aumentada e realidade virtual), muitos pensam nelas em um espectro da realidade completa até completamente virtual, com graus de imersão no meio. O "X" em XR reflete esse pensamento como uma espécie de variável algébrica que representa qualquer coisa no espectro de experiências imersivas.
Confira alguns exemplos de experiências imersivas:
- Jogos
- Vídeos em 360°
- Vídeos tradicionais em 2D (ou 3D) apresentados em ambientes imersivos
- Compra de imóveis
- Conferir os produtos na sua casa antes de comprá-los
- Arte imersiva
- Algo legal que ninguém pensou ainda
Conceitos e uso
Vou explicar os fundamentos do uso da API WebXR Device. Se você precisar de mais detalhes do que eu forneci, confira os exemplos do WebXR do Immersive Web Working Group ou os materiais de referência em crescimento da MDN (links em inglês). Caso você já conheça as versões anteriores da API WebXR Device, confira todo esse material. Houve mudanças.
O código deste artigo é baseado na amostra de barebones do Immersive Web Working Group (demonstração, fonte), mas foi editado para maior clareza e simplicidade.
Parte da criação da especificação WebXR foi desenvolver as medidas de segurança e privacidade para proteger os usuários. Consequentemente, as implementações precisam aderir a determinados requisitos. Uma página da Web ou um app precisa estar ativo e focado antes de solicitar informações sensíveis ao visualizador. As páginas da Web ou os apps precisam ser exibidos por HTTPS. A API em si foi projetada para proteger informações recebidas de sensores e câmeras, necessárias para o funcionamento.
Solicitar uma sessão
A entrada em uma sessão XR requer um gesto do usuário. Para isso, use a detecção de
recursos para testar XRSystem
(via navigator.xr
) e faça uma chamada para
XRSystem.isSessionSupported()
. Lembre-se de que, nas versões 79 e 80 do Chrome, o objeto
XRSystem
era chamado de XR
.
No exemplo abaixo, eu indiquei que quero uma sessão de realidade virtual com o tipo de sessão 'immersive-vr'
. Os outros tipos de sessão são 'immersive-ar'
e 'inline'
. Uma sessão inline destina-se à apresentação de conteúdo
em HTML e é usada principalmente para conteúdo de teaser. O exemplo de Sessão
de RA imersiva
(link em inglês) demonstra isso. Vou explicar isso em um artigo posterior.
Depois de saber que as sessões de realidade virtual têm suporte, ativo um botão que permite adquirir um gesto do usuário.
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
}
}
Depois de ativar o botão, espero por um evento de clique e solicito uma sessão.
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();
}
}
Observe a hierarquia de objetos nesse código. Ele muda de navigator
para xr
para
uma instância de XRSession
. Nas primeiras versões da API, um script precisava solicitar um
dispositivo antes de uma sessão. Agora, o dispositivo é adquirido implicitamente.
Insira uma sessão
Depois de receber uma sessão, preciso iniciá-la e inseri-la. Mas, primeiro, preciso
configurar algumas coisas. Uma sessão precisa de um manipulador de eventos onend
para que o app ou a página da Web possa ser redefinido quando o usuário sai.
Também vou precisar de um elemento <canvas>
para desenhar minha cena. Ele precisa ser um
WebGLRenderingContext
ou
WebGL2RenderingContext compatível com XR.
Todo o desenho é feito usando esses elementos ou um framework baseado em WebGL, como o
Three.js.
Agora que tenho um lugar para desenhar, preciso de uma fonte de conteúdo
para desenhar nele. Para isso, crio uma instância do XRWebGLLayer
. Eu o associo à
tela chamando XRSession.updateRenderState()
.
Quando estou em uma sessão, preciso de uma forma de determinar onde as coisas estão na realidade
virtual. Preciso de um espaço de referência. Um espaço de referência 'local-floor'
é aquele
em que a origem está localizada perto do visualizador, e o eixo y é 0 no nível do andar
e não se espera que ele se mova. Há outros tipos de espaços de
referência,
mas esse é um tópico mais complicado do que eu posso abordar aqui. Salvo o espaço de referência em uma variável porque vou precisar dele quando desenhar na tela.
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);
});
}
Depois de receber um espaço de referência, chamo XRSession.requestAnimationFrame()
.
Esse é o início da apresentação de conteúdo virtual, que é feito no loop
de frames.
Executar um loop de frame
O loop de frames é um loop infinito controlado pelo user agent em que o conteúdo é desenhado repetidamente na tela. O conteúdo é desenhado em blocos discretos chamados de frames. A sucessão de frames cria a ilusão de movimento. Para aplicativos de RV, os quadros por segundo podem variar de 60 a 144. A RA no Android é executada a 30 quadros por segundo. Seu código não deve presumir nenhum frame rate específico.
O processo básico para o loop de frames é:
- Chame
XRSession.requestAnimationFrame()
. Em resposta, o user agent invoca oXRFrameRequestCallback
, que é definido por você. - Dentro da função de callback:
- Chame
XRSession.requestAnimationFrame()
de novo. - Identifique a pose do espectador.
- Transmita ("bind") o
WebGLFramebuffer
doXRWebGLLayer
para oWebGLRenderingContext
. - Itere em cada objeto
XRView
, recuperando oXRViewport
doXRWebGLLayer
e transmitindo-o para oWebGLRenderingContext
. - Desenhe algo no framebuffer.
- Chame
O restante deste artigo descreve as etapas 1 e parte da etapa 2, como configurar
e chamar o XRFrameRequestCallback
. Os itens restantes da etapa 2 são
abordados na parte II.
O XRFrameRequestCallback
O XRFrameRequestCallback
é definido por você. Ele usa dois parâmetros: uma
DOMHighResTimeStamp
e uma instância de XRFrame
. O objeto XRFrame
fornece
as informações necessárias para renderizar um único frame para a exibição. O
argumento DOMHighResTimeStamp
é para uso futuro.
Antes de fazer qualquer outra coisa, vou solicitar o próximo frame de animação. Como mencionado anteriormente, o tempo dos frames é determinado pelo user agent com base no hardware. Solicitar o próximo frame primeiro garante que o loop de frames continue se algo durante o callback gerar um erro.
function onXRFrame(hrTime, xrFrame) {
let xrSession = xrFrame.session;
xrSession.requestAnimationFrame(onXRFrame);
// Render a frame.
}
Neste ponto, é hora de desenhar algo para o espectador. Essa é uma discussão para a parte II. Antes de ir até lá, vou mostrar como encerrar uma sessão.
Encerrar a sessão
Uma sessão imersiva pode ser encerrada por vários motivos, incluindo ser encerrada com seu próprio
código usando uma chamada para XRSession.end()
. Outras causas incluem a desconexão do fone de ouvido
ou outro aplicativo assumindo o controle. É por isso que um
aplicativo bem comportado precisa monitorar o evento end
. Quando isso ocorrer, descarte
a sessão e os objetos de renderização relacionados. Não é possível retomar uma sessão imersiva
finalizada. Para voltar à experiência imersiva, meu app precisa iniciar uma nova
sessão.
Lembre-se de Como entrar em uma sessão que, durante a configuração, adicionei
um manipulador de eventos onend
.
function onSessionStarted(xrSession) {
xrSession.addEventListener('end', onSessionEnded);
// More setup…
}
No manipulador de eventos, restaure o estado do app antes de o usuário entrar em uma sessão.
function onSessionEnded(event) {
xrSession = null;
xrButton.textContent = 'Enter VR';
}
Conclusão
Não expliquei tudo o que você precisa para criar um aplicativo Web XR ou RA. Espero ter dado a você o suficiente para começar a entender o código por conta própria e para começar a experimentar. No próximo artigo, vou explicar o loop de frames, que é onde o conteúdo é desenhado na tela.
Foto de JESHOOTS.COM no Unsplash