Por que o sinal é importante na matriz de projeção OpenGL
-
21-09-2019 - |
Pergunta
Estou trabalhando em um problema de visão computacional que requer renderizar um modelo 3D usando uma câmera calibrada. Estou escrevendo uma função que quebra a matriz da câmera calibrada em uma matriz de ModelView e uma matriz de projeção, mas encontrei um fenômeno interessante no OpenGL que desafia a explicação (pelo menos por mim).
A breve descrição é que negar a matriz de projeção resulta em nada sendo renderizado (pelo menos na minha experiência). Eu esperaria que multiplicar a matriz de projeção por qualquer escalar não tivesse efeito, porque transforma coordenadas homogêneas, que não são afetadas pela escala.
Abaixo está o meu raciocínio por que acho que isso é inesperado; Talvez alguém possa apontar onde meu raciocínio é falho.
Imagine a seguinte matriz de projeção de perspectiva, que fornece resultados corretos:
[ a b c 0 ]
P = [ 0 d e 0 ]
[ 0 0 f g ]
[ 0 0 h 0 ]
Multiplicar isso por coordenadas da câmera fornece coordenadas de clipes homogêneas:
[x_c] [ a b c 0 ] [X_e]
[y_c] = [ 0 d e 0 ] * [Y_e]
[z_c] [ 0 0 f g ] [Z_e]
[w_c] [ 0 0 h 0 ] [W_e]
Finalmente, para obter coordenadas de dispositivos normalizadas, dividimos x_c, y_c e z_c por w_c:
[x_n] [x_c/w_c]
[y_n] = [y_c/w_c]
[z_n] [z_c/w_c]
Agora, se negarmos P, as coordenadas de clipes resultantes devem ser negadas, mas como são coordenadas homogêneas, a multiplicação por qualquer escalar (por exemplo -1) não deve afetar as coordenadas de dispositivo normalizado resultante. No entanto, no OpenGL, negando p resulta em nada sendo renderizado. Eu posso multiplicar P por qualquer escalar não negativo e obter exatamente os mesmos resultados renderizados, mas assim que multiplico por um escalar negativo, nada se torna. O que está acontecendo aqui??
Obrigado!
Solução
Bem, a essência é que o teste de recorte é feito através de:
-w_c < x_c < w_c
-w_c < y_c < w_c
-w_c < z_c < w_c
Multiplicar por um valor negativo quebra este teste.
Outras dicas
Acabei de encontrar este boato, que faz progredir em direção a uma resposta:
Do Red Book, Apêndice G:
Evite usar coordenadas negativas de vértices W e coordenadas de textura Q negativa. O OpenGL pode não prender essas coordenadas corretamente e pode cometer erros de interpolação quando as primitivas de sombreamento definidas por essas coordenadas.
Inverter a matriz de projeção resultará em coordenadas negativas de recorte W e, aparentemente, o OpenGL não gosta disso. Mas alguém pode explicar por que o OpenGL não lida com esse caso?
referência: http://glprogramming.com/red/appendixg.html
Razões pelas quais posso pensar:
- Ao inverter a matriz de projeção, as coordenadas não estarão mais nos seus planos Znear e Zfar da vista frustum (necessariamente maior que 0).
- Para criar coordenadas de janela, as coordenadas de dispositivo normalizadas são traduzidas/escalonadas pela viewport. Portanto, se você usou um escalar negativo para as coordenadas do clipe, as coordenadas de dispositivos normalizadas (agora invertidas) traduzem a viewport para coordenadas de janelas que estão ... fora da sua janela (à esquerda e abaixo, se você quiser)
Além disso, desde que você mencionou o uso de uma matriz de câmera e que você inverteu a matriz de projeção, tenho que perguntar ... a quais matrizes você está aplicando o que da matriz da câmera? Operar na matriz de projeção Salvar próximo/distante/fovy/aspecto causa todos os tipos de problemas no buffer de profundidade, incluindo qualquer coisa que use Z (teste de profundidade, abate de face, etc.).
A seção de perguntas frequentes do OpenGL em Transformações tem mais alguns detalhes.