- Primeiro programa (again!)
- Sistemas de Coordenadas
- Clipping (recorte)
- Cores, Máquina de Estado e Interpolação
- Primitivas Geométricas
- Convenção de nomes do OpenGL
- Lista de exercícios 1
#include <GL/glew.h> // glew.h deve vir antes
#include <GL/freeglut.h> // do freeglut.h
// callback de desenho (display)
void desenhaMinhaCena() {
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0, 1, 0);
// desenha um POLYGON por seus vértices
glBegin(GL_POLYGON);
// NOVIDADE: antes os valores eram -0.5, 0.5
glVertex3f(20, 20, 0);
glVertex3f(80, 20, 0);
glVertex3f(80, 80, 0);
glVertex3f(20, 80, 0);
glEnd();
glFlush();
}
// NOVIDADE: uma função que vamos chamar dentro
// do "main"
// Inicia algumas variáveis de estado do OpenGL
void inicializa() {
// define qual é a cor do fundo
glClearColor(1, 1, 1, 1); // branco
// desenho preenchido vs. contorno
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
}
// NOVIDADE: callback para o evento "reshape"
void redimensionada(int width, int height) {
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 100, 0, 100, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
// NOVIDADE: callback de "keyboard"
void teclaPressionada(unsigned char key, int x, int y) {
// vê qual tecla foi pressionada
switch(key) {
case 27: // Tecla "ESC"
exit(0); // Sai da aplicação
break;
default:
break;
}
}
// função principal
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitContextVersion(1, 1);
glutInitContextProfile(GLUT_COMPATIBILITY_PROFILE);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
glutInitWindowSize(500, 500);
glutInitWindowPosition(100, 100);
glutCreateWindow("Hello World");
// registra callbacks para alguns eventos
glutDisplayFunc(desenhaMinhaCena);
glutReshapeFunc(redimensionada);
glutKeyboardFunc(teclaPressionada);
// configura valor inicial de algumas
// variáveis de estado do OpenGL
inicializa();
glutMainLoop();
return 0;
}
Exemplo: hello-world-callbacks
void desenhaMinhaCena() {
// 1. apaga o conteúdo da janela
glClear(GL_COLOR_BUFFER_BIT);
// 2. começa a usar a cor VERDE
glColor3f(0, 1, 0);
// 3. gera os vértices de um quadrado
glBegin(GL_POLYGON);
// NOVIDADE: antes os valores eram -0.5, 0.5
glVertex3f(20, 20, 0);
glVertex3f(80, 20, 0);
glVertex3f(80, 80, 0);
glVertex3f(20, 80, 0);
glEnd();
// 4. efetivamente desenha
glFlush();
}
// 3. gera os vértices de um quadrado
glBegin(GL_POLYGON);
// NOVIDADE: antes os valores
// eram -0.5, 0.5
glVertex3f(20, 20, 0); // vértice 0
glVertex3f(80, 20, 0); // v1
glVertex3f(80, 80, 0); // v2
glVertex3f(20, 80, 0); // v3
glEnd();
- Os "cantos" do quadrado estão especificados por 4 vértices entre
glBegin
eglEnd
- Para criar um vértice, usamos
glVertex3f
e passamos as suas coordenadas (x, y, z) como argumento - Mas qual é o sistema de coordenadas que estamos usando?
- Projeção ortogonal
- Volume de visualização
- Coordenadas do mundo
- Coordenadas da janela
- Recorte (clipping)
- O que os valores das coordenadas dos vértices significam?
- No vértice
(20, 20, 0)
, 20 está em mm, cm ou pixels?
- No vértice
- Experimento
- Alterar
glutInitWindowSize()
para os argumentos (300, 300) e depois (500, 250)
- Alterar
- Para entender o que as coordenadas representam, precisamos entender o
mecanismo de renderização do OpenGL
- Declaração da projeção sendo usada:
// left, right, bottom, top, near, far glOrtho(0, 100, 0, 100, -1, 1);
- Declaração da projeção sendo usada:
glOrtho(0, 100, 0, 100, -1, 1);
// Referência de glOrtho(...):
// glOrtho(left, right, bottom, top, near, far);
Documentação do OpenGL 2: https://www.opengl.org/sdk/docs/man2/
- É usado para definir a projeção ortogonal da cena
- Entenda como o "tamanho do mundo" - até onde as coisas aparecem
- Forma um cubo com lados alinhados aos eixos
left
atéright
no eixo Xbottom
atétop
no eixo Ynear
atéfar
no eixo Z
- Tudo que está dentro é desenhado, tudo que está fora é descartado
- Se
glOrtho(0, 100, 0, 100, -1, 1)
- vértice em
(0, 0, 0)
:↙️ - vértice em
(0, 100, 0)
:↖️
- vértice em
- Se
Repare onde estão os vértices do quadrado
dentro do cubo de visualização
// 3. gera os vértices de um quadrado
glBegin(GL_POLYGON);
// NOVIDADE: antes os valores
// eram -0.5, 0.5
glVertex3f(20, 20, 0); // vértice 0
glVertex3f(80, 20, 0); // v1
glVertex3f(80, 80, 0); // v2
glVertex3f(20, 80, 0); // v3
glEnd();
Passo 1 ~ "Fotografar" (a ➡️ b) ~ Objetos são projetados perpendicularmente na caixa de visualização (o plano próximo, ou near plane)
Passo 2 ~ "Revelar" (b ➡️ c) ~ O plano de visualização é escalado ("redimensionado") para caber na janela
- É o sistema de coordenadas definido via
glOrtho
(ouglFrustum
, para projeção perspectiva) - Tudo o que colocarmos na nossa cena deve ser definido nesse sistema de
coordenadas
- Em
hello-world.c
, nossa cena contém apenas os 4 vértices do quadrado - Mas poderia haver outros vértices com coordenadas "fora do mundo"
glVertex3f(300, 0, 0)
- Em
Trocar a caixa de visualização para:
glOrtho(-100, 100, -100, 100, −1, 1);
- Trocar o sistema de coordenadas pelos seguintes valores e testar
-
glOrtho( 0, 200, 0, 200, −1, 1); glOrtho(20, 80, 20, 80, −1, 1); glOrtho( 0, 100, 0, 100, −2, 5);
-
- Conclusões:
- Especificamos o sistema de coordenadas global
com
glOrtho
ouglFrustum
- A unidade de medida dos valores dos vértices é definida
pelo sistema de coordenadas:
(20, 20, 0)
não representa pixels!
- Especificamos o sistema de coordenadas global
com
- Trocar o sistema de coordenadas pelos seguintes valores e testar
- Experimento: trocar
glutInitWindowSize(500, 500)
porglutInitWindowSize(500, 250)
- Por que o quadrado deixou de ser quadrado?
- Como fazer com que ele continue quadrado ao redimensionar?
- Porque na fase de "impressão", o conteúdo da cena "fotografada" foi redimensionado para que fosse revelado
- Podemos fixar a tela de pintura (viewport)
...ou veja como fazer isso em de um jeito bacana em manter-razao-aspecto
glViewport(0, 0, 500, 500); // solução meh
- Sistema de coordenadas do mundo (
glOrtho
ouglFrustum
):- Um espaço 3D virtual em que criamos nossas cenas
- Unidade de medida: arbitrária
- Sistema de coordenadas da janela (
glViewport
):- Espaço 2D real onde as imagens "reveladas" são desenhadas
- Unidade de medida: pixel
- Alterar as coordenadas
z
de alguns vértices para [-1, 1]- Nada acontece visualmente
- Os vértices continuam dentro da caixa de visualização que definimos via
glOrtho
- Objetos fora do volume: descartados
- Objetos no meio do caminho: recortados
- Objetos dentro do volume: incluídos
- Vértices desenhados fora da caixa de visualização são descartados
- Experimento
- Desenhar um novo quadrado com os vértices abaixo
glBegin(GL_POLYGON); glVertex3f(120, 120, 0); glVertex3f(180, 120, 0); glVertex3f(180, 180, 0); glVertex3f(120, 180, 0); glEnd();
- Resultado: o novo quadrado não aparece porque foi descartado - todos seus
vértices estavam fora da caixa de visualização que definimos no
glOrtho
- Resultado: o novo quadrado não aparece porque foi descartado - todos seus
vértices estavam fora da caixa de visualização que definimos no
- Desenhar um novo quadrado com os vértices abaixo
- Experimento
- Redefinir nossa caixa de visualização para mostrar os dois quadrados
- Representar um triângulo, em vez de quadrado, e alterar o valor
z
para valores fora da caixa de visualização (e.g., -2.5, -5)
- Um algoritmo de clipping descartou o vértice que ficou de fora, mas criou
outros dois na interseção com o volume
- Algoritmos de line clipping:
- Cohen-Sutherland, 1967
- Lian-Barsky, 1984
- Algoritmos de polygon clipping:
- Sutherland-Hodgman, 1974
- Weiler-Atherton, 1977
- Algoritmos de line clipping:
-
A cor do quadrado é definida pelos três parâmetros da função
void desenha() { //.. glColor3f(1, 0, 0); //... desenha coisas em vermelho glColor3f(0, 0, 1); // ... desenha coisas em azul }
glColor3f
- RGB (vermelho, verde, azul)
- Os valores de cada componente são presos (clamped) entre
0
e1
:- Se menores que
0
então0
- Se maiores que
1.0
então1.0
- Se entre
0.0
e1.0
então usa o valor
- Se menores que
- A função
glColor3f(...)
altera a cor de pintura CORRENTE - Todos os vértices desenhados têm a cor da COR CORRENTE
- A COR CORRENTE muda apenas se chamarmos
glColor3f(...)
novamente - Este é um modelo de máquina de estados
- O OpenGL mantém o estado de coisas como cor, grossura das linhas, tamanho dos pontos etc.
- Outro exemplo:
glClearColor(...)
, que usamos dentro da nossa funçãosetup()
, é como alteramos a cor do fundo
<iframe src="../../samples/rgb-cube/index.html" width="100%" height="350" frameborder="0"></iframe>
- Preto:
glColor3f(0.0, 0.0, 0.0)
- Vermelho:
glColor3f(1.0, 0.0, 0.0)
- Verde:
glColor3f(0.0, 1.0, 0.0)
- Azul:
glColor3f(0.0, 0.0, 1.0)
- Amarelo:
glColor3f(1.0, 1.0, 0.0)
- Magenta:
glColor3f(1.0, 0.0, 1.0)
- Ciano:
glColor3f(0.0, 1.0, 1.0)
- Cinza:
glColor3f(0.6, 0.6, 0.6)
- Branco:
glColor3f(1.0, 1.0, 1.0)
- Alterar a cor do quadrado
- Desenhar um quadrado de cada cor
- Desenhar um quadrado de forma que cada vértice possua uma cor diferente
Que tipos de objetos podemos desenhar?
- São as construções geométricas que o OpenGL entende
- São os "tijolos" para construirmos objetos complexos
- Exemplos
- Pontos (
GL_POINTS
) - Linhas (
GL_LINES
) - Triângulos (
GL_TRIANGLES
)
- Pontos (
- Usamos como um argumento para
glBegin
. Por exemplo:glBegin(GL_POINTS); glVertex3f(x, y, z) // ... glEnd();
Do livro vermelho (online)
Do livro vermelho (online)
Primitiva | Descrição |
---|---|
GL_TRIANGLES |
Desenha uma série de triângulos usando os vértices v0, v1, v2, depois v3, v4, v5, e daí por diante. Se n não é um múltiplo de 3, o último ou os 2 últimos vértices são ignorados. |
GL_TRIANGLE_STRIP |
Desenha uma série de triângulos usando os vértices v0, v1, v2, depois v2, v1, v3 (repare na ordem), então v2, v3, v4 e daí por diante. A ordem é para assegurar que os triângulos estão todos desenhados com a mesma orientação de forma que a tira possa formar parte de uma superfície corretamente. Preservar a orientação é importante para algumas operações, como culling. |
GL_TRIANGLE_FAN |
Mesmo que GL_TRIANGLE_STRIP , exceto que os vértices são v0, v1, v2, depois v0, v2, v3, depois v0, v3, v4, e daí por diante. |
Do livro vermelho (online)
-
Desenhar pontos (
GL_POINTS
) em vez de quadrados. Para que os pontos fiquem visíveis, aumentar seu tamanho usandoglPointSize()
. -
Usar outras primitivas:
GL_LINES, GL_LINE_STRIP, GL_LINE_LOOP
- Estávamos desenhando polígonos preenchidos até agora
- Mas podemos querer desenhar apenas a sua silhueta (contorno)
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); // ou GL_FILL
- Assinatura da função:
glPolygonMode(faces, modo);
faces
:GL_FRONT
,GL_BACK
ouGL_FRONT_AND_BACK
modo
:GL_FILL
(padrão, para preencher) ouGL_LINE
(contorno)
- Documentação do
glPolygonMode
- Assinatura da função:
- Alterar a forma de desenho das primitivas
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); //GL_FILL
e a primitiva para
glBegin( GL_TRIANGLE_STRIP );
...
- Notas:
glVertex2f(x, y)
=glVertex3f(x, y, 0)
glColor
é análogo- mas não há cores com apenas 2 componentes (i.e.,
glColor2f
)
- mas não há cores com apenas 2 componentes (i.e.,
Link via Moodle
- Documentação do OpenGL 2: https://www.opengl.org/sdk/docs/man2/
- Livro Vermelho: http://www.glprogramming.com/red/