A apresentação está carregando. Por favor, espere

A apresentação está carregando. Por favor, espere

Desenhos Tridimensionais

Apresentações semelhantes


Apresentação em tema: "Desenhos Tridimensionais"— Transcrição da apresentação:

1 Desenhos Tridimensionais

2 Primitivas Gráficas em 3D
A forma de representação de objetos 3D mais utilizada em computação gráfica consiste na especificação de uma malha de faces poligonais. Uma superfície discretizada por faces planas que podem ser triângulos (preferencialmente) ou quadrados com tabela de vértices e tabela de faces.

3 A utilização de primitivas gráficas em três e duas dimensões é praticamente igual. A principal diferença está na especificação dos vértices , pois em 3 dimensões deve-se atribuir um valor para a coordenada Z. Qualquer uma das primitivas gráficas podem ser utilizadas quando se está trabalhando em 3 dimensões.

4 Implementação de um objeto
A primeira providência é definir algumas estruturas para armazenar vértices e faces. A estrutura de vértices é simplesmente uma coordenada 3D: // Define um vértice typedef struct { float x,y,z; // posição no espaço } VERT;

5 Já na estrutura de faces é preciso armazenar o total de vértices sendo utilizados por cada uma e um outro vetor, que contém os índices para cada vértice. (Triângulos e Quadriláteros) // Define uma face typedef struct { int total; // total de vértices int ind[4]; // índices para o vetor de vértices } FACE;

6 A última estrutura é para representar um objeto – aqui se guardam apontadores para o vetor de vértices, para o vetor de faces e também a quantidade de faces, uma vez que essa informação não existe em nenhum outro local: // Define um objeto 3D typedef struct { VERT *vertices; // aponta para os vértices FACE *faces; // aponta para as faces int total_faces; // total de faces no objeto } OBJ;

7 Vetor de vértice // Definição dos vértices VERT vertices[ ] = {
{ -1, 0, -1 }, // 0 canto inf esquerdo tras. { 1, 0, -1 }, // 1 canfo inf direito tras. { 1, 0, 1 }, // 2 canto inf direito diant. { -1, 0, 1 }, // 3 canto inf esquerdo diant. { 0, 2, 0 }, // 4 topo };

8 Vetor de Faces // Definição das faces FACE faces[] = {
{ 4, { 0,1,2,3 }}, // base { 3, { 0,1,4,-1 }}, // lado traseiro { 3, { 0,3,4,-1 }}, // lado esquerdo { 3, { 1,2,4,-1 }}, // lado direito { 3, { 3,2,4,-1 }} // lado dianteiro };

9 Definição do Objeto // Finalmente, define o objeto pirâmide
OBJ piramide = { vertices, faces, 5 };

10 Por que fazer tudo isso?

11 Faces diretamente no código?
- Separar o modelo 3D do código que desenha o mesmo; * Se trocar o modelo não será necessário modificar o código. Eficiência no armazenamento: se substituirmos as estruturas por um conjunto de chamadas de desenho, potencialmente vários vértices serão repetidamente informados.

12 Pirâmide: Cada vértice é compartilhado por pelo menos três faces. Isso também criaria um problema considerável no caso da necessidade de alterar o modelo: todas as ocorrências de cada vértice teriam que ser modificadas.

13 Função: Partindo dessas razões, escrevemos uma função que recebe um objeto genérico, indicado por sua estrutura devidamente preenchida, e traça o contorno de todas as suas faces (usando GL_LINE_LOOP):

14 // Desenha um objeto em wireframe
void DesenhaObjetoWireframe(OBJ *objeto) { OBJ *obj = objeto; // Percorre todas as faces for(int f=0; f < obj->total_faces; ++f) glBegin(GL_LINE_LOOP); // Percorre todos os vértices da face for(int v=0; v < obj->faces[f].total; ++v) glVertex3f(obj->vertices[faces[f].ind[v]].x, obj->vertices[faces[f].ind[v]].y, obj->vertices[faces[f].ind[v]].z); } glEnd();

15 Para desenhar um objeto, basta agora chamar a função “DesenhaObjetoWireframe” e passar um apontador para o objeto desejado (se houver mais de um). Isso é feito na função callback de desenho:

16 // Função callback de redesenho da janela de visualização
void Desenha(void) { // Limpa a janela de visualização com a cor // de fundo definida previamente glClear(GL_COLOR_BUFFER_BIT); // Altera a cor do desenho para preto glColor3f(0.0f, 0.0f, 0.0f); // Desenha o objeto definido anteriormente: uma pirâmide DesenhaObjetoWireframe(&piramide); // Executa os comandos OpenGL glFlush(); }

17 Este exemplo também introduz um conceito muito importante: comandos de navegação, que serão incluidos em quase todos os demais códigos, como segue: - Movimento do mouse: botões esquerdo, direito e centro. - Teclas Home e End

18 A implementação desses comandos é realizada em funções diferentes: para rotacionar o objeto, utilizam-se duas variáveis – rotX e rotY - que são empregados na função que posiciona o observador (PosicionaObservador). Nessa mesma função também se empregam as variáveis obsX, obsY e obsZ, que informam a posição do objeto em relação ao observador.

19 // Função usada para especificar a posição do observador virtual
void PosicionaObservador(void) { // Especifica sistema de coordenadas do modelo glMatrixMode(GL_MODELVIEW); // Inicializa sistema de coordenadas do modelo glLoadIdentity(); // Posiciona e orienta o observador glTranslatef(-obsX,-obsY,-obsZ); glRotatef(rotX,1,0,0); glRotatef(rotY,0,1,0); }

20 Ângulo de Visão Já o ângulo de visão (variável angle) é empregada na função EspecificaParametrosDeVisualizacao:

21 // Função usada para especificar o volume de visualização
void EspecificaParametrosVisualizacao(void) { // Especifica sistema de coordenadas de projeção glMatrixMode(GL_PROJECTION); // Inicializa sistema de coordenadas de projeção glLoadIdentity(); // Especifica a projeção perspectiva(angulo,aspecto,zMin,zMax) gluPerspective(angle,fAspect,0.1,1200); PosicionaObservador(); }

22 Callbacks de mouse // Função callback para eventos de botões do mouse
void GerenciaMouse(int button, int state, int x, int y) { if(state==GLUT_DOWN) // Salva os parâmetros atuais x_ini = x; y_ini = y; obsX_ini = obsX; obsY_ini = obsY; obsZ_ini = obsZ; rotX_ini = rotX; rotY_ini = rotY; bot = button; } else bot = -1;

23 Durante o movimento em si, a GLUT chama a função GerenciaMovim, a qual recebe as coordenadas atualizadas do mouse. Primeiramente, determina-se qual botão foi pressionado: se foi o botão esquerdo, calculam-se as diferenças (em X e Y) entre a posição atual e a inicial (salva na função GerenciaMouse), e atualizamos as variáveis que controlam a rotação do objeto. A constante SENS_ROT, definida antes da função, permite especificar a sensibilidade do movimento: quanto maior o valor, mais o mouse terá que ser deslocado para afetar a rotação.

24 // Função callback para eventos de movimento do mouse
#define SENS_ROT 5.0 #define SENS_OBS 15.0 #define SENS_TRANSL 30.0 void GerenciaMovim(int x, int y) { // Botão esquerdo ? if(bot==GLUT_LEFT_BUTTON) // Calcula diferenças int deltax = x_ini - x; int deltay = y_ini - y; // E modifica ângulos rotY = rotY_ini - deltax/SENS_ROT; rotX = rotX_ini - deltay/SENS_ROT; }

25 No segundo trecho, trata-se o botão direito: nesse caso, basta calcular a diferença apenas em Y e atualizar a variável obsZ. É utilizada outra constante, SENS_OBS, também para definira sensibilidade do movimento:

26 // Botão direito ? else if(bot==GLUT_RIGHT_BUTTON) { // Calcula diferença int deltaz = y_ini - y; // E modifica distância do observador obsZ = obsZ_ini + deltaz/SENS_OBS; }

27 Por fim, o último trecho considera o botão do meio: o processo é praticamente o mesmo do primeiro trecho, mas atualizam-se as variáveis que controlam a translação em X e Y: obsX e obsY. Porém, note que as diferenças são somadas em X, mas subtraídas em Y, de modo que se o mouse for deslocado para baixo, o objeto também será movido na mesma direção. A constante de sensibilidade empregada aqui é denominada SENS_TRANSL:

28 // Botão do meio ? else if(bot==GLUT_MIDDLE_BUTTON) { // Calcula diferenças int deltax = x_ini - x; int deltay = y_ini - y; // E modifica posições obsX = obsX_ini + deltax/SENS_TRANSL; obsY = obsY_ini - deltay/SENS_TRANSL; } PosicionaObservador(); glutPostRedisplay();


Carregar ppt "Desenhos Tridimensionais"

Apresentações semelhantes


Anúncios Google