No próximo fim de semana chegou, você precisa escrever algumas dezenas de linhas de código e desenhar uma imagem, mas nenhuma é a melhor. Então, no último fim de semana, mostrei como
fazer o traçado de raios e até
explodir tudo. Isso é surpreendente para muitos, mas a computação gráfica é uma coisa muito simples, algumas centenas de linhas de C ++ simples são suficientes para criar imagens interessantes.
O tópico da conversa de hoje é a visão binocular, e hoje não podemos sequer chegar a cem linhas de código. Sendo capaz de renderizar cenas tridimensionais, seria tolice passar por pares estereotipados, hoje vamos desenhar algo assim:

A loucura dos desenvolvedores do
Magic Carpet está me assombrando. Para quem não encontrou, este jogo possibilitou a renderização 3D em anaglyph e em estereogramas
nas configurações principais, disponíveis apenas no menu! Este cérebro explodiu apenas especificamente.
Parallax
Então, vamos começar. Para iniciantes, por que nosso aparato visual nos permite perceber a profundidade? Existe uma palavra tão inteligente "paralaxe". Se estiver nos dedos, vamos nos concentrar na tela. Tudo o que está no plano da tela para o nosso cérebro existe em uma única cópia. Mas se de repente uma mosca voa na frente da tela, então (se não mudarmos os olhos!) Nosso cérebro a registrará em duplicata. E, ao mesmo tempo, a aranha na parede atrás da tela também se bifurca, e a direção da bifurcação depende se o objeto está na frente do ponto focal ou atrás:

Nosso cérebro é uma máquina muito eficiente para analisar imagens ligeiramente diferentes. Ele usa
disparidade para obter informações detalhadas de imagens bidimensionais da retina para
estereopsia . Bem, Deus os abençoe, com as palavras, vamos desenhar melhor!
Vamos supor que nossa tela seja uma janela para o mundo virtual :)

Nossa tarefa é desenhar duas figuras com o que será visível através dessa “janela”. Haverá duas fotos, uma para cada olho, no diagrama acima, mostrei-as com um “sanduíche” vermelho e azul. Não vamos incomodar ainda como exatamente alimentamos essas imagens para o aparato visual, só precisamos salvar dois arquivos. Estou especificamente interessado em saber como essas imagens podem ser obtidas usando o
nosso traçador de raios .
Bem, suponha que a direção da aparência não mude, é um vetor (0,0, -1). Suponha que possamos mover a posição da câmera pela distância interocular, o que mais? Há uma pequena sutileza: o cone de visão através da nossa “janela” é assimétrico. E nosso traçador de raios só pode renderizar um cone de olhar simétrico:

O que fazer? Leia :)
De fato, podemos tornar as imagens mais amplas do que precisamos e apenas cortar o excesso:

Anaglyph
Com o mecanismo geral de renderização, deve ficar claro, agora é a hora de nos perguntarmos sobre a entrega da imagem ao nosso cérebro. Uma das opções mais simples são os óculos vermelho-azul:

Acabamos de fazer as duas pré-renderizações não em preto, mas em branco, escrevemos a imagem esquerda no canal vermelho e a imagem direita em azul. Você obtém a seguinte imagem:

O vidro vermelho cortará um canal e o azul cortará outro, para que cada olho receba sua própria imagem, e possamos olhar o mundo em 3D. Aqui estão as
alterações no commit principal do primeiro artigo , que mostram as configurações da câmera para os olhos e a montagem do canal.
As renderizações anaglíficas são uma das maneiras mais antigas de visualizar (computador!) As imagens estéreo. Eles têm muitas falhas, por exemplo, baixa renderização de cores (a propósito, tente gravar o canal verde do olho direito no canal verde da imagem final). Um benefício - esses óculos são facilmente fabricados com materiais improvisados.
Stereoscope
Com a proliferação de smartphones, lembramos o que são os estereoscópios (que, por um segundo, foram inventados no século XIX)! Há alguns anos, o
Google sugeriu o uso de duas lentes de um centavo (infelizmente elas não são feitas no joelho), um pouco de papelão (espalhadas por toda parte) e um smartphone (deitado no bolso) para obter óculos de realidade virtual bastante toleráveis:

No aliexpress, eram montões, cem rublos por peça. Comparado ao anaglyph, você não precisa fazer nada, basta tirar duas fotos e compor lado a lado,
eis o commit .

Estritamente falando, dependendo da lente, a
correção da distorção da lente pode ser necessária, mas eu não me incomodei e fica ótimo nos meus óculos. Mas se você realmente precisa aplicar uma pré-distorção em forma de barril que compensa a distorção da lente, é assim que fica para o meu smartphone e os meus óculos:

Estereogramas
Mas e se você não quiser usar dispositivos adicionais? Depois, há apenas uma opção - adormecer. De um modo geral, a imagem anterior é suficiente para assistir em estéreo, basta usar o truque para assistir em estéreo. Existem dois princípios para a visualização de estereogramas: mova os olhos ou afaste os olhos. Então, desenhei um diagrama no qual mostro como você pode ver a figura anterior. A imagem anterior é dupla, duas barras vermelhas no diagrama mostram duas imagens na retina esquerda, duas azuis na direita.

Se focarmos os olhos na tela, das quatro imagens obteremos duas. Se apertarmos os olhos para o nariz, é bem possível mostrar ao cérebro "três" figuras. E vice-versa, se você abrir os olhos, também poderá obter "três" fotos. A sobreposição de imagens centrais dará ao cérebro um efeito estéreo.
Esses métodos são dados a pessoas diferentes de maneiras diferentes, por exemplo, não sei como mexer meus olhos, mas procuro facilmente. É importante que o estereograma construído para um método seja visualizado da mesma maneira; caso contrário, é obtido um mapa de profundidade invertido (consulte paralaxe negativo e positivo). O problema com esse método de visualização em estéreo é que é muito difícil mover os olhos
fortemente em relação ao estado normal; portanto, você deve se contentar com imagens pequenas. E se você quiser grandes? Vamos sacrificar completamente a cor e queremos apenas uma percepção de profundidade. Olhando para o futuro, aqui está a imagem que obtemos no final desta parte:

Este estereograma foi projetado para "diluir" os olhos (estereograma de olhos nas paredes). Para quem prefere o modo inverso de visualização,
tire uma foto aqui . Se você não está acostumado a fazer estereogramas, tente diferentes condições: uma imagem em tela cheia, uma imagem pequena, luz brilhante, escuridão. A tarefa é abrir os olhos para que as duas faixas vorticais adjacentes coincidam. A maneira mais fácil de focar no canto superior esquerdo é ela é plana. Por exemplo, estou cercado pelo ambiente da Habr, abro a imagem em tela cheia. Não se esqueça de remover o mouse dele!
Não fique satisfeito com o efeito 3D com defeito. Se você está vagamente ciente das formas arredondadas no meio de pontos aleatórios, além de alguns efeitos 3D fracos, essa certamente é uma ilusão incompleta! Se você olhar corretamente, as bolas devem sair claramente do plano da tela para o visualizador, o efeito deve ser estável e mantido devido ao estudo constante e detalhado de cada parte da imagem, tanto em primeiro plano quanto em segundo plano. A estereopsia tem histerese: assim que você obtém uma imagem estável, fica mais clara quanto mais tempo você olha. Quanto mais a tela estiver dos olhos, maior será o efeito de profundidade.
Este estereograma foi desenhado de acordo com o método proposto há um quarto de século por Thimbleby et al. No artigo “
Exibição de imagens 3D: algoritmos para estereogramas de pontos aleatórios de imagem única ”.
Ponto de partida
O ponto de partida para renderizar estereogramas é um mapa de profundidade (esquecemos a cor).
Aqui está um commit que
mostra essa imagem:

As profundidades em nossa renderização são cortadas pelos planos próximo e distante, ou seja, o ponto mais distante do meu mapa tem uma profundidade de 0, o mais próximo.
Princípio básico
Deixe nossos olhos estarem distantes d da tela. Coloque o plano distante (imaginário) (z = 0) na mesma distância atrás da tela. Escolhemos uma constante μ, que determina a posição do plano próximo (z = 0): ele estará a uma distância μd do plano mais distante. Eu escolhi µ = 1/3 no meu código. No total, nosso mundo vive a uma distância de d-µd a d atrás da tela. Vamos ter uma distância definida entre os olhos (em pixels, no meu código eu escolhi 400 pixels).

Se observarmos o ponto do nosso objeto marcado em vermelho no diagrama, dois pixels marcados em verde devem ter a mesma cor no estereograma. Como encontrar a distância entre esses pixels? Muito simples Se o ponto projetado atual tiver uma profundidade z, a proporção de paralaxe e a distância entre os olhos será igual à proporção das profundidades correspondentes: p / e = (d-dμz) / (2d-dμz). A propósito, observe que d está encolhendo e não está envolvido em nenhum outro lugar! Ou seja, p / e = (1-μz) / (2-μz), o que significa que a paralaxe é igual a p = e * (1-μz) / (2-μz) pixels.
Ou seja, o princípio básico da construção de um estereograma: examinamos todo o mapa de profundidade, para cada valor de profundidade determinamos quais pixels devem ter a mesma cor e o escrevemos em nosso sistema de restrições. Em seguida, partimos de uma imagem arbitrária e tentamos cumprir todas as restrições impostas anteriormente.
Prepare a imagem original
Nesta fase, prepararemos uma imagem na qual mais tarde imporemos restrições de paralaxe.
Aqui, faça um commit , ele desenha esta imagem:

Observe que, em geral, as cores são aleatórias, exceto que eu coloquei rand () * sin no canal vermelho para fornecer ondas periódicas. Essas ondas são feitas com uma distância de 200 pixels, este (com μ selecionado = 1/3 e e = 400) é o valor máximo de paralaxe em nosso mundo, é também um plano distante. Essas ondas são opcionais, mas facilitarão o foco necessário da visão.
Render estereograma
Na verdade, o código completo relacionado ao estereograma se parece com o seguinte:
int parallax(const float z) { const float eye_separation = 400.;
Se alguma coisa,
comprometa -
se aqui . A função int parallax (const float z) fornece a distância entre pixels da mesma cor para o valor atual da profundidade. Renderizamos o estereograma linha por linha, uma vez que as linhas são independentes uma da outra (não temos paralaxe vertical). Portanto, o loop principal simplesmente percorre todas as linhas; para cada um deles, começamos com um conjunto completo e ilimitado de pixels, no qual imporemos restrições de igualdade aos pares e, no final, teremos um certo número de clusters de pixels (desconectados) da mesma cor. Por exemplo, um pixel com índice à esquerda e um pixel com índice à direita devem acabar sendo os mesmos.
Como armazenar esse conjunto de restrições? A resposta mais simples é a
união - encontre a estrutura de dados . Não vou descrevê-lo, são apenas três linhas de código, você pode lê-lo na Wikipedia. A idéia principal é que, para cada cluster, teremos um certo "responsável" por ele, também é um pixel raiz, deixaremos a mesma cor da imagem original e repintaremos todos os outros pixels do cluster:
for (size_t i=0; i<width; i++) {
Conclusão
Bem, na verdade, é tudo. Vinte linhas de código - e nosso estereograma está pronto, quebre seus olhos e cabeças, desenhe! A propósito, apenas cores aleatórias em um estereograma geralmente são um luxo; em princípio, se você tentar, também poderá transmitir parcialmente a cor da imagem.
Outros sistemas de visualização estéreo, por exemplo,
relacionados à polarização , tirei da discussão, pois vão além do orçamento de cem rublos. Se você perder alguma coisa, adicione e corrija!