flowchart TD
A[Um passo a frente<br/>com o visor no rosto] --> B[Ouvido interno e musculos<br/>registram o avanco]
A --> C[Olhos registram<br/>cena imovel]
B --> D{Dois relatos<br/>sobre o mesmo evento}
C --> D
D --> E[Nenhum arbitro<br/>decide qual mente]
E --> F[Mal-estar<br/>sem defeito de imagem]
1 Dispositivos, rastreamento e graus de liberdade
Antes de desenhar qualquer coisa, o aparelho precisa responder onde ele está — e a resposta errada dá enjoo em quem está de visor.
Este capítulo termina com um programa que não desenha nada, e é esse o argumento dele. O que fica são três coisas: o vocabulário que descreve quanto movimento um aparelho acompanha, o mecanismo pelo qual ele descobre onde está sem ajuda de fora, e as condições em que esse mecanismo falha. Leia com um aparelho concreto em mente — o celular do seu bolso serve — e pergunte a cada seção o que ele responderia.
1.1 Um passo à frente, e a imagem fica onde estava
Seis números descrevem qualquer objeto sólido no espaço, e um aparelho que acompanha só três deles produz mal-estar em minutos.
Vista um visor barato e dê um passo à frente. Seu corpo avança meio metro. Os canais semicirculares do ouvido interno registram a aceleração desse avanço e avisam ao cérebro que houve deslocamento. Seus olhos, dentro do visor, veem uma cena que não se aproximou de nada. Duas informações incompatíveis sobre o mesmo evento, e nenhum árbitro para decidir qual delas mente.
O desconforto que sai daí não se conserta com mais quadros por segundo. Ele também não melhora com textura mais caprichada nem com iluminação melhor. A causa é um sensor que não está dentro do aparelho, e software nenhum alcança isso. JERALD trata o mecanismo em detalhe, e a literatura de fatores humanos o documenta há décadas.
O problema tem data bem anterior a qualquer visor barato. Em 1968, Ivan Sutherland montou o primeiro visor acoplado à cabeça, e ele pesava demais para ser usado como se usa um chapéu. A saída foi pendurá-lo no teto do laboratório por um braço mecânico articulado, que rendeu ao conjunto o apelido de espada de Dâmocles, pela peça suspensa sobre a cabeça de quem se sentava embaixo. O que ele exibia eram arestas de arame, sem cor e sem superfície.
Acontece que o braço não estava ali só para segurar peso. Cada junta articulada informava um ângulo, e da combinação dos ângulos saía onde a cabeça estava e para onde ela apontava. O primeiro visor da área já respondia à pergunta de posição, e respondia com engenharia mecânica. Quase sessenta anos depois, um visor de três graus não responde a ela. Em compensação, cabe na mochila.
1.1.1 Seis maneiras de mexer um livro
Pegue um livro fechado e segure-o à sua frente. Dá para movê-lo à esquerda e à direita, para cima e para baixo, para perto e para longe do rosto. São três deslocamentos independentes, no sentido de que executar um não obriga a executar os outros. Agora, sem tirá-lo do lugar, gire-o como um volante, como uma porta e como uma pizza sobre a mesa.
Acabou. Não existe uma sétima maneira, e o livro na sua mão comprova isso em dez segundos. Qualquer movimento que você faça com ele é combinação dessas seis, e a afirmação é geométrica em vez de convencional. A palavra rígido é o que faz a conta fechar: o livro não amassa nem entorta.
Os três giros herdaram nomes da navegação, e a bibliografia inteira os usa. Girar como um volante é rolagem. Girar como quem diz sim com a cabeça é arfagem. Girar como quem diz não é guinada. Os deslocamentos não ganharam nomes tão pitorescos, e costumam ser chamados apenas de translação em cada eixo.
Complementar — grau de liberdade e pose
Um grau de liberdade é uma direção de movimento independente das demais: a variação nela não é determinada pelas variações nas outras. Um corpo rígido no espaço tridimensional tem seis, sendo três de translação e três de rotação. A pose é o par formado pela rotação e pela translação que levam esse corpo da origem combinada até onde ele está agora.
O menor exemplo concreto cabe numa frase. A pose de uma xícara sobre a mesa é onde ela está no tampo, mais para que lado a alça aponta. Note o que a definição não exige. Ela não pede que o corpo seja pequeno. Não pede que ele se mova devagar. E não diz uma palavra sobre a precisão com que a pose é conhecida. Precisão é outro assunto, e a pose continua sendo pose mesmo quando quem a estima erra feio.
flowchart LR
subgraph T[Translacao: onde o corpo esta]
T1[deslocamento<br/>no eixo lateral]
T2[deslocamento<br/>no eixo vertical]
T3[deslocamento<br/>no eixo frontal]
end
subgraph R[Rotacao: para onde ele aponta]
R1[giro em torno<br/>do eixo lateral]
R2[giro em torno<br/>do eixo vertical]
R3[giro em torno<br/>do eixo frontal]
end
R --> A[Aparelho de tres graus:<br/>estima so a metade de cima]
T --> B[Aparelho de seis graus:<br/>estima as duas metades]
R --> B
1.1.2 A metade barata e a metade cara
Por que um fabricante deixaria metade dos graus de fora? O motivo é de custo antes de ser técnico. Rotação se mede com sensores inerciais pequenos e baratos, os mesmos que qualquer celular carrega há anos. A medida se estabiliza em fração de segundo. Essa é a metade barata, e ela vem quase de graça em qualquer aparelho.
Translação é outra história. Um sensor inercial mede aceleração, e da aceleração até a posição são duas integrações seguidas. Cada uma amplifica o erro da anterior, e o resultado desanda depressa: o aparelho passa a acreditar que desliza enquanto está parado. Medir deslocamento de forma confiável exige olhar para o mundo, o que significa câmera, processamento e bateria.
Daí sai uma exigência de projeto que atravessa todo o resto do livro. Um ambiente que não sabe quantos graus o aparelho acompanha acaba propondo a alguém um movimento que ele não segue. É questão de tempo. Isso não é curiosidade técnica de quem gosta de sensor. É pré-condição para não fazer mal a quem usa o que você construiu.
A explicação cobre menos do que parece, e esticá-la sai caro. Nem todo mal-estar em ambiente imersivo vem do desacordo entre canais sensoriais. Peso do equipamento, lentes mal ajustadas e cansaço visual produzem desconforto por outras vias, e a bibliografia os trata separadamente. O que se afirma aqui é mais estreito e mais firme. Este mecanismo específico decorre de rastrear menos graus do que o corpo executa. E não se corrige por software.
1.1.3 Do que se declarou ao que o aparelho responde
No capítulo anterior, ao separar imersão de presença e de registro, escrevemos duas declarações sobre o ambiente em construção: qual é o domínio dele e o que cada regime pretende fazer com o mundo de quem observa.
Uma dessas declarações dizia que o regime aumentado espera compor a imagem gerada sobre uma captura do ambiente real.
Repare no verbo. Espera.
Era afirmação escrita antes de qualquer aparelho ter sido consultado, e o valor dela estava exatamente em poder ser desmentida. Agora existe quem a desminta.
O aparelho responde, e ele pode discordar. Quando as duas coisas batem, a declaração sai confirmada e nada muda. Quando não batem, o ganho é maior: descobre-se que a declaração estava errada, e a descoberta vem da única entidade com autoridade para fazê-la.
A virada é essa. Até aqui o projeto afirmava. Daqui em diante ele pergunta e escuta.
E a consulta de suporte que já existia — este aparelho entra neste regime? — continua valendo inteira. O que se acrescenta agora é a consulta de recursos, a que só a sessão aberta responde.
1.2 Quem olha para quem
Há dois lugares possíveis para os sensores, e a escolha entre eles decide de que jeito o rastreamento quebra.
O braço de Sutherland pertence a uma família que ainda existe. Nela, a sala é instrumentada: equipamentos fixos, montados em posições conhecidas, observam o aparelho e calculam onde ele está. As juntas articuladas viraram meios ópticos, e o princípio geométrico ficou intacto desde 1968. A outra família inverte tudo, e põe os sensores dentro do próprio aparelho, olhando para fora.
A pergunta que os dois arranjos respondem é a mesma. Então por que a escolha entre eles importa? As respostas têm qualidades diferentes, falham de maneiras diferentes e cobram em colunas diferentes da conta. Confundir esses três aspectos é o que produz a escolha errada de equipamento em projeto real. E a escolha errada costuma aparecer só no dia da demonstração.
1.2.1 O que cada arranjo cobra
Comece pelo que o arranjo de dentro para fora dispensa, que é instalação. Tira-se o aparelho da caixa, veste-se, e ele funciona em qualquer sala. Não há equipamento a montar, alinhamento a conferir nem cabo atravessando o chão. Para um produto vendido a quem não é técnico, isso decide entre existir mercado e não existir.
A conta chega na palavra qualquer. Ele funciona em qualquer sala que ofereça o que ele precisa, e o que ele precisa é textura visual. Parede branca e lisa não tem canto algum a reconhecer, e luz fraca não dá o contraste necessário para separar um elemento do outro. Há ainda uma dependência fácil de esquecer e cara de descobrir tarde: o arranjo pressupõe que o ambiente fique parado.
Uma cortina balançando. Uma televisão ligada. Um grupo de pessoas circulando pela sala. O aparelho reconhece elementos que se movem por conta própria e conclui que quem se moveu foi ele, e então corrige uma posição que estava certa, guiado por uma referência que trocou de lugar sem avisar. O sintoma é a imagem deslizando sozinha, e a causa está do lado de fora do equipamento, num lugar onde nenhuma linha de código do ambiente alcança e nenhuma consulta de capacidade jamais vai reportar.
O arranjo de fora para dentro compra uma propriedade que a outra família não tem. A medida não é incremental: cada leitura é feita contra a referência fixa, e não contra a leitura anterior, então os erros não se acumulam. Um sistema desses roda horas sem derivar, porque não há de que derivar. Em troca, ele é da sala, e não do aparelho.
| Aspecto | De dentro para fora | De fora para dentro |
|---|---|---|
| Instalação | nenhuma | montagem e alinhamento prévios |
| Área útil | onde houver textura e luz | onde o equipamento fixo alcança |
| Acúmulo de erro | incremental, sujeito a deriva | absoluto, sem acúmulo |
| Falha típica | ambiente liso, luz baixa, cena que se move | linha de visão obstruída |
| Portabilidade | total | nenhuma |
flowchart TD
P{De onde parte<br/>a observacao?} -- Da sala fixa --> E[Infraestrutura externa]
P -- Do proprio aparelho --> S[Sensores embarcados]
E --> E1[Medida que nao deriva]
E --> E2[Fronteira nitida:<br/>fora da area, nao existe]
S --> S1[Depende da aparencia<br/>do ambiente]
S --> S2[Sem fronteira:<br/>fora da area, funciona pior]
E1 --> C[A pose chega igual<br/>nos dois casos]
S1 --> C
C --> D[A diferenca so aparece<br/>no dia da falha]
Duas linhas dessa tabela apontam para lados opostos, e isso não é coincidência. A ausência de acúmulo vem justamente de existir uma referência fixa, e uma referência fixa é o que impede o sistema de ser portátil. Sutherland fez essa troca em 1968, e ela continua de pé. Do lado do código, porém, os dois arranjos chegam idênticos. A pose vem com o mesmo formato e o mesmo significado. Saber qual deles está em uso só ajuda no dia em que ela deixa de vir.
1.3 O cartógrafo no escuro
Uma pessoa no escuro, com uma lanterna fraca, precisa desenhar a planta da casa enquanto anda por ela — e o visor faz literalmente isso.
Imagine alguém deixado numa casa desconhecida, sem luz, com uma lanterna fraca e a incumbência de desenhar a planta baixa. Essa pessoa não pode acender as lâmpadas, não recebeu mapa nenhum e não sabe por qual porta entrou. Precisa andar pelos cômodos e desenhar o que encontra, e o desenho é a única memória de onde ela já esteve.
É o problema exato que um aparelho de rastreamento autônomo enfrenta ao ser ligado numa sala nova. A formulação que resume o que ele faz vale para o resto deste livro. O aparelho desenha a planta da sala enquanto atravessa a sala, e corrige o desenho toda vez que reconhece um canto por onde já passou.
1.3.1 O círculo entre o mapa e a posição
Por que isso é difícil? A dificuldade não está em nenhuma das duas tarefas isoladas. Suponha que a pessoa da casa escura recebesse a planta pronta. Descobrir onde está seria comparar o que a lanterna ilumina com o desenho na mão. Se ela soubesse exatamente onde está a cada instante, desenhar a planta seria anotar o que vê a partir de cada posição conhecida.
O problema é que ela não tem nenhuma das duas. Para saber onde está, precisa do mapa. Para desenhar o mapa, precisa saber de onde está olhando. Cada uma das duas informações é pré-requisito da outra, e é isso que faz o problema ser interessante em vez de trivial.
A saída é estimar as duas juntas, aceitando que as duas fiquem aproximadas. A pessoa avança um passo, estima quanto avançou, anota o que vê a partir da posição estimada, e repete. O mapa cresce com erro embutido, e a posição carrega o mesmo erro, porque um foi calculado a partir do outro. É por isso que localização e mapeamento precisam da palavra simultâneos: as duas metades compõem um cálculo só.
O que sustenta a estimativa a cada passo é o deslocamento aparente do que a câmera vê. A quina de um móvel. A junção de duas paredes. A textura de um quadro. Cada um desses pontos muda de lugar na imagem conforme o aparelho se move. A geometria que liga esse deslocamento aparente ao movimento real é bem estabelecida. HARTLEY e ZISSERMAN a tratam em profundidade, assim como SZELISKI no contexto de visão computacional aplicada.
Só que todo passo estimado carrega erro, e os erros se somam. Depois de atravessar a casa inteira, a pessoa pode estar a metros de onde acredita estar, com uma planta deformada na mesma proporção. Esse acúmulo é a deriva mencionada na seção anterior, e sem correção ele torna o método inútil para sessões longas.
1.3.2 O canto reconhecido muda o passado
E quando o desenho deixa de bater com o que se vê? A correção vem de um evento específico. A pessoa entra num cômodo e reconhece uma quina que já tinha desenhado. Ela sabe onde essa quina está no desenho, e está vendo onde ela está agora em relação ao próprio corpo. Se as duas coisas discordam, ou o desenho está errado, ou a posição está errada — o que dá no mesmo, porque foram calculados juntos.
Aí vem a parte engenhosa. O sistema não corrige apenas a posição atual. Ele redistribui a discrepância por todo o percurso feito desde a última passagem por ali. O mapa inteiro se deforma para fazer as duas observações da mesma quina coincidirem. É como puxar uma corda frouxa pelas duas pontas: o ajuste acontece ao longo de todo o comprimento, não só onde a mão está.
flowchart LR
A[Observar o ambiente<br/>no quadro atual] --> B[Reconhecer pontos<br/>distintos na imagem]
B --> C[Estimar o movimento<br/>desde o quadro anterior]
C --> D[Atualizar a posicao<br/>estimada de quem observa]
D --> E[Acrescentar ao mapa<br/>os pontos ainda nao vistos]
E --> F{Algum ponto ja<br/>estava no mapa?}
F -- nao --> A
F -- sim --> G[Redistribuir o erro<br/>acumulado no percurso]
G --> A
Duas consequências saem daí, e quem usa o aparelho percebe as duas. A qualidade do rastreamento melhora conforme a pessoa circula pelo mesmo espaço, porque cada reencontro é uma chance de correção. E a primeira travessia de um espaço novo é sempre a pior, já que não há nada a reconhecer ainda. Quem monta uma demonstração numa sala em que nunca entrou está escolhendo o pior momento possível.
A correção diz algo sobre a natureza do que o aparelho entrega, e esse algo contraria o que se espera de um sensor. A posição informada num instante qualquer não tem o estatuto de uma medida de régua. É a melhor estimativa disponível ali, sujeita a revisão retroativa quando informação nova chegar. O aparelho pode, literalmente, mudar de ideia sobre onde você esteve.
Isso atrapalha quem espera de um sensor o comportamento de um relógio. Duas leituras feitas no mesmo lugar físico, em momentos diferentes da sessão, podem devolver coordenadas diferentes. Nenhuma das duas está errada — a origem foi reposicionada entre elas. Um objeto virtual que guardasse apenas as coordenadas numéricas de onde foi deixado apareceria deslocado depois de uma correção grande.
É por isso que existe a âncora, e aqui ela deixa de ser item de catálogo. Ancorar um objeto não é anotar as coordenadas dele. É pedir ao aparelho que mantenha aquele objeto preso a um ponto do mapa. E que ele atualize as coordenadas sozinho toda vez que o mapa for corrigido. A âncora sobrevive à correção; a coordenada guardada à mão, não.
Há ainda uma assimetria temporal no mecanismo, e ela explica um comportamento que costuma ser atribuído a defeito. A correção redistribui o erro pelo percurso já feito, e portanto melhora a coerência do que já foi mapeado. Ela não melhora a estimativa do próximo passo, que continua tão incerta quanto era. O rastreamento fica mais confiável sobre o espaço conhecido, e não fica mais preciso ao avançar para o desconhecido.
Nada disso é chamada de função sua. O mapa é construído pelo sistema do aparelho, num processo a que o ambiente não tem acesso. O que a sessão entrega são consequências do mapa, e são quatro. A pose de quem observa. O resultado de lançar um raio contra as superfícies reais reconhecidas. Os planos identificados no ambiente. E a âncora corrigida. Um aparelho que não concede nenhuma das quatro está declarando, sem dizer a palavra, que não tem mapa algum a oferecer.
Uma figura com prazo de validade. O cartógrafo no escuro descreve bem o que acontece quando o aparelho precisa descobrir o ambiente sozinho. Ela vai deixar de valer mais adiante neste livro, no ponto em que o registro passa a se apoiar num padrão impresso conhecido de antemão. Ali não existe planta a desenhar nem canto a reconhecer. Existe um gabarito que o sistema já sabia como era antes de a câmera ser ligada. Quando chegarmos lá, vou dizer que a figura acabou.
1.3.3 Três maneiras de o mapa se perder
Se todo o edifício se apoia em reconhecer pontos distintos no que a câmera vê, o que acontece quando não há pontos distintos a reconhecer? O cartógrafo com a lanterna apagada não desenha nada, e o aparelho diante da parede branca está exatamente nessa situação. As condições que derrubam o rastreamento saem do mecanismo, e são três.
A primeira é a superfície sem textura. Parede recém-pintada, cortina lisa, piso monocromático: nada ali constitui um ponto que possa ser reconhecido de novo no quadro seguinte. Uma região uniforme deslocada continua parecendo a mesma região uniforme. O sintoma ajuda no diagnóstico. Quem usa vira o rosto para a parede lisa e a posição começa a derivar. Ao girar de volta para o lado do móvel, ela salta para o lugar certo.
A segunda é a iluminação pobre, e ela pede uma distinção que costuma passar batido. O que atrapalha é a ausência de contraste, e escuridão é só uma das formas de produzi-la. Uma sala com pouca luz uniforme é pior para o rastreamento do que uma sala escura com uma janela clara ao fundo. A segunda ainda oferece uma fronteira nítida. O sensor precisa de diferença, não de brilho.
A terceira é o movimento brusco, e o mecanismo dela é óptico. Uma câmera integra luz durante um intervalo para formar cada quadro. Se o aparelho gira depressa nesse intervalo, o ponto distinto se espalha por vários lugares da imagem e deixa de aparecer nítido em um só. O canto some entre um quadro e o seguinte. Girar a cabeça rapidamente é, para o rastreamento, o mesmo que fechar os olhos por um instante.
Uma quarta condição não pertence à lista, e nomeá-la evita confusão. A cena que se move por conta própria não impede o reconhecimento: ela produz reconhecimentos falsos. Por isso o sintoma é outro — em vez de derivar por falta de informação, o aparelho se move por causa de informação errada.
Ausência de pose não é erro de programação. As três condições acontecem fora do aparelho e são invisíveis para o código: não há sensor de textura a consultar, nem medidor de luz da sala. O que existe é uma consequência única e observável. A cada quadro o ambiente pede a pose. Quando o aparelho perdeu a conta de onde está, ela simplesmente não vem. A primeira reação de quem encontra um quadro sem pose é procurar defeito no próprio código, e essa procura consome horas. Tratar a ausência como caso normal do laço de renderização é decisão de projeto. É o que separa um ambiente que degrada com elegância de um que trava.
Contar essas ausências transforma uma impressão em medida. “O rastreamento estava ruim” é uma frase que não se confronta com nada. “A pose faltou numa fração dos quadros observados, com uma lacuna máxima de tantos quadros seguidos” é uma frase que outra pessoa pode reproduzir e comparar entre aparelhos. Um caso precisa ficar fora da contagem. Quando alguém abre o menu do sistema do visor, a sessão continua viva e a pose deixa de vir. O ambiente saiu de primeiro plano.
Feita a contagem, aparece a tentação de interpretá-la, e é aqui que muitos relatórios se estragam. Qual das três condições causou a perda? Daqui não se sabe, e o motivo é estrutural: as três produzem exatamente o mesmo sintoma. Um relatório que afirma “rastreamento degradado por iluminação insuficiente” inventou o laudo junto com a medida. Alguém vai acender uma lâmpada para resolver um problema que era a parede lisa.
Prefiro o relatório que nomeia as três causas prováveis e declara que não as distingue. A razão é prática: ele manda a pessoa certa olhar para os três lugares certos. Daí sai um princípio de projeto que ultrapassa a sonda. Contagem e interpretação ficam em lugares separados no código, sempre. Quando as duas moram juntas, o instrumento passa a produzir a conclusão que quem o escreveu esperava. E ninguém percebe, porque o número e a conclusão saem da mesma linha.
1.4 Nenhuma plataforma diz quantos graus ela rastreia
A pergunta mais natural sobre um aparelho não tem resposta na interface de programação, e a ausência foi decidida em vez de esquecida.
Sabendo que graus de liberdade preveem desconforto, a pergunta se impõe sozinha. Quantos este aparelho acompanha? Onde se lê esse número? A resposta incomoda: em lugar nenhum. Não existe propriedade, consulta ou campo que informe isso nas plataformas de programação de ambientes imersivos em uso hoje.
A primeira reação é supor descuido de quem escreveu a especificação. Pois é, e não foi. O navegador que executa o ambiente não conversa com o sensor, não sabe que sensores existem dentro do aparelho e não tem como auditá-los. Ele conversa com o sistema do próprio aparelho, e o que esse sistema entrega é de outra natureza.
1.4.1 Um espaço de referência é uma promessa
Se o número não existe, o que existe no lugar dele? O que a plataforma entrega são espaços de referência, e pedir um deles é pedir uma promessa específica. Peço que as poses venham medidas a partir do chão do ambiente. Peço que venham medidas a partir de onde a pessoa estava quando a sessão começou. Peço que venham medidas a partir da própria cabeça de quem observa.
Complementar — espaço de referência
Um espaço de referência é um sistema de coordenadas com origem e orientação definidas, contra o qual as poses entregues pelo aparelho são expressas. A relação que importa liga o sistema interno de rastreamento ao sistema em que o ambiente trabalha. Conceder um espaço é afirmar que ela pode ser mantida coerente ao longo da sessão. É essa afirmação que o código consegue consultar — e não um número de sensores.
O menor exemplo concreto: pedir a origem no chão é pedir que a altura zero coincida com o piso físico onde a pessoa está. A definição não exige que essa origem seja precisa. Não exige que ela permaneça imóvel se o mapa for corrigido. E não diz nada sobre a frequência com que a pose é atualizada.
Aí mora a inferência que salva o problema. Um espaço ancorado no chão exige saber onde o chão está em relação a quem observa, e essa relação muda quando a pessoa anda. Um aparelho que apenas gira não sustenta essa promessa, porque não sabe que a pessoa andou. Conceder o espaço com chão é, portanto, evidência forte de que há posição rastreada.
flowchart TD
A[Pedir espacos<br/>de referencia] --> B{Qual foi<br/>concedido?}
B -- So o que acompanha<br/>quem observa --> C[Tres graus]
B -- O ancorado<br/>no chao --> D[Seis graus]
B -- So o intermediario --> E[Indeterminado]
E --> F[Escrever nao da para saber daqui,<br/>em vez de apostar no mais provavel]
O caso do meio é genuinamente ambíguo. Origem próxima de quem observa no início da sessão é compatível com três graus e com seis, e nada mais na sessão desempata. A tentação é apostar no mais provável, já que hoje a maioria dos aparelhos que chega até aí acompanha seis. Não apostamos, e a razão vale mais que a regra. Um relatório que afirma seis graus com evidência fraca vai ser citado como se fosse medida. O engano aparece no dia da demonstração, num aparelho diferente.
Essa postura tem custo, e é honesto declará-lo. Um relatório com indeterminados parece menos competente que um relatório com números em todas as linhas. Quem o lê pela primeira vez pode concluir que a sondagem ficou pela metade. É um custo de aparência, pago em troca de não afirmar o que não se sabe.
1.4.2 O nome do aparelho não é fonte
Por que não ler simplesmente o nome do aparelho? O caminho existe e é usado em código de produção. O navegador expõe uma cadeia de identificação que descreve o programa, a versão e, às vezes, o modelo. Basta procurar nela o nome do visor e consultar uma tabela com as capacidades de cada modelo conhecido.
Funciona por um tempo, e depois falha de três maneiras conhecidas. A cadeia é editável por quem usa. Ela é deliberadamente imitada por aparelhos que querem receber o mesmo conteúdo que os concorrentes. E envelhece: modelo novo não está na tabela, e a tabela precisa de manutenção que ninguém faz.
Existe um problema mais fundo que os três, e ele não é de manutenção. O nome do modelo descreve o que o aparelho consegue fazer em condições de fábrica. O que interessa ao ambiente é o que ele está fazendo agora, nas mãos desta pessoa, nesta sala, com estas permissões concedidas. Um visor de seis graus com a câmera obstruída não entrega seis graus, e o nome dele continua o mesmo.
Há um argumento em favor da identidade que merece resposta honesta, porque ele não é tolo. Em alguns casos, saber o modelo permite contornar defeitos conhecidos daquele equipamento, e consulta de capacidade nenhuma revela defeito. É uso legítimo. O que não se sustenta é usar a identidade para responder a uma pergunta que a capacidade responde melhor. Graus de liberdade é exatamente uma dessas.
1.5 Silêncio não é a mesma coisa que não
Três respostas chegam pelo mesmo canal, e confundir duas delas produz um relatório alinhado, completo e falso.
Além dos espaços de referência, a plataforma expõe uma segunda família de perguntas. Um conjunto de capacidades opcionais pode ser solicitado ao abrir a sessão, e quatro delas interessam aqui. Lançar raio contra superfícies reais. Receber os planos reconhecidos. Prender objetos a âncoras corrigidas. Acompanhar a pose das mãos sem controle.
O ambiente pede o que quer usar, e o aparelho concede o que consegue. Parece simples, até se perguntar o que significa não receber alguma coisa. Um computador de mesa sem câmera não faz detecção de superfície real, e nenhuma configuração muda isso. Já um visor capaz pode ter tido a permissão recusada, ou a política do navegador bloqueou, ou o sistema desativou o recurso.
Do lado de quem escreve o código, os dois chegam idênticos. A plataforma não distingue, e a razão é defensável. Informar por que um recurso foi negado vazaria detalhes da configuração de quem usa para qualquer página visitada. A distinção precisa ser construída à mão. Sem ela, o relatório trata “não tem” e “não quis” como a mesma coisa. A diferença entre os dois diagnósticos é a diferença entre trocar de equipamento e clicar num botão.
flowchart TD
A[Recurso pedido<br/>ao abrir a sessao] --> B{A sessao declarou<br/>a lista do que ligou?}
B -- Nao ha lista --> I[Indeterminado:<br/>nao houve resposta]
B -- Ha lista --> C{O nome consta<br/>dela?}
C -- Sim --> G[Concedido]
C -- Nao --> N[Negado:<br/>houve resposta, e foi nao]
I --> X[Tratar como negado<br/>afirma o que o aparelho nunca disse]
Conclusivo — três estados, e o terceiro é o que evita o erro caro
Concedido: o nome consta da lista reportada pela sessão, e o recurso pode ser usado. Negado: a lista existe e o nome não está nela; houve resposta, e ela foi negativa. Indeterminado: não há lista a consultar, porque declará-la é opcional; não houve resposta. Sem o terceiro estado, um navegador competente que apenas não declara o que ligou aparece descrito como aparelho que negou tudo. Tabela preenchida, alinhada e falsa.
1.5.1 Por que o catálogo curto é decisão de risco
Ao montar a lista de recursos a consultar, a tentação imediata é pedir tudo. Informação a mais não custa nada, diz o raciocínio, e ele está errado por duas razões independentes. A primeira é tempo: cada recurso pedido entra na negociação de abertura da sessão, e negociação longa atrasa o instante em que a imagem aparece. Quem está de visor não vê barra de carregamento — vê o mundo demorando a existir.
A segunda razão é a que decide. Alguns recursos exigem um dicionário de configuração próprio no momento do pedido, com formatos e opções específicos. Um pedido malformado não devolve recurso negado: ele derruba a sessão inteira. A sondagem perde tudo o mais que teria descoberto, por causa de um item que talvez nem fosse usado.
Daí a regra que o projeto adota, conservadora de propósito. Só entra no catálogo o recurso de que algum ponto do percurso depende, e o motivo da omissão fica escrito ao lado. A próxima pessoa a ler o arquivo vai querer acrescentar o que falta, e ela merece saber que a ausência foi decidida.
O efeito colateral convém aceitar de olhos abertos. O catálogo curto produz um relatório que não descreve o aparelho por inteiro: há capacidades que aquele equipamento tem e que ninguém perguntou. O relatório retrata o encontro entre aquele aparelho e este ambiente específico, e não o aparelho em si. Abri uma exceção, e ela ilustra o critério. O acompanhamento de mãos fica fora do núcleo do percurso e ainda assim entra no catálogo. Saber que ele existe naquele equipamento tem valor de registro.
1.6 O diagnóstico que não chega a quem está de visor
Toda essa informação é inútil se ela aparecer num lugar que quem está com o aparelho no rosto não consegue abrir.
Suponha resolvido tudo o que veio até aqui. O ambiente consulta os espaços de referência e infere os graus com a devida prudência. Classifica cada recurso em três estados e conta os quadros sem pose. Resta uma pergunta que parece de acabamento e não é: onde esse resultado aparece?
A resposta natural de quem programa para a web é o console de depuração. Ela funciona perfeitamente, e funciona para uma pessoa só: quem está sentada diante do computador em que o código foi escrito. Veja só o que acontece com o resto do mundo. Quem está com um visor no rosto não abre painel de desenvolvedor, não vê aviso de rede e não fica sabendo que houve exceção.
O efeito se repete com quase todo mundo que constrói um ambiente pela primeira vez. Alguém escreve o programa, testa no computador, envia para o visor e toca o botão. Nada acontece. O botão parece quebrado, e a busca começa pelo tratador do evento, que está correto. Houve uma recusa, informada por um canal que ninguém dentro do visor consegue consultar.
1.6.1 Traduzir a recusa em frase
Quando um pedido de sessão é recusado, o que chega ao código é um erro cru. Um nome de classe e uma frase curta, em inglês, escrita para quem implementa navegadores. Exibir esse texto tal como veio é tecnicamente honesto e praticamente inútil, porque ele não separa as situações que quem está usando precisa separar.
São três as recusas que acontecem de verdade, e cada uma pede uma ação diferente. O aparelho pode não sustentar o modo pedido, e aí resta usar outro regime. O pedido pode ter partido sem gesto de quem usa, ou fora de conexão cifrada, e aí a correção é de quem escreveu. E pode já haver uma sessão aberta, resquício de uma tentativa anterior que não encerrou.
Traduzir essas três em frases que digam o que aconteceu e o que fazer não é enfeite de interface. É a diferença entre alguém concluir que o programa está com defeito e alguém entender que o aparelho respondeu não. A segunda conclusão é verdadeira e leva à ação certa; a primeira manda a pessoa depurar código que está correto.
Existe um erro mais sutil que os três, e ele passa por competência. O ambiente captura a exceção, impede que a página quebre e não mostra nada. De fora, tudo parece bem: página intacta, sem mensagem vermelha, sem travamento. De dentro do visor, o que se vê é um botão que não reage. Capturar a falha e silenciá-la é pior do que deixá-la aparecer.
1.6.2 O endereço que responde no lugar do aparelho
Como um relatório perfeitamente coerente pode estar inteiramente errado? A armadilha vem de uma exigência de segurança da plataforma, e ela é fácil de esquecer justamente porque não produz mensagem de erro. As capacidades imersivas só são expostas em conexão cifrada. Numa página servida sem cifragem, a interface de programação simplesmente não está lá.
Toda consulta responde, então, exatamente como responderia num aparelho sem suporte algum. O visor mais capaz do laboratório, aberto no endereço errado, produz um relatório idêntico ao de um computador antigo. Nada nesse relatório denuncia o engano: as linhas estão preenchidas, os estados são coerentes entre si, a conclusão é plausível. É a causa número um de diagnóstico errado, e ela custa uma tarde inteira de quem investiga um equipamento perfeito.
A defesa cabe numa linha, escrita antes de qualquer outra informação. Ela responde a uma pergunta que precede todas as demais: o que vem abaixo é informação sobre o aparelho, ou sobre o endereço? Uma linha, no topo, que evita a tarde perdida.
flowchart LR
A[Pagina carrega] --> B[Primeiro tempo:<br/>contexto seguro, interface exposta,<br/>tipos de sessao declarados]
B --> C[Botao grande<br/>espera o gesto]
C --> D[Segundo tempo:<br/>sessao aberta]
D --> E[Espacos concedidos,<br/>recursos ligados,<br/>fontes de entrada,<br/>quadros com e sem pose]
E --> F[Encerrar sempre,<br/>inclusive se algo falhar]
F --> G[Relatorio legivel<br/>no proprio aparelho]
Repare que a sondagem se parte em dois tempos, e a divisão vem de outra regra da plataforma. Entrar em sessão imersiva exige um gesto explícito de quem usa, e o navegador recusa o pedido que não venha de um. Há, portanto, o que se descobre ao carregar a página e o que só a sessão aberta responde. Duas restrições de apresentação decorrem disso, e as duas parecem gosto. O botão precisa ser grande, porque mirar de visor é apontar um raio a um metro do alvo. O texto também, porque a resolução angular do aparelho é bem menor que a de um monitor a meio metro dos olhos.
1.7 O ambiente que pergunta antes de desenhar
A primeira peça executável do percurso não desenha um triângulo sequer, e é ela que decide o que todas as outras poderão assumir.
Todo o vocabulário do capítulo cabe em três arquivos pequenos, e vale ler os três com o argumento na cabeça.
O primeiro traduz a inferência conservadora dos graus de liberdade. Ele parte do que a sessão concedeu, e não do que o navegador diz ser.
devices/graus.ts
// ---------------------------------------------------------------------------
// Graus de liberdade e classe do aparelho, inferidos do que foi concedido.
//
// A API XR não expõe um número de graus de liberdade. Não há propriedade a ler,
// e isso não é omissão: o navegador não sabe o que o sensor faz, sabe o que o
// runtime do aparelho aceitou entregar. O que existe para inferir é o conjunto de
// espaços de referência concedidos, e a inferência tem limites que este arquivo
// registra em vez de esconder.
//
// O porquê de a inferência ser conservadora: um relatório que afirma "seis graus
// de liberdade" com base em evidência fraca é pior que um relatório que diz "não
// dá para saber daqui". O primeiro será citado; o segundo, verificado.
// ---------------------------------------------------------------------------
/**
* O que se pode afirmar sobre o rastreamento de posição a partir do que a sessão
* concedeu — três graus (só orientação) contra seis (orientação e posição).
*/
export type GrausDeLiberdade = 'tres' | 'seis' | 'indeterminado';
/**
* Classe do aparelho deduzida da capacidade declarada, e não do nome que o
* navegador diz ter.
*
* A escolha é deliberada e é o conteúdo do módulo: a cadeia de identificação do
* navegador é editável, imitada por outros aparelhos e envelhece a cada versão.
* O que a sessão concede é o que o aparelho faz agora, na mão de quem está
* usando.
*/
export type ClasseDeAparelho =
| 'sem-api'
| 'somente-janela'
| 'visor-sem-posicao'
| 'visor-com-posicao'
| 'aparelho-de-mao-com-camera';
export interface LeituraDeEspacos {
/** Espaços de referência que a sessão de fato entregou quando pedidos. */
readonly concedidos: readonly string[];
/** O modo de sessão em que a leitura foi feita. */
readonly modo: 'immersive-vr' | 'immersive-ar';
/** Havia alguma fonte de entrada com pose de punho declarada. */
readonly comPoseDePunho: boolean;
}
/**
* Regra da inferência, escrita por extenso porque é ela que o estudante precisa
* poder contestar:
*
* - `local-floor` ou `bounded-floor` concedidos exigem que o aparelho saiba onde
* está o chão em relação a quem observa. Um visor que só gira não tem como
* sustentar isso, então a concessão é evidência forte de posição rastreada.
* - `viewer` sozinho é o mínimo que qualquer sessão entrega: a origem acompanha
* quem observa, e translação alguma é observável a partir dela. Evidência forte
* da ausência.
* - `local` no meio do caminho é ambíguo de verdade. A especificação o descreve
* como origem próxima de quem observa no início da sessão, e um aparelho de três
* graus pode concedê-lo mantendo a posição sempre na origem. Daí
* `indeterminado`, e não uma aposta.
*/
export function grausDeLiberdade(leitura: LeituraDeEspacos): GrausDeLiberdade {
const temChao: boolean =
leitura.concedidos.includes('local-floor') ||
leitura.concedidos.includes('bounded-floor') ||
leitura.concedidos.includes('unbounded');
if (temChao) {
return 'seis';
}
if (leitura.concedidos.length === 1 && leitura.concedidos[0] === 'viewer') {
return 'tres';
}
return 'indeterminado';
}
/**
* Classifica o aparelho pela combinação de modo de sessão, posição rastreada e
* tipo de mira das fontes de entrada.
*
* `modosSuportados` vem da consulta feita sem sessão alguma — a mesma do módulo
* anterior —, e por isso esta função responde mesmo quando nenhuma sessão chegou
* a abrir.
*/
export function classificarAparelho(
modosSuportados: readonly string[],
graus: GrausDeLiberdade,
temApiXr: boolean,
): ClasseDeAparelho {
if (!temApiXr) {
return 'sem-api';
}
const suportaVr: boolean = modosSuportados.includes('immersive-vr');
const suportaAr: boolean = modosSuportados.includes('immersive-ar');
if (!suportaVr && !suportaAr) {
return 'somente-janela';
}
// Aparelho que faz realidade aumentada e não faz sessão imersiva completa é o
// celular: a câmera vê o mundo, mas ninguém veste a tela no rosto.
if (suportaAr && !suportaVr) {
return 'aparelho-de-mao-com-camera';
}
return graus === 'tres' ? 'visor-sem-posicao' : 'visor-com-posicao';
}
/** Frase curta e legível para cada classe, usada no relatório. */
export function descreverClasse(classe: ClasseDeAparelho): string {
switch (classe) {
case 'sem-api':
return 'Navegador sem a API XR, ou página fora de contexto seguro.';
case 'somente-janela':
return 'Aparelho que só sustenta o regime de janela — é o caso do desktop do laboratório.';
case 'visor-sem-posicao':
return 'Visor que acompanha a rotação da cabeça e não acompanha o deslocamento.';
case 'visor-com-posicao':
return 'Visor que acompanha rotação e deslocamento, com o chão do ambiente como referência.';
case 'aparelho-de-mao-com-camera':
return 'Aparelho de mão que compõe o virtual sobre a imagem da própria câmera.';
}
}
Repare que o caso do meio devolve indeterminado. É a recusa da aposta, escrita como valor de retorno em vez de comentário.
O segundo arquivo constrói, à mão, a distinção que a plataforma não entrega. Ele classifica cada recurso pedido contra a lista que a sessão reportou — e trata a ausência da lista como terceira coisa.
devices/recursos.ts
// ---------------------------------------------------------------------------
// Catálogo dos recursos opcionais que a sonda consulta, e a classificação do
// que o aparelho respondeu sobre cada um.
//
// Este arquivo existe para separar duas coisas que o vocabulário corrente
// confunde: o recurso que o aparelho NÃO TEM e o recurso que ele TEM e NÃO
// CONCEDEU. A API XR trata os dois de um jeito só na hora de pedir — passam
// ambos por `optionalFeatures` e simplesmente não aparecem depois —, e é por
// isso que a distinção precisa ser feita aqui, à mão, em vez de esperada da
// plataforma.
//
// O terceiro estado é o que mais dá trabalho e o que mais evita erro:
// `indeterminado`. A sessão só reporta o que concedeu através de
// `enabledFeatures`, e essa propriedade é opcional na especificação — um
// navegador pode entrar em sessão sem dizer o que ligou. Sem o terceiro estado,
// esse navegador apareceria no relatório como aparelho que negou tudo.
// ---------------------------------------------------------------------------
/**
* O que se sabe sobre um recurso depois de a sessão abrir.
*
* - `concedido`: o nome está em `enabledFeatures`, e o recurso pode ser usado.
* - `negado`: a sessão reportou a lista e o nome não está nela — o aparelho ou o
* navegador recusou, e a razão não é exposta.
* - `indeterminado`: a sessão não reportou lista alguma. Não é negativa; é
* ausência de resposta, e tratá-la como negativa produz relatório confiante e
* errado.
*/
export type EstadoDeRecurso = 'concedido' | 'negado' | 'indeterminado';
/** Um recurso opcional da API XR, com o motivo de ele estar no catálogo. */
export interface RecursoOpcional {
/** O nome exato aceito por `optionalFeatures` — não traduzir. */
readonly nome: string;
/** O que ele habilita no percurso, em uma frase. */
readonly paraQueServe: string;
}
/**
* Os recursos que a Bancada consulta.
*
* A lista é curta de propósito: pedir tudo o que a especificação prevê faria a
* sonda demorar mais e algumas plataformas recusarem a sessão inteira por causa
* de um item exótico. Cada entrada aqui é um recurso de que algum módulo adiante
* realmente depende.
*
* `depth-sensing` ficou de fora, e a razão é técnica: ele exige um dicionário de
* configuração próprio no pedido de sessão (formato de dado e ordem de uso), e um
* pedido malformado derruba a sessão inteira em vez de apenas negar o recurso.
* Consultá-lo custaria, aqui, o risco de perder tudo o mais.
*/
export const RECURSOS_CONSULTADOS: readonly RecursoOpcional[] = [
{
nome: 'local-floor',
paraQueServe:
'origem no chão do espaço físico — é o que faz a bancada nascer na altura certa',
},
{
nome: 'bounded-floor',
paraQueServe:
'origem no chão mais os limites da área livre que o aparelho conhece',
},
{
nome: 'unbounded',
paraQueServe: 'espaço sem fronteira declarada, para percursos longos',
},
{
nome: 'hit-test',
paraQueServe:
'lançar um raio contra as superfícies reais que o aparelho encontrou',
},
{
nome: 'anchors',
paraQueServe:
'prender um objeto virtual a um ponto do mapa e deixar o aparelho corrigi-lo',
},
{
nome: 'plane-detection',
paraQueServe: 'receber os planos que o aparelho reconheceu no ambiente',
},
{
nome: 'hand-tracking',
paraQueServe:
'pose das mãos sem controle — fora do núcleo do percurso, e consultado só para registro',
},
];
/**
* Classifica um recurso contra a lista que a sessão reportou.
*
* `concedidos` vem de `XRSession.enabledFeatures`, que é opcional na
* especificação: `undefined` significa "esta sessão não diz", e é o que produz
* `indeterminado`.
*/
export function estadoDoRecurso(
nome: string,
concedidos: readonly string[] | undefined,
): EstadoDeRecurso {
if (concedidos === undefined) {
return 'indeterminado';
}
return concedidos.includes(nome) ? 'concedido' : 'negado';
}
Veja também o comentário sobre o recurso de leitura de profundidade, deixado fora do catálogo. Ele é o exemplo concreto do item cujo pedido malformado custaria a sondagem inteira.
O terceiro arquivo transforma a falha em medida. Ele conta quadros com pose e quadros sem, separa a sessão que saiu de foco, e deixa o julgamento numa função à parte.
devices/estabilidade.ts
// ---------------------------------------------------------------------------
// A falha como medida, e não como anedota.
//
// A pose de quem observa pode simplesmente não vir. A API prevê isso: o quadro
// entrega a pose ou entrega nada, e nada significa que o aparelho perdeu, naquele
// instante, a conta de onde está. É o único sintoma de degradação de rastreamento
// que se lê de dentro do código, sem instrumento e sem sensor extra.
//
// Este contador existe porque o módulo cobra prever a falha, e previsão que não
// se confronta com contagem alguma é opinião. Ele é deliberadamente burro: conta
// quadros com pose e quadros sem, e mais nada. A interpretação fica na função de
// diagnóstico, separada de propósito — misturar contagem e julgamento é o que
// produz medidor que sempre concorda com quem o escreveu.
// ---------------------------------------------------------------------------
export interface Estabilidade {
readonly quadros: number;
readonly quadrosSemPose: number;
/** Maior sequência ininterrupta de quadros sem pose. */
readonly maiorLacuna: number;
/** Quadros descartados por a sessão não estar em primeiro plano. */
readonly quadrosOcultos: number;
}
/**
* Acumula a contagem quadro a quadro.
*
* O parâmetro `visivel` é o que separa perda de rastreamento de sessão que saiu
* de foco. Quando quem usa abre o menu do sistema do visor, a sessão continua
* viva, os quadros continuam chegando e a pose deixa de vir — e contar isso como
* falha de sensor acusaria o aparelho de um defeito que é comportamento normal
* do sistema operacional.
*/
export class ContadorDeEstabilidade {
private quadros: number = 0;
private quadrosSemPose: number = 0;
private quadrosOcultos: number = 0;
private maiorLacuna: number = 0;
private lacunaCorrente: number = 0;
public registrar(temPose: boolean, visivel: boolean): void {
this.quadros += 1;
if (!visivel) {
this.quadrosOcultos += 1;
this.lacunaCorrente = 0;
return;
}
if (temPose) {
this.lacunaCorrente = 0;
return;
}
this.quadrosSemPose += 1;
this.lacunaCorrente += 1;
if (this.lacunaCorrente > this.maiorLacuna) {
this.maiorLacuna = this.lacunaCorrente;
}
}
public resultado(): Estabilidade {
return {
quadros: this.quadros,
quadrosSemPose: this.quadrosSemPose,
maiorLacuna: this.maiorLacuna,
quadrosOcultos: this.quadrosOcultos,
};
}
}
/**
* Traduz a contagem numa frase, com as condições que a bibliografia da disciplina
* aponta como causas de degradação de rastreamento óptico: superfície sem textura
* (não há canto a reconhecer), iluminação pobre (não há contraste para extrair
* canto algum) e movimento brusco (a imagem borra e o canto some entre quadros).
*
* A frase não afirma qual das três aconteceu. Não dá para saber daqui, e escolher
* uma seria inventar o diagnóstico junto com a medida.
*/
export function diagnosticar(estabilidade: Estabilidade): string {
if (estabilidade.quadros === 0) {
return 'Nenhum quadro foi entregue — a sessão não chegou a produzir imagem.';
}
if (estabilidade.quadrosSemPose === 0) {
return 'A pose veio em todos os quadros observados. A janela de observação é curta, e ausência de falha aqui não é promessa de estabilidade em uso prolongado.';
}
const proporcao: number = Math.round(
(estabilidade.quadrosSemPose / estabilidade.quadros) * 100,
);
return (
`A pose faltou em ${proporcao}% dos quadros, com lacuna máxima de ` +
`${estabilidade.maiorLacuna} quadros seguidos. As causas prováveis são superfície ` +
'sem textura, iluminação pobre ou movimento brusco — e daqui não se distingue qual delas.'
);
}
Note a frase que a função de diagnóstico devolve. Ela nomeia as três causas prováveis e declara, na mesma linha, que daqui não se distingue qual delas aconteceu.
É a diferença entre um medidor e um laudo.
1.8 Cinco caixas que sobrevivem ao próximo lançamento
A classificação que fecha o inventário não cita marca nem modelo, e por isso não precisa ser atualizada quando um aparelho novo chegar.
Quantas caixas bastam para descrever qualquer aparelho que chegue ao ambiente? Três perguntas geram cinco categorias, e nenhuma delas parte de fabricante, geração de produto ou faixa de preço. Que modos de sessão o aparelho declara sustentar. Quantos graus a concessão de espaços permite inferir, pela inferência de Seção 1.4. E se a interface de programação está sequer disponível.
Duas vezes três daria oito, e a assimetria é proposital. Algumas combinações não ocorrem na prática, e forçar uma taxonomia completa produziria caixas que nada habita. Categoria vazia é ruído, porque obriga quem lê a considerar um caso que nunca vai encontrar.
A primeira caixa é a do aparelho sem a interface disponível. Ou o navegador não a implementa, ou a página está fora de conexão cifrada. Do lado de dentro do código, as duas situações são indistinguíveis. A segunda é o aparelho que só sustenta o regime de janela, caso do computador de mesa e caso base de todo o percurso. A terceira e a quarta se separam pela inferência: o visor que gira e não anda, e o que acompanha o corpo pelo ambiente. A quinta sustenta o regime aumentado e não o imersivo completo, que é a descrição exata do celular.
1.8.1 Três coisas que esta classificação não promete
Toda taxonomia útil tem um recorte, e declará-lo é o que impede que ela seja usada onde não vale. Esta classifica o que o aparelho faz, e nada além disso. Ela não diz se ele é confortável, não diz se roda bem, não diz quantos quadros por segundo entrega nem se a imagem é nítida.
Dois aparelhos na mesma caixa podem ser radicalmente diferentes para quem os veste. Um deles pode ser pesado a ponto de se tornar insuportável em uso prolongado, e a classificação não tem linha para isso. Um deles pode entregar metade dos quadros do outro, e os dois continuam juntos. Nenhuma dessas grandezas está ao alcance da consulta, e fingir que estão seria o mesmo defeito que derruba a cadeia de identificação.
Há uma ausência mais sentida que as outras. A classificação não diz nada sobre a qualidade do rastreamento, só sobre a existência dele. Um visor que acompanha translação com precisão excelente e outro que a acompanha mal caem na mesma caixa. A concessão do espaço de referência é a mesma nos dois casos. A qualidade só aparece na contagem de quadros sem pose, que é medida separada e de outra natureza.
Isso não é limitação a corrigir numa versão futura. É consequência de a classificação se basear em promessas declaradas, e promessa declarada não vem com métrica de cumprimento, do mesmo jeito que um cardápio informa que há sobremesa sem dizer se ela vale a pena. O aparelho diz que sustenta; o quanto ele sustenta bem, só o uso responde.
flowchart TD
A[Vocabulario que descreve<br/>capacidade sem citar marca] --> S[Saldo do capitulo]
B[Consulta feita de verdade<br/>no lugar de suposicao] --> S
C[Distincao entre negado<br/>e sem resposta] --> S
D[Sintoma medivel<br/>de perda de rastreamento] --> S
S --> P{O que continua<br/>sem resposta?}
P --> P1[Escala e alcance de braco]
P --> P2[Taxa de quadros sob carga]
P --> P3[Conforto em uso prolongado]
P1 --> N[Nada disso se responde<br/>sem desenhar nada:<br/>o proximo passo e a cena]
P2 --> N
P3 --> N
O que fica pronto, então, é uma consulta honesta sobre o aparelho. O que falta é qualquer coisa a desenhar nele. Daqui em diante existe cena. Objetos com posição, orientação e escala, uma câmera que os observa, e um laço que produz imagem enquanto a sessão durar. Cada capacidade sondada aqui deixa de ser linha de relatório e vira decisão de projeto. O espaço concedido escolhe onde nasce a origem do mundo. Os graus inferidos escolhem que movimentos podem ser pedidos.
A pergunta que abre o próximo capítulo é a que este deixou sem resposta de propósito. Sabendo onde o observador está, como se organiza aquilo que ele vai ver? A resposta é uma estrutura de dados, e ela é mais velha que qualquer visor citado aqui.
Tarefa 1: Construir a sonda de capacidades
A primeira peça executável do ambiente não desenha coisa alguma. Ela pergunta ao aparelho o que ele oferece — que tipos de sessão suporta, que recursos opcionais concede, que fontes de entrada declara, quantos graus de liberdade rastreia — e guarda a resposta numa estrutura que o resto do ambiente possa consultar.
O que fica pronto é essa consulta feita de verdade contra o aparelho, com a distinção preservada entre recurso ausente e recurso negado. Assumir capacidade que o aparelho nunca declarou é a origem da maior parte das falhas silenciosas dos capítulos seguintes.
Tarefa 2: Tornar o relatório visível
Um relatório que só existe no console de depuração serve a quem escreveu o código e a mais ninguém. O resultado da sonda precisa aparecer em algum lugar que qualquer pessoa consiga ler no próprio aparelho.
A tarefa está cumprida quando o mesmo endereço, aberto em aparelhos de classes diferentes, produz relatórios diferentes e legíveis. É o instante em que a palavra dispositivo deixa de ser tópico narrado e passa a ser algo que se lê na tela.