- Primeiro programa
- Sistemas de coordenadas
- Clipping (recorte)
- Cores
- Primitivas geométricas
- 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:
- Como especificar cores
- Variável de estado: cor
- Interpolação de cores
void desenha() {
//..
glColor3f(1, 0, 0);
//... desenha coisas em vermelho
glColor3f(0, 0, 1);
// ... desenha coisas em azul
}
- A cor do quadrado é definida pelos três parâmetros da função
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?
- Objetos geométricos que o OpenGL entende
- São os "tijolos" para construirmos objetos mais complexos
- Usamos como um argumento para
glBegin
. Por exemplo:glBegin(GL_POINTS); glVertex3f(x, y, z) // ... glEnd();
- Exemplos
- Pontos (
GL_POINTS
) - Linhas (
GL_LINES
) - Triângulos (
GL_TRIANGLES
)
- Pontos (
GL_POINTS
~ Desenha um ponto para cada vértice n.
GL_LINES
~ Desenha uma série de segmentos de linha desconectados. São
desenhados entre v_0 e
v_1, v_2 e
v_3, v_3 e
v_4 e
daí em diante. Se n é ípmar, o último
vértice não faz parte de um segmento.
GL_LINE_STRIP
~ Desenha um segmento de v_0 a
v_1, então de
v_1 a v_2 e daí por
diante, desenhando o segmento v_{n-2}
para v_{n-1}. Então, um total de
n-1 segmentos são desenhados.
GL_LINE_LOOP
~ Mesmo que GL_LINE_STRIP
, exceto que um segmento final é desenhado
de v_{n-1} até v_0,
completando o circuito.
GL_TRIANGLES
~ Desenha uma série de triângulos usando os vértices
v_0, v_1,
v_2, depois v_3,
v_4, v_5, 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
v_0, v_1, v_2, depois
v_2, v_1, v_3
(repare na ordem), então v_2, v_3, v_4,
e daí por diante. A ordem é para assegurar que os triângulos estão
todos desenhados com a mesma orientação.
GL_TRIANGLE_FAN
~ Mesmo que GL_TRIANGLE_STRIP
, exceto que os vértices são
v_0, v_1, v_2, depois
v_0, v_2, v_3, depois
v_0, v_3, v_4 e daí por diante.
~ Desenha uma série de quadriláteros de forma análoga a GL_QUADS
GL_TRIANGLES
.
~ Desenha uma série de quadriláteros começando com
v_0, v_1, v_3, v_2, então
v_2, v_3, v_5, v_4, depois
v_4, v_5, v_7, v_6 e daí por diante.GL_QUAD_STRIP
~ Desenha um polígono usando os pontos v_0,...,v_n
como vértices. n deve ser pelo menos 3, ou
nada é desenhado. Ademais, o polígono especificado não deve se
auto-intersectar e deve ser convexo. Se os vértices não
satisfazerem essas condições, os resultados são imprevisíveis.GL_POLYGON
- 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 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
e a primitiva para
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); //GL_FILL
glBegin(GL_TRIANGLE_STRIP); ... glEnd();
- 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/