Skip to content

Latest commit

 

History

History
580 lines (463 loc) · 23.8 KB

README-old.md

File metadata and controls

580 lines (463 loc) · 23.8 KB

Introdução a OpenGL hands on

Sistemas de coordenadas, cores e primitivas geométricas


Roteiro

  1. Primeiro programa (again!)
  2. Sistemas de Coordenadas
  3. Clipping (recorte)
  4. Cores, Máquina de Estado e Interpolação
  5. Primitivas Geométricas
  6. Convenção de nomes do OpenGL
  7. Lista de exercícios 1

Primeiro programa

Tela do programa quadrado


O código fonte, um pouco maior

#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


Apenas a função de desenho

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();
}

Apenas o pedaço que desenha

// 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();

glBegin e glEnd

  • Os "cantos" do quadrado estão especificados por 4 vértices entre glBegin e glEnd
  • 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?

Sistemas de coordenadas 2 Sistemas de coordenadas 1


Sistemas de coordenadas

  • Projeção ortogonal
  • Volume de visualização
  • Coordenadas do mundo
  • Coordenadas da janela
  • Recorte (clipping)

Projeção ortogonal

  • O que os valores das coordenadas dos vértices significam?
    • No vértice (20, 20, 0), 20 está em mm, cm ou pixels?
  • Experimento
    • Alterar glutInitWindowSize() para os argumentos (300, 300) e depois (500, 250)
  • Para entender o que as coordenadas representam, precisamos entender o mecanismo de renderização do OpenGL

Projeção ortogonal (cont.)

Exemplo de projeção ortogonal


glOrtho - definindo a projeção a ser 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

glOrtho - o tamanho do mundo

  • Forma um cubo com lados alinhados aos eixos
    • left até right no eixo X
    • bottom até top no eixo Y
    • near 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): ↖️

O volume de visualização do hello-world.c

Repare onde estão os vértices do quadrado
dentro do cubo de visualização


Código que desenha

// 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 2 Passos para renderização

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


Sistema de coordenadas global ou "do mundo"

  • É o sistema de coordenadas definido via glOrtho (ou glFrustum, 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)

Experimento:

Trocar a caixa de visualização para:

glOrtho(-100, 100, -100, 100, −1, 1);

Resultado do experimento

  • Mais experimentos:

    • Trocar o sistema de coordenadas pelos seguintes valores e testar
      1. glOrtho( 0, 200,  0, 200, −1, 1);
        glOrtho(20,  80, 20,  80, −1, 1);
        glOrtho( 0, 100,  0, 100, −2, 5);
    • Conclusões:
      1. Especificamos o sistema de coordenadas global com glOrtho ou glFrustum
      2. A unidade de medida dos valores dos vértices é definida pelo sistema de coordenadas: (20, 20, 0) não representa pixels!

Sistema de coordenadas da janela

  • Experimento: trocar glutInitWindowSize(500, 500) por glutInitWindowSize(500, 250)
    1. Por que o quadrado deixou de ser quadrado?
    2. Como fazer com que ele continue quadrado ao redimensionar?
  1. Porque na fase de "impressão", o conteúdo da cena "fotografada" foi redimensionado para que fosse revelado
  2. Podemos fixar a tela de pintura (viewport)
    glViewport(0, 0, 500, 500);  // solução meh
    ...ou veja como fazer isso em de um jeito bacana em manter-razao-aspecto

Os 02 sistemas de coordenadas

  • Sistema de coordenadas do mundo (glOrtho ou glFrustum):
    • 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

Experimento com a coordenada z

  1. 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

Clipping (recorte)

  • Objetos fora do volume: descartados
  • Objetos no meio do caminho: recortados
  • Objetos dentro do volume: incluídos

Clipping (Recorte)

  • 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

Clipping (Recorte)

  • Experimento
    1. Redefinir nossa caixa de visualização para mostrar os dois quadrados
    2. 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)

O que aconteceu?

  • 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:
      1. Cohen-Sutherland, 1967
      2. Lian-Barsky, 1984
    • Algoritmos de polygon clipping:
      1. Sutherland-Hodgman, 1974
      2. Weiler-Atherton, 1977

Cores e Primitivas Geométricas


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 e 1:
    • Se menores que 0 então 0
    • Se maiores que 1.0 então 1.0
    • Se entre 0.0 e 1.0 então usa o valor

OpenGL é uma máquina de estados

  • 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ção setup(), é como alteramos a cor do fundo

Valores RGB de algumas cores

<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)

Experimento com cores

  1. Alterar a cor do quadrado
  2. Desenhar um quadrado de cada cor
  3. Desenhar um quadrado de forma que cada vértice possua uma cor diferente

Primitivas Geométricas

Que tipos de objetos podemos desenhar?


Primitivas Geométricas

  • São as construções geométricas que o OpenGL entende
  • São os "tijolos" para construirmos objetos complexos
  • Exemplos
    1. Pontos (GL_POINTS)
    2. Linhas (GL_LINES)
    3. Triângulos (GL_TRIANGLES)
  • Usamos como um argumento para glBegin. Por exemplo:
    glBegin(GL_POINTS);
        glVertex3f(x, y, z)
        // ...
    glEnd();



Do livro vermelho (online)

Primitiva Descrição
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 v0 e v1, v2 e v3, v3 e v4 e daí em diante. Se n é ímar, o último vértice não faz parte de um segmento.
GL_LINE_STRIP Desenha um segmento de v0 a v1, então de v1 a v2 e daí por diante, desenhando o segmento vn-2 para vn-1. Então, um total de n-1 segmentos são desenhados. Nada é desenhado a menos que n seja maior que 1.
GL_LINE_LOOP Mesmo que GL_LINE_STRIP, exceto que um segmento final é desenhado de vn-1 até v0, completando o circuito.

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)

Primitiva Descrição
GL_QUADS Desenha uma série de quadriláteros de forma análoga a GL_TRIANGLES.
GL_QUAD_STRIP Desenha uma série de quadrilátores começando com v0, v1, v3, v2, então v2, v3, v5, v4, depois v4, v5, v7, v6 e daí por diante. n deve ser pelo menos 4 antes que algo seja desenhado. Se n é ímpar, o último vértice será ignorado.
GL_POLYGON Desenha um polígono usando os pontos v0, ... , vn-1 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.

Experimentos com as primitivas

  1. Desenhar pontos (GL_POINTS) em vez de quadrados. Para que os pontos fiquem visíveis, aumentar seu tamanho usando glPointSize().

  2. Usar outras primitivas: GL_LINES, GL_LINE_STRIP, GL_LINE_LOOP


Preenchimento

  • 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 ou GL_FRONT_AND_BACK
      • modo: GL_FILL (padrão, para preencher) ou GL_LINE (contorno)
    • Documentação do glPolygonMode

Experimento com tipo de preenchimento

  1. Alterar a forma de desenho das primitivas
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );  //GL_FILL

e a primitiva para

glBegin( GL_TRIANGLE_STRIP );
    ...

Convenção de nomes do OpenGL


  • Notas:
    • glVertex2f(x, y) = glVertex3f(x, y, 0)
    • glColor é análogo
      • mas não há cores com apenas 2 componentes (i.e., glColor2f)

Lista de exercícios 1

Link via Moodle


Referências