- Entender a transformação de uma cena em 3D para 2D
- Conhecer as matrizes de projeção ortogonal e perspectiva
- Entender o funcionamento da projeção em OpenGL
- Transformações de projeção são aquelas capazes de representar pontos ou objetos a partir de um espaço tridimensional (uma cena) em um plano bidimensional (uma imagem).
- Trata-se de (i) transformar o volume de visualização no volume
de visualização canônico (cubo com raio 1) e (ii) guardar as coordenadas
z dos vértices no z-buffer
::: figure .layout-split-2.no-margin
:::
- Essa transformação é feita por meio de uma matriz que vai multiplicar as coordenadas dos vértices, assim como as outras transformações que vimos
Plano de projeção:
- Definido pelo sistema de coordenadas da câmera
- Raios de projeção:
- Ligam um ponto no espaço 3D à imagem 2D representada no plano de projeção
- Centro de projeção:
- Ponto fixo na cena de onde todos os raios de projeção surgem
-
Centro de projeção se encontra no infinito
- Raios de projeção são paralelos entre si
- Tamanho relativo em cada eixo é preservado
- Linhas paralelas permanecem paralelas
- Existem subtipos de projeção paralela em que o ângulo de incidência dos raios de projeção varia
- Projeção ortogonal
- Ângulo dos raios no plano de projeção = 90º
::: figure .layout-split-2.no-margin
void glOrtho(double left, //l
double right, //r
double bottom,//b
double top, //t
double near, //n
double far); //f
::: figure .layout-split-3.hello-world-code.compact-code
// define a projeção
glOrtho(0, 100, 0, 100, -1, 1);
// ...
// desenha
glBegin(GL_TRIANGLE_STRIP);
glVertex3f(20, 20, 0);//v0
glVertex3f(80, 20, 0);//v1
glVertex3f(80, 80, 0);//v2
glVertex3f(20, 80, 0);//v3
glEnd();
::: figure .no-margin flex: 1; display: flex; flex-direction: column; justify-content: flex-start; font-size: 15px;
::: figure .picture-steps.clean.opacity-only padding: 0; align-self: center; font-size: 16px;
::: figure . align-self: center; font-size: 14px; margin: 3em 0 0 16em
- Se você não definir uma projeção, existe a matriz identidade previamente carregada
- Isso é equivalente a
glOrtho(-1, 1, -1, 1, -1, 1)
(exceto pelo -1): ::: figure .no-margin display: flex; flex-direction: row; justify-content; center\begin{bmatrix} \frac{2}{r-l} & 0 & 0 & -\frac{r+l}{r-l} \\ 0 & \frac{2}{t-b} & 0 & -\frac{t+b}{t-b} \\ 0 & 0 & \frac{-2}{f-n} & -\frac{f+n}{f-n} \\ 0 & 0 & 0 & 1 \end{bmatrix}=\begin{bmatrix} \frac{2}{1+1} & 0 & 0 & -\frac{1-1}{1+1} \\ 0 & \frac{2}{1+1} & 0 & -\frac{1-1}{1+1} \\ 0 & 0 & \frac{-2}{1+1} & -\frac{1-1}{1+1} \\ 0 & 0 & 0 & 1 \end{bmatrix}=\begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & -1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}:::
::: figure .full-width display:flex; justify-content: space-around;
:::
O OpenGL nos permite trabalhar right-handed
mas ele projeta num sistema left-handed
- A cena é orientada em 45º relativo ao plano de projeção
- Também podemos usar
glOrtho
, mas vamos precisar "movimentar a câmera" usandogluLookAt
(veremos logo mais)
A projeção perspectiva mapeia os pontos no plano de projeção ao longo dos raios de projeção que emanam de um centro de projeção
- Características:
- Objetos mais próximos ao plano de projeção são maiores
- Linhas paralelas se encontram em pontos de fuga
- Aparência semelhante ao modelo do nosso olho
Façamos uma breve digressão...
- Um objeto tridimensional é formado por várias faces (polígonos) adjacentes que podem estar no mesmo plano ou não
Para desenhar um cubo em vez de um quadrado, basta desenhar 6 faces em vez de 1
glBegin(GL_QUADS);
// Cima (y = +1)
glVertex3f( 1, 1, -1); glVertex3f(-1, 1, -1);
glVertex3f(-1, 1, 1); glVertex3f( 1, 1, 1);
// Baixo (y = -1)
glVertex3f( 1, -1, 1); glVertex3f(-1, -1, 1);
glVertex3f(-1, -1, -1); glVertex3f( 1, -1, -1);
// Direita (x = +1)
// ...
:::
-
O FreeGLUT possui algumas funções para desenho de objetos tridimensionais:
::: figure .layout-split-2.full-width
- Voltando ao tema de hoje...
glFrustum (referência)
- Assinatura da função:
void glFrustum(double left, double right, double bottom, double top, double near, double far);
near
efar
devem ser positivos enear
<far
-
\begin{bmatrix} \frac{2n}{r-l} & 0 & \frac{r+l}{r-l} & 0 \\ 0 & \frac{2n}{t-b} & \frac{t+b}{t-b} & 0 \\ 0 & 0 & \frac{f+n}{f-n} & \frac{2fn}{f-n} \\ 0 & 0 & -1 & 0 \end{bmatrix}
glFrustum
multiplica a matriz corrente por uma matriz da forma ➡️glFrustum(left, right, // l, r bottom, top, // b, t near, far); // n, f
-
Lembre-se: a matriz de projeção (
glOrtho
ouglFrustum
) deve ser colocada na pilha de matrizes de projeção do OpenGL:glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-1, 1, -1, 1, 1, 20);
- Pressionar barra de espaço para alternar de projeção perspectiva para ortogonal
gluPerspective
(referência)
- Não é muito intuitivo configurar a perspectiva usando
glFrustum
- Uma forma mais comum para configurar perspectiva é usando dois parâmetros:
- Um ângulo para o campo de visão
- Razão de aspecto (largura / altura)
- A biblioteca GLU (OpenGL Utilities) contém uma função para isso, o
gluPerspective
:glMatrixMode(GL_PROJECTION); glLoadIdentity(); // fovy, aspectRatio, nearZ, farZ gluPerspective(45.0f, 4.0f/3.0f, 1, 20);
- O
gluPerspective
substitui o uso deglFrustum
, já que ele gera uma matriz de transformação perspectiva da mesma forma, porém usando outros tipos de parâmetros - Campo de visão (fov, ou field of view)
- Determina o quanto queremos enxergar da cena
- Para aplicações interativas, tipicamente algo entre 45º e 60º
- Calculada pela divisão da largura pela altura
- Deve ser a mesma razão de aspecto da janela/tela em que estamos desenhando para que não haja distorção
-
Além de configurar a projeção que queremos (via
glOrtho, glFrustum, gluPerspective
), queremos também poder posicionar e mirar nossa câmera virtual -
É uma transformação de visualização - ou seja, usamos a pilha de matrizes
GL_MODELVIEW
void gluLookAt(double eyeX, eyeY, eyeZ // posição do olho
double centerX, centerY, centerZ // para onde olhamos
double upX, upY, upZ); // onde fica "para cima"
- A transformação de visualização deve acontecer ANTES das transformações
de modelo
- Ou seja,
gluLookAt(...)
deve ser chamada na funçãodesenhaCena
antes de começarmos a desenhar os objetos da cena
- Ou seja,
- FAQ sobre visualização em OpenGL (excelente leitura)
- Capítulo 3 do livro Real-Time Rendering
- Lições 5 e 8 das anotações do prof. David Mount