Rotação da câmera 3D

9

Por favor, perdoe-me, mas preciso de ajuda e estou preso a isso há algumas semanas, não estou fazendo nenhum progresso e em todos os lugares que vou e vejo uma resposta diferente, tudo o que tento não funciona. Já tive dicas e conselhos suficientes, agora só preciso que alguém me dê a resposta para que eu trabalhe de trás para frente porque não consigo entender isso.

O que tornou esse assunto mais confuso é a maneira como todos usam um conjunto diferente de convenções ou regras, e suas respostas são baseadas em suas próprias convenções, sem definir o que são.

Então, aqui está o conjunto de convenções que formei com base no que parece ser mais comum e lógico:

  1. Regra da mão direita para o eixo.
  2. O positivo Y está ativo, o positivo Z está voltado para o espectador, o positivo X está à direita.
  3. Matrizes principais de linha, transpostas quando enviadas para shaders.
    • Passo: rotação em torno do eixo X
    • Guinada: rotação em torno do eixo y
    • Rolo: rotação sobre o eixo z
  4. Ordem de rotação: rotação, inclinação, guinada (isso está correto? Alguém pode me verificar isso?)
  5. Valores de rotação positivos, olhando para baixo a partir da extremidade positiva de um eixo, resultam em rotação no sentido horário.
  6. A direção padrão para a rotação 0 em todo o eixo é um vetor apontando para Y negativo.

.. dadas essas convenções (por todos os meios, corrija-me se estiverem erradas!), como alguém:

  • Escreva uma função LookAt? (lookAt (posição do vetor, foco do vetor, vetor acima))
  • Calcular uma matriz de rotação. (rotação (x, y, z))

Tentei responder a essas duas perguntas pessoalmente pelo menos nas últimas 3 semanas, reescrevi minha função LookAt & Rotation Matrix pelo menos 30 vezes, testei dezenas de métodos e li o material que vi em centenas de sites e leu muitas perguntas respondidas, copiou o código de outras pessoas e nada que eu fiz até agora funcionou, tudo produziu o resultado errado. Alguns dos quais produziram resultados hilariantes e bizarros, nem mesmo perto da rotação correta.

Venho trabalhando nisso todas as noites, com exceção da noite passada, porque estava tão frustrado com o fracasso repetido que tive que parar e fazer uma pausa.

Por favor, mostre-me qual é o método correto para que eu possa trabalhar de trás para frente e descobrir como funciona. Só não estou recebendo a resposta correta e isso está me deixando um pouco louco!

Estou escrevendo em Java, mas vou pegar o código escrito em qualquer linguagem, a maioria do meu código de renderização 3D está realmente funcionando de maneira brilhante, são apenas as matemáticas que não consigo entender.

ATUALIZAÇÃO: RESOLVIDO

Obrigado pela ajuda! Agora tenho uma função LookAt funcional que realmente entendo e não poderia estar mais feliz (se alguém quiser vê-la, pergunte por todos os meios).

Tentei novamente criar uma matriz de rotação baseada em variáveis ​​fora do pitch / yaw / roll e novamente pareceu falhar, mas decidi fazer um dump ao tentar usar ângulos de euler para a câmera freelook, pois parece ser inadequado para o O papel, em vez de criar uma classe de quaternion, pode ter melhor sorte nesse caminho; caso contrário, recorrerei ao uso do pitch / yaw como coordenadas esféricas e contarei com a nova função LookAt para rotação.

Se alguém estiver enfrentando um problema semelhante e quiser me fazer perguntas, sinta-se à vontade.

Pelo menos não estou mais preso, obrigado pela ajuda!

Grady
fonte

Respostas:

15

O que você está procurando pode ser encontrado nesta muito boa explicação: http://www.songho.ca/opengl/gl_transform.html

Mas desde que eu achei meio confuso sem segurar as mãos, tentarei explicar aqui.

Neste ponto, você precisa considerar 5 sistemas de coordenadas e como eles se relacionam. Estas são as coordenadas da janela, as coordenadas normalizadas do dispositivo, as coordenadas oculares, as coordenadas mundiais e as coordenadas do objeto.

As coordenadas da janela podem ser vistas como os pixels "físicos" na tela. São as coordenadas às quais o sistema de janelas se refere e, se você opera na resolução nativa de seus monitores, esses pixels são realmente individuais. O sistema de coordenadas da janela é um número inteiro 2D e é relativo à sua janela. Aqui o x + é deixado e o y + está abaixo com a origem no canto superior esquerdo. Você os encontra quando, por exemplo, liga glViewport.

O segundo conjunto são as coordenadas normalizadas do dispositivo. Referem-se à configuração de espaço pela porta de visualização ativa. A área visível da porta de visualização varia de -1 a +1 e, portanto, tem a origem no centro. O x + é deixado e o y + é ativado. Você também tem o z + "fora" da cena. Isso é o que você descreve em 1.

Você não tem controle sobre como obter das coordenadas normalizadas do dispositivo para as coordenadas da janela, isso é feito implicitamente para você. O único controle que você tem é completo glViewportou similar.

Ao trabalhar com o openGL, seu resultado final sempre estará nas coordenadas normalizadas do dispositivo. Como resultado, você precisa se preocupar em exibir sua cena neles. Se você definir a matriz de projeção e visualização de modelo para a matriz de identidade, poderá desenhar diretamente essas coordenadas. Isso é feito, por exemplo, ao aplicar efeitos em tela cheia.

O próximo são as coordenadas oculares. Este é o mundo visto da câmera. Como resultado, a origem está na câmera e os mesmos eixos são aplicados como as coordenadas do dispositivo.

Para ir das coordenadas oculares às coordenadas do dispositivo, você cria a matriz de projeção. O mais simples é a projeção ortográfica que apenas dimensiona os valores adequadamente. A projeção em perspectiva é mais complicada e envolve a perspectiva da simulação.

Finalmente, você tem o sistema de coordenadas do mundo. Este é o sistema de coordenadas em que seu mundo está definido e sua câmera faz parte deste mundo. Aqui é importante observar que as orientações do eixo são exatamente como você as define . Se você preferir z +, isso é totalmente aceitável.

Para passar das coordenadas do mundo para as coordenadas oculares, defina a matriz da vista. Isso pode ser feito com algo parecido lookAt. O que essa matriz faz é "mover" o mundo para que a câmera esteja na origem e olhando para o eixo z.

Para calcular a matriz de vistas é surpreendentemente simples, você precisa fazer a transformação da câmera. Você basicamente precisa formular a seguinte matriz:

M=x[1 1]y[1 1]z[1 1]-p[1 1]x[2]y[2]z[2]-p[2]x[3]y[3]z[3]-p[3]0 00 00 01 1

Os vetores x, ye z podem ser obtidos diretamente da câmera. No caso de olhar, você os derivaria dos valores alvo, ocular (central) e superior. Igual a:

z=normumaeuEuze(eye-tumarget)x=normumaeuEuze(vocêp×z)y=zx

Mas se você tiver esses valores por aí, poderá aceitá-los como são.

Obter p é um pouco mais complicado. Não é a posição nas coordenadas do mundo, mas a posição nas coordenadas da câmera. Uma solução simples aqui é inicializar duas matrizes, uma com apenas x, ye z e a segunda com -eye e multiplicá-las. O resultado é a matriz da vista.

Para como isso pode parecer no código:

mat4 lookat(vec3 eye, vec3 target, vec3 up)
{
    vec3 zaxis = normalize(eye - target);    
    vec3 xaxis = normalize(cross(up, zaxis));
    vec3 yaxis = cross(zaxis, xaxis);     

    mat4 orientation(
       xaxis[0], yaxis[0], zaxis[0], 0,
       xaxis[1], yaxis[1], zaxis[1], 0,
       xaxis[2], yaxis[2], zaxis[2], 0,
         0,       0,       0,     1);

    mat4 translation(
              1,       0,       0, 0,
              0,       1,       0, 0, 
              0,       0,       1, 0,
        -eye[0], -eye[1], -eye[2], 1);

    return orientation * translation;
}

código completo

E, finalmente, por uma questão de integridade, você também tem o sistema de coordenadas do objeto. Este é o sistema de coordenadas em que as malhas são armazenadas. Com a ajuda da matriz do modelo, as coordenadas da malha são convertidas no sistema de coordenadas do mundo. Na prática, as matrizes de modelo e vista são combinadas na chamada matriz de vista de modelo.

rioki
fonte
11
Se eu pudesse votar essa resposta centenas de vezes, votaria. Obrigado por uma resposta completa e completa, abordando tudo o que eu estava confuso e fornecendo o código e o link também! Passei o dia todo lendo livros de matemática sobre esse assunto e com sua resposta e o código de exemplo e a página vinculada, se isso não for suficiente para eu descobrir isso, devo sair agora. Se eu pudesse pedir apenas um esclarecimento, nessa última amostra de código, eu estaria certo ao dizer que essas matrizes estão na ordem principal das colunas e a acima está na linha principal?
Grady
Isso é um pouco confuso, as matrizes são importantes na coluna, mas a coluna está na linha. Portanto, para mapear a matemática real para o código, você precisa transpor a matriz. Veja github.com/rioki/glm/blob/master/src/matrix.h#l72 Isso mapeia exatamente para o openGL e como seria se estivesse usando float[16].
Rioki 31/03
Ah, eu acho que sim, mas só queria ter certeza, obrigado novamente! Você tem sido uma grande ajuda, eu realmente aprecio isso.
Grady #