Computação Gráfica I

Transformações Geométricas Hierárquicas em OpenGL


Introdução

O objetivo desta aula é aprender como trabalhar com hierarquia de transformações geométricas em OpenGL.

Carregue o projeto disponível neste link abra no Code::Blocks e adicone o arquivo Hierarquia3D-basico.cpp

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