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