Exercício
IV (2014/1)
Disciplina:
Computação Gráfica
Professora: Soraia R. Musse
Pos
Doc: Leandro Dihl
Aula
prática – Movimentação de Objetos 3D
O objetivo desta aula é aprender aplicar transformações geométricas em
objetos 3D usando OpenGL.
As transformações geométricas são usadas para manipular
um modelo, isto é, através delas é possível mover, rotacionar
ou alterar a escala de um objeto. A aparência final da cena ou do objeto
depende muito da ordem na qual estas transformações são aplicadas.
A biblioteca gráfica OpenGL é
capaz de executar transformações de translação, escala e rotação através de uma
multiplicação de matrizes. A idéia central destas
transformações em OpenGL é que elas podem ser
combinadas em uma única matriz, de tal maneira que várias transformações
geométricas possam ser aplicadas através de uma única operação.
Isto ocorre porque uma transformação geométrica em OpenGL é armazenada internamente em uma matriz. A cada
transformação que é aplicada, esta matriz é alterada e usada para desenhar os
objetos a partir daquele momento. A cada nova alteração é feita uma composição
de matrizes. Para evitar este efeito "cumulativo", é necessário
utilizar as funções glPushMatrix() e glPopMatrix(), que salvam e
restauram, respectivamente, a matriz atual em uma pilha interna da OpenGL.
A translação é feita através da função glTranslatef(Tx, Ty, Tz),
que pode receber três números float ou double (glTranslated) como
parâmetro. Neste caso, a matriz atual é multiplicada por uma matriz de
translação baseada nos valores dados.
A rotação é feita através da função glRotatef(Ângulo, x, y, z),
que pode receber quatro números float ou double (glRotated) como
parâmetro. Neste caso, a matriz atual é multiplicada por uma matriz de rotação
de "Ângulo" graus ao redor do eixo definido pelo vetor "x,y,z" no sentido anti-horário.
A escala é feita através da função glScalef(Ex,
Ey, Ez), que pode receber
três números float ou double
(glScaled) como parâmetro. Neste caso, a matriz atual
é multiplicada por uma matriz de escala baseada nos valores dados.
Iremos aprender a movimentar um objeto 3D usando as
teclas especiais ç
e è. Depois
utilizaremos um Timer para fazer a animação automática de um objeto 3D.
Clicando AQUI, você pode obter os códigos fontes
que serão utilizados na aula de hoje.
Inicialmente,
verifique o conteúdo do programa fonte fornecido.
MOVIMENTAÇÃO USANDO TECLADO
Primeiro, precisamos definir quais parâmetros iremos
variar. Para a esfera da Figura 1 iremos variar a coordenada x.
Figura 1
Para isso, criamos uma variável global X e uma variação delta:
float X = -20; |
Agora, temos que associar X com as teclas especiais ç e è. Com a GLUT,
usaremos a função glutSpecialFunc():
Ela tem que ser chamada uma vez no main().
TeclasEspeciais é uma função
chamada automaticamente quando as teclas especiais são pressionadas. Ela é a
função que vai fazer a variável X variar, Observe no código.
void TeclasEspeciais(int key, int x, int y){ if(key ==
GLUT_KEY_LEFT){ X-=4; if(X<
-30) X
= -30; } if(key ==
GLUT_KEY_RIGHT){ X+=4;
if(X> 30) X
= 30; } glutPostRedisplay(); } |
MOVIMENTAÇÃO USANDO ANIMAÇÃO
Para animar um objeto temos que associar a variável X
ao tempo e ao método de transformação do objeto. Com a GLUT, usaremos a função glutTimerFunc:
void glutTimerFunc(unsigned
int msecs, void (*func)(int value), value); |
Ela tem que ser chamada uma vez no main() para estabelecer
qual função timer será usada, como por exemplo:
TimerFunction é uma função
chamada automaticamente que definiremos depois. Ela é a função que vai fazer a
variável X variar ao longo do tempo.
void TimerFunction( int value ){ |
Neste exemplo usamos a seguinte função de desenho.
Perceba que a variável X é usada para transladar a esfera.
void
Objetos(void) { // DRAW PLANE glPushMatrix(); glColor3f(0,1,0); glTranslatef(-100,0,-100); glScalef(200,200,200); drawPlane(); glPopMatrix(); // DRAW SPHERE glPushMatrix(); glColor3f(1,1,0); glTranslated( X, 15, 0 ); glutSolidSphere(30,16,16); glPopMatrix(); // DRAW WALLS glPushMatrix(); glColor3f(1,0,0); glTranslated(
-65, 50, 0 ); glScalef(0.2,3.0,1.0); glutSolidCube(35); glPopMatrix(); glPushMatrix(); glColor3f(1,0,0); glTranslated(
65, 50, 0 ); glScalef(0.2,3.0,1.0); glutSolidCube(35); glPopMatrix(); glutSwapBuffers(); } |
#include <stdlib.h> |
Includes |
#include <GL/glut.h> |
|
#include <stdio.h> |
|
|
Variáveis |
GLfloat rotX, rotY, rotX_ini, rotY_ini; |
|
GLfloat obsX, obsY, obsZ =200, obsX_ini, obsY_ini, obsZ_ini; |
|
GLfloat fAspect =
1, angle = 44; |
|
int x_ini,y_ini,bot; |
|
float X = -30; |
|
float delta = 0.4; |
|
#define SENS_ROT 5.0 |
|
#define SENS_OBS 10.0 |
|
#define SENS_TRANSL 30.0 |
|
|
|
void PosicionaObservador(void) |
Método
de |
{ |
posicionamento do |
glMatrixMode(GL_MODELVIEW); |
observador |
glLoadIdentity(); |
|
glTranslatef(-obsX,-obsY,-obsZ); |
|
glRotatef(rotX,1,0,0); |
|
glRotatef(rotY,0,1,0); |
|
gluLookAt(0.0,40.0,200.0, 0.0,0.0,0.0, 0.0,1.0,0.0); |
|
} |
|
void drawPlane()//Desenha o
plano |
Método
para o desenho |
{ |
do Plano Verde |
glBegin(GL_POLYGON); |
|
glVertex3f(1,0,1); |
|
glVertex3f(1,0,0); |
|
glVertex3f(0,0,0); |
|
glVertex3f(0,0,1); |
|
glEnd(); |
|
} |
|
|
|
void Objetos(void) |
Método
para o desenho |
{ |
dos objetos da cena |
// DRAW PLANE |
|
glPushMatrix(); |
|
glColor3f(0,1,0); |
|
glTranslatef(-100,0,-100); |
|
glScalef(200,200,200); |
|
drawPlane(); |
|
glPopMatrix(); |
|
|
|
// DRAW SPHERE |
|
glPushMatrix(); |
|
glColor3f(1,1,0); |
|
glTranslated(X,
15, 0 ); |
Controla
a translação |
glutSolidSphere(30,16,16); |
da esfera pela variável |
glPopMatrix(); |
“X” |
|
|
// DRAW WALLS |
|
glPushMatrix(); |
|
glColor3f(1,0,0); |
|
glTranslated(
-65, 50, 0 ); |
|
glScalef(0.2,3.0,1.0); |
|
glutSolidCube(35); |
|
glPopMatrix(); |
|
|
|
glPushMatrix(); |
|
glColor3f(1,0,0); |
|
glTranslated(
65, 50, 0 ); |
|
glScalef(0.2,3.0,1.0); |
|
glutSolidCube(35); |
|
glPopMatrix(); |
|
|
|
// glFlush(); // Makes sure that we output the model to
the graphics card |
|
glutSwapBuffers(); |
|
} |
|
|
|
void EspecificaParametrosVisualizacao(void) |
Método
para a |
{ |
especificação dos |
glMatrixMode(GL_PROJECTION); |
parâmetros de |
glLoadIdentity(); |
Visualização |
gluPerspective(angle,fAspect,0.5,500); |
|
PosicionaObservador(); |
|
} |
|
|
|
void Desenha(void) |
Método
que Desenha a |
{ |
Cena |
glClearColor(1.0f,
1.0f, 1.0f, 1.0f); |
|
glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT ); |
|
EspecificaParametrosVisualizacao(); |
|
Objetos(); |
|
} |
|
|
|
void AlteraTamanhoJanela(GLsizei w, GLsizei h) |
|
{ |
Método
para o ajuste da |
// Para previnir
uma divisão por zero |
Visualização
caso o |
if
( h == 0 ) h = 1; |
Tamanho
da Janela |
// Especifica as dimensões da viewport |
seja alterado |
glViewport(0, 0, w, h); |
|
// Calcula a correção de aspecto |
|
fAspect = (GLfloat)w/(GLfloat)h; |
|
EspecificaParametrosVisualizacao(); |
|
} |
|
|
|
void Teclado (unsigned char key, int x, int y) |
Método
de finalização |
{ |
do programa |
if (key == 27) |
|
exit(0); |
|
} |
|
|
|
void GerenciaMouse(int
button, int state, int x,
int y) |
Método
que gerencia o |
{ |
mouse |
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; |
|
} |
|
void GerenciaMovim(int
x, int y) |
Método
de configuração |
{ |
dos movimentos do |
if(bot==GLUT_LEFT_BUTTON) |
mouse |
{ |
|
int
deltax = x_ini - x; |
|
int
deltay = y_ini - y; |
|
rotY
= rotY_ini - deltax/SENS_ROT; |
|
rotX
= rotX_ini - deltay/SENS_ROT; |
|
} |
|
else
if(bot==GLUT_RIGHT_BUTTON) |
|
{ |
|
int
deltaz = y_ini - y; |
|
obsZ = obsZ_ini + deltaz/SENS_OBS; |
|
} |
|
else
if(bot==GLUT_MIDDLE_BUTTON) |
|
{ |
|
int
deltax = x_ini - x; |
|
int
deltay = y_ini - y; |
|
obsX = obsX_ini + deltax/SENS_TRANSL; |
|
obsY = obsY_ini - deltay/SENS_TRANSL; |
|
} |
|
PosicionaObservador(); |
|
glutPostRedisplay(); |
|
} |
|
|
|
void TeclasEspeciais(int
key, int x, int y){ |
Método
que controla as |
if(key == GLUT_KEY_LEFT){ |
teclas especiais |
X-=4; |
|
if(X < -30) |
|
X = -30; |
|
} |
|
if(key == GLUT_KEY_RIGHT){ |
|
X+=4; |
|
if(X > 30) |
|
X = 30; |
|
} |
|
glutPostRedisplay(); |
|
} |
|
|
|
void TimerFunction( int
value ){ |
Método
que controla o |
if( X < -30 ) delta = 0.4; |
Timer |
if( X > 30 ) delta = -0.4; |
|
X += delta; |
|
glutPostRedisplay(); |
|
glutTimerFunc( 33, TimerFunction, 1); |
|
} |
|
|
|
int main(void) |
Método
principal e de |
{ |
inicialização das |
int
argc = 0; |
Principais funções |
char *argv[]
= { (char *)"gl", 0 }; |
|
glutInit(&argc, argv); |
|
glutInitDisplayMode(GLUT_DOUBLE
| GLUT_RGB | GLUT_DEPTH); |
|
glutInitWindowPosition(5,5); |
|
glutInitWindowSize(450,450); |
|
glutCreateWindow("Movimentação 3D"); |
|
glutTimerFunc(33,
TimerFunction, 1 ); // 33 ms |
Inicializa o Timer |
glutDisplayFunc(Desenha); |
|
glutReshapeFunc(AlteraTamanhoJanela); |
|
glutKeyboardFunc
(Teclado); |
|
glutSpecialFunc(TeclasEspeciais); |
|
glutMotionFunc(GerenciaMovim); |
|
glutMouseFunc(GerenciaMouse); |
|
glutMainLoop(); |
|
return
0; |
|
} |
|
EXERCÍCIOS:
1) Usando o código acima como modelo
desenvolva os seguintes exercícios:
a)
Utilizando as teclas especiais é e ê faça a
esfera se deslocar na coordenada Z ;
b)
Utilizando a tecla especial F1 faça com que a movimentação das teclas ç, è, é e ê passe a
movimentar outro objeto da cena.
c)
Tente criar uma nova animação movendo outros objetos com outras variáveis;