Confira algumas noções básicas que vão preparar você para diversas experiências imersivas: realidade virtual, realidade aumentada e muito mais.
As experiências imersivas chegaram à Web no Chrome 79. A API WebXR Device oferece a realidade virtual trazida pela realidade virtual, enquanto o suporte à realidade aumentada chega no Chrome 81. Enquanto uma atualização da API GamePad estende 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 o navegador Helio da Magic Leap, entre outros.
Este artigo é o primeiro de uma série sobre a Web imersiva. Esta parte aborda como configurar um aplicativo WebXR básico e como entrar e sair de uma sessão de XR. Os próximos artigos vão abordar o loop de frames (o principal recurso da experiência do WebXR), as especificidades da realidade aumentada e a API WebXR Hit Test, uma maneira de detectar superfícies em uma sessão de RA. A menos que indicado de outra forma, tudo o que abordo neste e nos próximos artigos se aplica igualmente à RA e à RV.
O que é a Web imersiva?
Embora usemos dois termos para descrever experiências imersivas (realidade aumentada e realidade virtual), muitas pessoas os consideram em um espectro que vai da realidade completa à completamente virtual, com graus de imersão entre eles. O "X" em XR tem a intenção de refletir esse pensamento sendo uma espécie de variável algébrica que representa qualquer coisa no espectro de experiências imersivas.
Estes são 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
- Confira os produtos na sua casa antes de comprá-los
- Arte imersiva
- Algo legal que ninguém pensou ainda
Conceitos e uso
Vou explicar alguns conceitos básicos do uso da API WebXR Device. Se você precisar de mais detalhes do que os que eu forneci, confira os exemplos de WebXR do Grupo de Trabalho da Web imersiva ou os materiais de referência do MDN. Se você já conhece as versões anteriores da API WebXR Device, leia todo este material. Houve mudanças.
O código neste artigo é baseado no exemplo barebones do Immersive Web Working Group (demonstração, fonte), mas foi editado para maior clareza e simplicidade.
Parte da criação da especificação do WebXR foi desenvolver medidas de segurança e privacidade para proteger os usuários. Consequentemente, as implementações precisam aderir a certos requisitos. Uma página da Web ou um app precisam estar ativos e focados antes de solicitar qualquer informação sensível do usuário. As páginas da Web ou os apps precisam ser veiculados por HTTPS. A API em si foi projetada para proteger as informações recebidas de sensores e câmeras, necessárias para funcionar.
Solicitar uma sessão
Para entrar em uma sessão de XR, é necessário um gesto do usuário. Para isso, use a detecção
de recursos para testar XRSystem
(usando navigator.xr
) e fazer uma chamada para
XRSystem.isSessionSupported()
. Nas versões 79 e 80 do Chrome, o
objeto XRSystem
era chamado de XR
.
No exemplo abaixo, 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 in-line serve para apresentar
conteúdo em HTML e é usada principalmente para teasers. O exemplo de sessão de RA
imersiva
demonstra isso. Vou explicar isso em um artigo posterior.
Depois de saber que as sessões de realidade virtual são compatíveis, ativei um botão que permite que eu colete 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 neste código. Ela é movida de navigator
para xr
para
uma instância de XRSession
. Nas versões anteriores da API, um script precisava solicitar um
dispositivo antes de solicitar uma sessão. Agora, o dispositivo é adquirido implicitamente.
Insira uma sessão
Depois de iniciar uma sessão, preciso iniciá-la e acessá-la. Mas primeiro, preciso
configurar algumas coisas. Uma sessão precisa de um manipulador de eventos onend
para que o aplicativo ou a página da Web possa ser redefinido quando o usuário sair.
Também vou precisar de um elemento <canvas>
para desenhar minha cena. Ele precisa ser um
WebGLRenderingContext
ou
WebGL2RenderingContext compatível com XR.
Todas as exibições são feitas usando esses elementos ou um framework baseado em WebGL, como
Three.js.
Agora que tenho um lugar para desenhar, preciso de uma fonte de conteúdo para desenhar
nele. Para isso, criei uma instância de XRWebGLLayer
. Eu o associo à
tela chamando XRSession.updateRenderState()
.
Quando estou em uma sessão, preciso de uma maneira de determinar onde as coisas estão na realidade
virtual. Vou precisar 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 é esperado que ele se mova. Há outros tipos de espaços de
referência,
mas esse é um tópico mais complicado do que posso abordar aqui. Eu salvo o espaço de referência
em uma variável porque vou precisar dele quando eu 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 frame é um loop infinito controlado pelo user agent em que o conteúdo é exibido repetidamente na tela. O conteúdo é exibido em blocos discretos chamados frames. A sucessão de frames cria a ilusão de movimento. Para aplicativos de RV, os frames por segundo podem variar de 60 a 144. A RA para Android é executada a 30 quadros por segundo. Seu código não deve assumir nenhuma taxa de quadros específica.
O processo básico do loop de frame é:
- Ligue para a
XRSession.requestAnimationFrame()
. Em resposta, o agente do usuário invoca oXRFrameRequestCallback
, que é definido por você. - Dentro da função de callback:
- Ligue para
XRSession.requestAnimationFrame()
novamente. - Mostre a pose do espectador.
- Transmita ('bind') o
WebGLFramebuffer
doXRWebGLLayer
para oWebGLRenderingContext
. - Itere cada objeto
XRView
, recuperando oXRViewport
doXRWebGLLayer
e transmitindo-o aoWebGLRenderingContext
. - Desenhe algo no framebuffer.
- Ligue para
O restante deste artigo descreve a etapa 1 e parte da etapa 2, a configuração
e a chamada da 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: um
DOMHighResTimeStamp
e uma instância XRFrame
. O objeto XRFrame
fornece
as informações necessárias para renderizar um único frame na tela. 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 lá, vou mostrar como encerrar uma sessão.
Encerrar a sessão
Uma sessão imersiva pode ser encerrada por vários motivos, incluindo o encerramento pelo seu próprio
código por uma chamada para XRSession.end()
. Outras causas incluem o fone de ouvido ser
desconectado ou outro app assumindo o controle dele. É 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. Uma sessão imersiva encerrada não pode ser
retomada. Para entrar novamente na experiência imersiva, meu app precisa iniciar uma nova
sessão.
Você se lembra que, em Como entrar em uma sessão, 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 que o usuário entre 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 de RA ou XR da Web. Espero ter fornecido informações suficientes para que você entenda o código e comece a fazer experimentos. No próximo artigo, vou explicar o loop de frames, que é onde o conteúdo é exibido na tela.
Foto de JESHOOTS.COM no Unsplash