Computação Gráfica I

Trabalho Prático

Exercícios


4. Modelagem (cont)

Objetivo: O objetivo deste exercício é aprender como modelar formas complexas usando métodos simples baseados em perfis (de revolução e extrusão).

0. Introdução: plano simples

Antes de usar perfis, façamos algo mais simples: um plano com n x m secções de dois triângulos, conforme a figura abaixo.


Faremos isso proceduralmente, usando laços encadeados para criar n+1 x m+1 vértices. Depois, ligaremos os vértices para formarem triângulos. Como as estruturas de dados para representar vértices e triangulos na malha são unidimensionais (arrays 1D) e o plano forma uma figura bidimensional, a conversão dos índices pode se tornar absurdamente complexa. Para minimizar o problema, usaremos uma matriz (array 2D) intermediária para armazenar os índices dos vértices já na forma como serão usados na geração dos triângulos. Vejam a função geradora do plano abaixo.

void Mesh::criaPlano( int n, int m, float offset ){

     // inicializa as estruturas
     initVerts( (n+1) * (m+1) );
     initTris( n*m*2 );
    
     // aloca matriz intermediária
     int **mTemp = new int*[(n+1)];
     for( int i=0; i < n+1; i++) mTemp[i] = new int[m+1];

     // cria vertices
     for( int i=0; i < n+1; i++){
          for( int j=0; j < m+1; j++){

              
// cria as coordenadas dos vertices
               verts[i+j*(n+1)].x = i*offset;
               verts[i+j*(n+1)].y = j*offset;
               verts[i+j*(n+1)].z = 0;

               // cria cores aleatórias
               colors[i+j*(n+1)].r = rand() % 10 / 10.0;
               colors[i+j*(n+1)].g = rand() % 10 / 10.0;
               colors[i+j*(n+1)].b = rand() % 10 / 10.0;

               // carrega o índice na matriz
               mTemp[i][j] = i+j*(n+1);
          }
     }
    
     // cira triangulos ligando os vertices
     int     vv = 0;
     for( int i=0; i < n; i++){
          for( int j=0; j < m; j++){
               tris[vv].vert[0] = mTemp[i][j];
               tris[vv].vert[1] = mTemp[i][j+1];
               tris[vv].vert[2] = mTemp[i+1][j+1];
               vv++;
               tris[vv].vert[0] = mTemp[i][j];
               tris[vv].vert[1] = mTemp[i+1][j+1];
               tris[vv].vert[2] = mTemp[i+1][j];
               vv++;
          }
     }
    
}


Resultado:


1. Construção por revolução

Neste método, uma malha é gerada pela revolução de um perfl (contorno 2D) em torno de um eixo de revolução.

     

 

Definição do perfil

GLfloat jarra_2d[] =
{0,0,
3,0,
4,2,
4,5,
3,7,
1,9,
1,11,
3,13
};

Função geradora

//nbr_vertices: number of vertices of the profile
//profile[]: 2d array containing the vertices of the profile relatively to the revolution axis
//angle: extension angle (360 is a complete round)
//nbr_sections: number of sections for the mesh
//lath_mesh:
mesh to save to

void init_lathe(int nbr_vertices, GLfloat profile[], float angle, int nbr_sections, Mesh &lathe_mesh) {

int s, v, cur_vert=0, cur_tri=0;
Vertex vertex[4];
float theta1, theta2;

lathe_mesh.initVerts(nbr_sections*(nbr_vertices-1)*4);
lathe_mesh.initTris(nbr_sections*(nbr_vertices-1)*2);

for(s=0; s<nbr_sections; s++) {

   theta1 = (float)s*angle/nbr_sections*PI/180;
   theta2 = (float)(s+1)*angle/nbr_sections*PI/180;

   for(v=0; v<nbr_vertices-1; v++) {

      vertex[0].x = profile[v*2]*cos(theta1);
      vertex[0].y = profile[v*2+1];
      vertex[0].z = profile[v*2]*sin(theta1);

      vertex[1].x = profile[v*2+2]*cos(theta1);
      vertex[1].y = profile[v*2+3];
      vertex[1].z = profile[v*2+2]*sin(theta1);

      vertex[2].x = profile[v*2+2]*cos(theta2);
      vertex[2].y = profile[v*2+3];
      vertex[2].z = profile[v*2+2]*sin(theta2);

      vertex[3].x = profile[v*2]*cos(theta2);
      vertex[3].y = profile[v*2+1];
      vertex[3].z = profile[v*2]*sin(theta2);

      for (int i=0; i<4;i++) {
         lathe_mesh.verts[cur_vert+i] = vertex[i];
         lathe_mesh.colors[cur_vert+i].r = 1.0;
         lathe_mesh.colors[cur_vert+i].g = 0.7;
         lathe_mesh.colors[cur_vert+i].b = 0.5;
      }

      lathe_mesh.tris[cur_tri].vert[0] = cur_vert;
      lathe_mesh.tris[cur_tri].vert[1] = cur_vert+1;
      lathe_mesh.tris[cur_tri].vert[2] = cur_vert+2;

      lathe_mesh.tris[cur_tri+1].vert[0] = cur_vert+2;
      lathe_mesh.tris[cur_tri+1].vert[1] = cur_vert+3;
      lathe_mesh.tris[cur_tri+1].vert[2] = cur_vert;

      cur_vert += 4;
      cur_tri += 2;

   }

}


}

 

Exemplo de chamada

// Initialization of jar in init()

init_lathe(8, jar_2d, 360, 16, jar);

// in display function display()
glScalef(0.1,0.1,0.1);
drawMeshBoringAndSlow(jar);

 

Não esqueça os cabeçalhos e declarações:

#include "math.h"
#define PI 3.14159263
Mesh jar; // mesh for the constructed object

 

Dica

Testem suas criações com essa applet:
http://www.fi.uu.nl/toepassingen/00182/toepassing_wisweb.en.html

 

2. Construção por extrusão

Neste método, uma malha é construída pela extrusão de um perfil ao longo de um vetor.

 

Definição de um perfil e de um vetor de extrusão

GLfloat profile_2d[] =
{x1, y,
...
xn, yn
};


GLfloat extrusion_vector[] = {0,0,3};

 

Função geradora

void init_extrude(int nbr_vertices, GLfloat profile[], GLfloat vector[], Mesh &extrude_mesh) {

int v, cur_vert=0, cur_tri=0;

Vertex vertex[4];

extrude_mesh.initVerts((nbr_vertices-1)*4);
extrude_mesh.initTris((nbr_vertices-1)*2);

for(v=0; v<nbr_vertices-1; v++) {

    vertex[0].x = profile[v*2];
    vertex[0].y = profile[v*2+1];
    vertex[0].z = 0;

    vertex[1].x = profile[v*2+2];
    vertex[1].y = profile[v*2+3];
    vertex[1].z = 0;

    vertex[2].x = profile[v*2+2]+vector[0];
    vertex[2].y = profile[v*2+3]+vector[1];
    vertex[2].z = vector[2];

    vertex[3].x = profile[v*2]+vector[0];
    vertex[3].y = profile[v*2+1]+vector[1];
    vertex[3].z = vector[2];

    for (int i=0; i<4;i++) {
        extrude_mesh.verts[cur_vert+i] = vertex[i];
        extrude_mesh.colors[cur_vert+i].r = 1.0;
        extrude_mesh.colors[cur_vert+i].g = 0.7;
        extrude_mesh.colors[cur_vert+i].b = 0.5;
    }

    extrude_mesh.tris[cur_tri].vert[0] = cur_vert;
    extrude_mesh.tris[cur_tri].vert[1] = cur_vert+1;
    extrude_mesh.tris[cur_tri].vert[2] = cur_vert+2;

    extrude_mesh.tris[cur_tri+1].vert[0] = cur_vert+2;
    extrude_mesh.tris[cur_tri+1].vert[1] = cur_vert+3;
    extrude_mesh.tris[cur_tri+1].vert[2] = cur_vert;

    cur_vert += 4;
    cur_tri += 2;

}

}

 

Exemplo de chamada

Mesh extrude; // declaration of a mesh for the constructed object

init_extrude(8, jar_2d, extrusion_vector, extrude); //in init

// in display function display()
glScalef(0.1,0.1,0.1);
drawMeshBoringAndSlow(extrude);

 



Exercício:

1. Construam por revolução a jarra dos exemplos e os seguintes objetos. Tentem também outros objetos que acham úteis para criar uma cena para o projeto da disciplina.


Fig. 4 - Exemplo de objetos construídos por revolução/sweeping.

2. Construam por extrusão os seguintes objetos. Novamente, tentem modelar outros objetos que possam vir a ser úteis no projeto.


Fig. 5- Estrela, carro, texto "GL".

Obs.: como ainda não estamos aplicando métodos de sombreamento, seus objetos terão um aspecto "chapado", sem nuances de tonalidade como os das imagens acima. Resolveremos isso nas próximas aulas.