Computação Gráfica I
Introdução
O objetivo desta aula é aprender como trabalhar com hierarquia de
transformações geométricas em OpenGL.
Abra o projeto OpenGL de sua preferência e inclua o arquivo Hierarquia3D-basico.cpp, como o programa principal.
Você pode usar algum dos
projetos disponíveis nesta página.
Teste o programa.
Veja no código que está na função DesenhaCenario
como é feito o posicionamento dos dois cubos na cena. Esta função é chamada de
dentro da função display.
glPushMatrix();
glTranslatef (
-1.0f, 0.0f, -1.0f );
glColor3f(1, 0,0);
DesenhaCubo();
glPopMatrix();
glPushMatrix();
glTranslatef (
1.0f, 0.0f, -1.0f );
glColor3f(0,0,1);
DesenhaCubo();
glPopMatrix();
As transformações geométricas em OpenGL são sempre aplicadas de forma
cumulativa, porém, quando usamos as funções glPushMatrix
e glPopMatrix, podemos restringir o efeito das
transformações ao escopo que desejamos.
Remova os comandos glPopMatrix e glPushMatrix que estão entre os desenhos dos
dois cubos, e compare o resultado com o exemplo anterior.
glPushMatrix();
glTranslatef (
-1.0f, 0.0f, 0.0f );
glColor3f(1, 0,0);
DesenhaCubo();
//glPopMatrix();
//glPushMatrix();
glTranslatef (
1.0f, 0.0f, 0.0f );
glColor3f(0,0,1);
DesenhaCubo();
glPopMatrix();
Note que agora o cubo azul ficou colado no cubo vermelho e o cubo azul ainda
ficou mais distante. Por que isto ocorre ??
Como o cubo vermelho foi transladado em X de -1 e o azul de +1, a posição final
do cubo azul é 0, já que a segunda translação foi aplicada de forma cumulativa
sobre a primeira. Algo semelhante aconteceu no eixo Z.
Desloque o cubo azul um pouco mais para a direita, aumentando o valor X de sua
translação. No eixo Z, remova a translação.
Faça por exemplo:
glTranslatef ( 2.0f, 0.0f, 0.0f );
Inclua a linha
glRotatef(AngY, 0,0,1);
logo após o glTranslate do
primeiro cubo. O código deverá ficar da seguinte forma:
glPushMatrix();
glTranslatef (
-1.0f, 0.0f, 0.0f );
glRotatef(AngY, 0,0,1);
glColor3f(1, 0,0);
DesenhaCubo();
A variável AngY é alterada sempre que o
usuário pressiona as tecla 'a' ou 'A'. Veja a função keyboard.
Compile e veja o resultado.
Obtendo as Coordenadas
de um ponto
Para saber a posição de um ponto de um dos objetos após uma sequência de transformações
geométricas é preciso multiplicar este ponto, dado no SRO(sistema
de coordenadas do objeto), pela matriz de transformação que está sendo usada
para desenhar este objeto.
Para obter a coordenada correta, é preciso aplicar as transformações sem
posicionar a câmera.
Para tanto, em OpenGL, deve-se repetir todo o processo de desenho sem exibir
de fato o objeto e colocar o cálculo do ponto, na mesma
código onde o obejto era desenhado.
Copie as funções abaixo para o código de seu programa.
// ***********************************************
// void CalculaPonto(float ptIN[3], float ptOUT[3]) {
//
// Esta função converte as coordenadas de um ponto IN,
// dado no Sistema de Referência do Objeto (SRO)
// para o equivalente OUT, no Sistema de Referência do
// Universo (SRU), ou seja, aplica as rotações,
// escalas e translações ao ponto.
// ***********************************************
void CalculaPonto(float ptIN[3], float ptOUT[3]) {
GLfloat ponto_novo[4];
GLfloat matriz_gl[4][4];
int i;
glGetFloatv(GL_MODELVIEW_MATRIX,&matriz_gl[0][0]);
for(i=0; i<4; i++) {
ponto_novo[i] =
matriz_gl[0][i] * ptIN[0] +
matriz_gl[1][i] * ptIN[1] +
matriz_gl[2][i] * ptIN[2] +
matriz_gl[3][i];
}
for (i=0; i<3; i++)
ptOUT[i] = ponto_novo[i];
}
// **********************************************************************
// void ImprimePosicao(float x, float y, float z) {
// Converte as coordenadas recebidas por
// parâmetro e imprime o resultado na tela.
// **********************************************************************
void ImprimePosicao(float x, float y, float z) {
float P1[3], P2[3];
P1[0] = x; P1[1] = y; P1[2] = z;
CalculaPonto(P1, P2);
cout << "X = "
<< P2[0] << " Y = " << P2[1] << "
Z = " << P2[2] << endl;
}
Substitua a função DesenhaCenario pelo código
abaixo.
Note que a função recebe por parâmetro uma variável booleana que definirá se
desejamos desenhar o cenário ou se desejamos apenas calcular as coodenadas de um ponto, através da função ImprimePosicao.
Para testar, o código está chamando a função passando o ponto (0,0,0) que
corresponde ao centro do cubo, no SRO.
// **********************************************************************
// void DesenhaCenario(bool desenha)
// se desenha == true
// então, desenha o cenário
// senão, imprime as coordenadas do centro
do objeto
//
// **********************************************************************
void DesenhaCenario(bool desenha)
{
glPushMatrix();
glTranslatef (
-1.0f, 0.0f, -1.0f );
glRotatef(AngY, 0,0,1);
glColor3f(1, 0,0);
if (desenha)
DesenhaCubo();
else {
cout
<< "Centro do Cubo Vermelho: ";
ImprimePosicao(0,0,0);
}
//glPopMatrix();
//glPushMatrix();
glTranslatef (
2.0f, 0.0f, 0.0f );
glColor3f(0,0,1);
if (desenha)
DesenhaCubo();
else {
cout
<< "Centro do Cubo Azul: ";
ImprimePosicao(0,0,0);
}
glPopMatrix();
}
Insira o código abaixo na função display. Posicione este código ANTES
da chamada da função PosicUser, logo após a
chamada da glClear.
if (fazCalculoPonto)
{
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
DesenhaCenario(false);
glPopMatrix();
fazCalculoPonto = false;
}
O objetivo deste trecho é ativar o cálculo da posição dos pontos do cenário,
chamando a função DesenhaCenario com um
parâmetro false.
A variável fazCalculoPonto tem seu valor
alterado sempre que o usuário pressiona a tecla "espaço". Veja na
função keyboard.
Compile e veja o resultado. Observe, na janela de console, as coordenadas dos
pontos centrais dos dois cubos.
Exercícios
1) Modifique o programa de forma a controlar a posição do cubo vermelho
através de teclas.
2) Modifique o programa de forma a controlar a posição do cubo azul através de teclas.
3) Adicione mais um objeto a cenário, de forma que este seja desenhado depois
do cubo azul. Procure imprimir também as coordenadas do centro deste objeto.
FIM