Ponto V!

Home OpenGL Aplicando as Transformações
Vinícius Godoy de Mendonça
Aplicando as TransformaçõesImprimir
Escrito por Vinícius Godoy de Mendonça

Agora que já entendemos que tipo de transformações existem, que tal darmos uma olhada em como elas são implementadas na OpenGL? Para esse artigo, é fortemente aconselhável que você conheça como a matemática das transformações funcionam, se não conhece, você pode descobrir aqui

.

OpenGL e suas matrizes

Como já foi dito, as transformações ocorrem em matrizes, em especial, nas matrizes de projeção e modelview. O primeiro passo é dizer à OpenGL qual matriz será usada. Fazemos isso através do comando void glMatrixMode(GLenum mode) passando como parâmetro o valor GL_MODELVIEW para a matriz de modelview ou GL_PROJECTION para a matriz de projeção. O valor GL_MODELVIEW já é padrão da OpenGL.

A OpenGL trabalha com matrizes quadradas, de 4×4. Por isso, todo vértice também é definido por quatro coordenadas x, y, z e w. A última coordenada é um fator de escala, geralmente definido em 1. Esse sistema é chamado de sistema de coordenadas homogêneo. Após a multiplicação de todas as matrizes, o valores de x, y e z finais serão divididos por w.

Podemos “zerar” qualquer matriz da OpenGL, usando o comando glLoadIdentity(). Isso fará com que a matriz selecionada seja substituída pela matriz identidade. Lembrando um pouco a matemática, qualquer matriz multiplicada pela identidade resulta na própria matriz. A matriz identidade 4×4 é a seguinte:

Matriz identidade

A OpenGL permite que multipliquemos o valor da matriz atual por um valor arbitrário. Sabendo as fórmulas corretas, é possível gerar efeitos de distorção de objetos, ou mesmo fazer qualquer uma das transformações descritas no artigo passado. O comando para multiplicar a matriz atual é o glMultMatrix. E vem em duas versões, uma para multiplicação de floats e outra de doubles. O comando aceita como parâmetro uma outra matriz, também 4×4, contendo os valores a serem multiplicados. Lembre-se que estamos falando aqui de multiplicação de matrizes. Talvez seja interessante você revisar em livros de matemática como essa multiplicação é feita, caso não se lembre – mas não se trata de simplesmente multiplicar o elemento atual com o mesmo elemento correspondente na outra matriz. Note que esse comando sobre a matriz identidade, trocaremos a matriz identidade pela matriz passada. Também é possivel substituir a matriz atual por uma arbitrária sem multiplica-la, usando o comando glLoadMatrix.

Uma peculiaridade estranha da OpenGL é que, diferentemente do que aprendemos na escola, as matrizes são baseadas em colunas, e não em linhas. O que significa que seus elementos estão dispostos da seguinte forma:

Disposição dos elementos da matriz

Essa notação também tem o inconveniente de não ser a que normalmente esperamos, mesmo do ponto de vista físico da organização dos dados na memória. Um artifício comum é criar uma classe para representar uma matriz e então fazer com que essa classe troque linhas por colunas apenas na hora de enviar para a OpenGL.

Embora multiplicar matrizes no braço possa ser realmente eficiente, deixa um código confuso e dificílimo de entender. Por isso, a OpenGL já fornece funções prontas para a manipualção (através de multiplicação) de suas matrizes. São elas:

  • Matrix ModelView: Escala, Translação, Rotação e Posicionamento do Olho;

  • Matrix de Projeção: Modo perspectiva, modo ortográfico;

Como vimos no artigo anterior, não há diferença entre deslocar o olho ou movimentar objetos, por isso todas as funções da matriz modelview podem ser usadas para as duas tarefas. Entretanto, intuitivamente, é mais fácil somente deslocar objetos com as três primeiras e utilizar uma função especial para posicionamento do olho.

Escala

Se os artistas forem caprichados e se os objetos do seu mundo não crescerem, o comando de escala nunca precisará ser usado. Agora, a vida de um programador de jogos caseiro envolve o download de modelos gratuitos, onde os artistas não sabiam o tamanho certo para exportar os seus modelos. Por isso, esse comando será usado para esticar o objeto.

A escala não precisa necessariamente ser proporcional nos três eixos. Você pode reduzir a escala somente no eixo y, por exemplo, e gerar uma figura parecida com os cogumelos após serem pisoteados pelo Super Mario. O comando para ajustar o tamanho de um objeto é o void glScalef(GLfloat x, GLfloat y, GLfloat z), onde x, y e z indica por quantas vezes o tamanho do modelo deve ser multiplicado em cada eixo. Esse comando multiplica a matriz ModelView pelo seguinte:

Matriz de Escala

Há também uma versão do comando para o tipo double.

Translação

A translação permite que desloquemos um objeto em nosso mundo. O comando para realizar uma translação é o void glTranslatef(GLfloat x, GLfloaty, GLfloat z), onde x, y e z é a posição que o objeto deve ficar. A OpenGL não define escala portanto, pode-se usar quaisquer valores consistentes com o mundo sendo modelado.

Na verdade, o que o comando faz é multiplicar a matriz ModelView pelo seguinte valor:

Matriz de translação

Como todos os comandos tratam apenas de multiplicações sobre a matriz model view, devemos lembrar que eles são cumulativos. Como sempre, há uma versão desse comando para o tipo double.

Rotação

Para rotacionar um objeto na tela, usamos a função void glRotate[fd](angle, x, y, z), que, como a assinatura diz, vem em duas versões uma para valores float e outra para double. Essa função gira a matriz atual no ângulo especificado no primeiro parâmetro e em torno do vetor definido por x, y e z. Normalmente, uma maneira fácil de definir esse vetor é apenas usar o número 1 no eixo que queremos girar, e 0 nos demais eixos. Por exemplo, para uma rotação de 45º em Z, usaríamos o comando da seguinte forma:

glRotatef(45.0f, 0.0f, 0.0f, 1.0f);

Todos os objetos desenhados após o comando são também rotacionados. Rodar em x, y e z causa as seguintes multiplicações de matrizes.

Rotação em x, y e z

Lembra-se que a ordem de uma rotação e de uma translação é relevante? No artigo passado, você viu uma explicação geométrica para o fenômeno. Estavamos lidando com rotações de eixos. Aqui está a explicação matemática: a multiplicação de matrizes não é comutativa. Isso é, multiplicar uma matriz A x B é diferente de multiplicar B x A. Por isso, usar o comando de rotação seguido do de translação também é diferente de usar a ordem inversa. O resultado de cada operação você já viu no artigo passado. Interessante, não?

Ajustando a posição do olho

Poderíamos ajustar a posição do olho usando os três comandos acima antes de qualquer comando. Se quiséssemos que o olho se deslocasse para frente, simplesmente aplicaríamos uma translação negativa, aproximando todos os modelos. Mas isso não seria nem prático e nem intuitivo.

Para isso, usamos a função da biblioteca auxiliar:
void gluLookAt(GLdouble eyex, GLdouble eyey, GLdouble eyez,
GLdouble centerx, GLdouble centery, GLdouble centerz,
GLdouble upx, GLdouble upy, GLdouble upz)

Como parâmetros ela aceita a posição onde a câmera está posicionada (eye), a posição para onde a câmera está olhando (center) e a posição onde está o topo do mundo (top) para câmera. A figura abaixo ajuda a entender essa analogia:

Camera

Note que o conceito de "topo do mundo" refere-se a um vetor que aponta da câmera para o que ela entende como topo, e não necessariamente para o céu. Por exemplo, um personagem que tenha caído de lado, poderia ter como vetor de topo o valor (1,0,0), considerando que z representasse a altura do mundo, e x e y as coordenadas do chão. Da mesma forma, se você negar o vetor de topo, a imagem da câmera ficará de cabeça para baixo.

Matrizes de projeção

Os comandos acima são usados na matriz GL_MODELVIEW. Agora, quais são os comandos de projeção? E como aplicá-los?

Como vimos no artigo sobre sistemas de coordenadas, podemos usar os comandos glOrtho, glPerspective e gluOrtho2D para alterar como a OpenGL projeta nossa imagem 3D numa tela de apenas 2 dimensões. Vejamos novamente o código de exemplo daquele artigo, que mostrava como usar a projeção 2D. Você notará que ele ficou muito mais claro:

glMatrixMode(GL_PROJECTION);
   glLoadIdentity();  //Resetamos a projeção atual
   gluOrtho2D(0, GAME_WINDOW.getWidth(),
      GAME_WINDOW.getHeight(), 0);
glMatrixMode(GL_MODELVIEW);

O que estamos fazendo? Basicamente, usamos o comando glMatrixMode para alterar para a matriz de projeção. Apagamos a projeção atual (provavelmente a de perspectiva) e damos um comando para usar a projeção ortográfica 2D. Agora que já estamos em um novo modo de projeção, voltamos para a matriz ModelView e poderemos posicionar os objetos do HUD.Veja que o comando glLoadIdentity() foi muito importante nesse contexto. Se o tivessemos esquecido, multiplicaríamos a matriz de perspectiva pela de projeção, resultando em algo bastante esquisito…Você deve estar curioso, então, eis as matrizes pela qual a projeção é multiplicada em cada comando:

projecoes.png

Creio que agora você dormirá tranquilo… ou terá pesadelos com elas. Pelo menos, agora é possível ter uma clara noção do porque aqueles comandos foram criados.

Pilhas de matrizes

Seria muito trabalhoso resetar cada uma das matrizes com a identidade antes de colocar cada um dos objetos do mundo. Muitas vezes, é conveniente colocar um objeto em relação a outro – por exemplo, o chapéu, a espada e o escudo, podem estar em relação ao corpo do seu personagem. Por isso, a OpenGL não trabalha apenas com uma matriz, mas com uma pilha de matrizes de projeção e modelview (na verdade, a OpenGL tem mais dois tipos de matrizes empilhadas, as de textura e cores).

A grande vantagem de trabalhar com matrizes é que você torna a OpenGL capaz de guardar o estado da transformação atual antes de aplicar uma nova transformação. Então, uma vez terminados os desenhos nessa nova transformação, é possível retornar ao estado previamente salvo.

Os comando para empilhar uma matriz é o void glPushMatrix(). Para desempilhar use o void glPopMatrix(). Veja abaixo um exemplo simples de como usar os comandos para desenhar o boneco com chapéu e espada:

glPushMatrix(); //Guardamos o sistema atual
   glTranslatef(pcPosX, pcPosY, pcPosZ);
   drawPc();
   glPushMatrix(); //Guardamos a posição do boneco
      //Posicionamos o chapéu, em relação ao boneco
      glTranslatef(hatPosX, hatPosY, hatPosZ);
      drawHat(); //desenho do chapéu
   //Voltamos as coordenadas do boneco
   glPopMatrix();
   glPushMatrix(); //Guardamos a posição do boneco
      //Posicionamos a espada, em relação ao boneco
      glTranslatef(swordPosX, swordPosY, swordPosZ);
      drawSword(); //Desenho da espada
   glPopMatrix();
glPopMatrix();

Nesse programa, drawPc(), drawHat() e drawSword() são funções que desenham o personagem, o chapéu e a espada. A implementação dessa função desenharia os objetos no centro de um sistema de coordenadas qualquer (mas todos proporcionais entre si, senão teríamos que usar também o glScale). Cada objeto é posicionado usando o glTranslate().Num primeiro momento, demos um glPushMatrix() e então mudamos o sistema de coordenadas para corresponder ao ponto no mundo onde queríamos esse personagem. Desenhamos então o personagem. Em seguida, com um novo glPushMatrix() guardamos essa posição e desenhamos o chapéu em relação a ela. Como não queríamos desenhar a espada em relação ao chapéu, desempilhamos a matriz com um glPopMatrix() , obtendo novamente as coordenadas do personagem, salvas previamente. Desenhamos então a espada em relação a ele, usando o mesmo processo.

Resumindo

  • Nesse artigo você viu como alternar as matrizes de projeção e modelview;
  • Também aprendeu a definir valores arbitrários as matrizes, multiplica-las e restaurar o valor da identidade;
  • Aprendeu como rotacionar, transladar e redimensionar o modelview;
  • Relembrou as funções para uso na matriz de projeção e viu suas fórmulas;
  • Aprendeu a como posicionar as coodenadas do olho;
  • Aprendeu sobre a pilha de matrizes.

Exercícios

  1. Baixe os programas glTutors (1.24MB) do site do Nate Robins e brinque um pouco com eles (em especial com o lightposition, projection e transformation). Eles demonstrarão para você o uso das funções acima de maneira interativa.
  2. Altere o seu programa do cubo para que possa “andar pelo cenário” usando as setas. Use para isso a função gluLookAt.
  3. DESAFIO: Usando o cubo do exercício anterior, faça um pequeno “sistema solar de cubos”. Basta ter um sol, um planeta girando em torno dele e uma lua em torno do planeta. O planeta também deve girar em torno do seu próprio eixo, assim como a lua. Você deve usar apenas uma função para o desenho do cubo, e lidar apenas com as matrizes antes de chamar essa função. A lua deve ser menor que o planeta e o sol maior.

Você também pode usar a função glutWireSphere(1.0, 20, 16); no lugar dos planetas. Basta incluir o cabeçalho GL/glut.h. Talvez seja necessário também inserir a glut32 entre suas libs e baixar a biblioteca glut no site do Nate Robins. Use projeção em perspectiva.


Comentários (24)
  • Anônimo  - Bom Resumo
    avatar

    Muito bom o resumo. seria bom se postassem mais exercícios.

  • Vinícius Godoy de Mendonça
    avatar

    Obrigado. Mais exercícios são colocados à medida que o conteúdo avança.

  • Zero  - gluLookAt()
    avatar

    Uma pequena correção:

    você informou que o top representaria o topo do mundo para a função gluLookAt(), mas isso não é correto pois o observador (câmera) é que é afetado ao definir top, por exemplo, apontar para o eixo x (-1,0,0 como parâmetros de up), o quê poderia representar um personagem que caiu de lado. Isto se considerarmos o plano do solo (horizontal) sendo o xz e o eixo y definido como a altura do ambiente (vertical).

  • Vinícius Godoy de Mendonça
    avatar

    Sim, para alguém de lado, o topo do mundo agora está na lateral. Por topo do mundo não me referia ao céu.

    Isso depende muito da interpretação e o termo "topo do mundo" é usado pelo próprio Red Book.

    Mas concordo com você, vou melhorar a explicação ali no artigo.

  • Zero  - re: gluLookAt()
    avatar

    errata:

    Zero Escreveu:
    pois o observador (câmera) é que é afetado ao definir top, por exemplo, apontar para o eixo x

    pois o observador (câmera) é que é afetado ao definir top, por exemplo, apontado para o eixo x

  • lucas  - rotação em torno do proprio centro
    avatar

    gostaria de saber como fazer pra rotacionar em torno do seu proprio centro....eu tenho uma imagem 2d e com o glRotatef(angulo, 0, 0, 1); só consigo rotacionar em torno de um dos eixos....

    obrigado...mt boa suas explicações

  • Vinícius Godoy de Mendonça
    avatar

    Pode exemplificar o que você quer? Pois só existem 3 eixos possíveis, x, y e z. Um deles deve representar a rotação que você deseja.

    Só lembre de aplicar essa rotação depois da translação da imagem, caso contrário, a imagem sairá deslocada. Lembre-se da sigla TRS (Translate-Rotation-Scale), pois é a ordem que essas operações são normalmente realizadas (em DirectX seria ao contrário, SRT).

  • Rômulo  - rotação em torno do proprio centro
    avatar

    Eu to na mesma duvida desse cara
    como faz pra girar em torno do próprio objeto?
    Ele rotaciona em torno do eixo y mas não fica legal

  • Vinícius Godoy
    avatar

    Faça primeiro uma translação que coloca seu objeto na posição (0,0,0). Faça a rotação e depois translacione novamente para o lugar.

    Agora, a melhor prática é sempre trabalhar com o objeto no (0,0,0) e só posiciona-lo através de translações na hora de desenhar.

  • Tales  - Depth test simplesmente não funciona.
    avatar

    Eu tentei de tudo. Até olhei o redbook, mas não consegui fazer o zbuffer funcionar. Eu já tinha visto isso em outros exercícios, mas achei que era alguma config. da máquina de estados que estava errada. Porém fazendo exercício dos planetas percebi que a coisa simplesmente não funciona.

    Não sei se é alguma configuração que fiz errado ou se é problema no meu driver/implementação do sistema. Eu botei o código (a definição da classe e os métodos setup e draw) em http://pastebin.com/VMaRktch. Se puder dar uma olhada seria bom... Senão puder, vc pode me indicar um fórum onde eu possa tirar esta dúvida?

  • Vinícius Godoy de Mendonça
    avatar

    Muito estranho, aparentemente seu código está certo. Tentou roda-lo em outra máquina?

    Pode colocar um PrintScreen do que ocorre?

    Vou testar à noite, quando chegar em casa.

  • Tales
    avatar

    Os printscreens:
    [IMG]http://i118.photobucket.com/albums/o97/Invisivel3c/print0002.png[ /IMG]
    [IMG]http://i118.photobucket.com/albums/o97/Invisivel3c/print0001.png[ /IMG]
    [IMG]http://i118.photobucket.com/albums/o97/Invisivel3c/print0000.png[ /IMG]
    A implementação completa: http://pastebin.com/tYneP8jv< /p>

    Ah fiz o código em um Core 2 duo com uma placa Geforce 210 512MB. Seguindo a sugestão, testei hoje também no pc do meu trabalho e lá deu o mesmo erro. O pc é um Dell com pentium dual core e vídeo onboard, configuração totalmente diferente do meu pc, o que indica que provavelmente eu fiz alguma besteira imensa no código e não consigui perceber.

  • Vinícius Godoy de Mendonça
    avatar

    Pode enviar um zip com os fontes do seu projeto para vinigodoy@pontov.com.br ?

  • Tales  - Resolvido
    avatar

    Depois de dias debugando achei o maldito problema. O bug mesmo acontece na minha função "Main":

    Código:

    int main(int argc,char* argv[])
    {
    GAMEWINDOW.setup("Cube", 800, 600, 0, false );
    GAMEWINDOW.show(new MainGameSteps);
    return 0;
    }


    Eu passo a profundidade como zero. A SDL entende esse 0 como "use o bpp nativo" e cria a janela normalmente. Entretanto a classe GameWindow faz o seguinte:

    Código:

    int GameWindow::setupOpenGL()
    {
    //Atributos do opengl
    SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
    SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, bpp);
    SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, 0);
    SDL_GL_SetAttribute( SDL_GL_ACCUM_RED_SIZE, 0);
    SDL_GL_SetAttribute( SDL_GL_ACCUM_GREEN_SIZE, 0);
    SDL_GL_SetAttribute( SDL_GL_ACCUM_BLUE_SIZE, 0);
    SDL_GL_SetAttribute( SDL_GL_ACCUM_ALPHA_SIZE, 0);

    return createFlags();
    }

    Só que olhando a documentação do SDL, o atributo SDL_GL_DEPTH_SIZE define o tamanho do Depth buffer e não o bits per pixel. Isso por si só não daria problema porque quando passamos um valor como 16 ou 32 o opengl enxerga um valor válido, mas como eu usei 0, ele reservou 0 pixels pro Z-buffer e por isso não funcionava.

    Corrigi isso colocando 16 em vez de bpp e tudo agora funciona perfeitamente!

  • Vinícius Godoy de Mendonça
    avatar

    Nossa, que detalhezinho macabro.

    O GL_SDL_DEPTH_SIZE diz quantos bits você usará para a resolução do DEPTH_BUFFER. Geralmente, é igual ao que você usa para a janela, por isso no código os bpps são iguais.

    Entretanto, você não pode passar 0 nesse parâmetro. Embora a SDL entenda que 0 é bpp nativo, a opengl não. Talvez você possa colocar um if aí para, se o valor for 0, você procurar na SDL que valor ela detectou.

  • mateus  - transformações
    avatar

    Para fazer transformações com duas dimensões,
    seria necessário apenas de uma matriz 2X2, certo?
    Se for como seria a matriz de translação, rotação (eixo Z) e escala?
    E para encontrar as coordenadas de um ponto bastaria
    multimplicar a matriz transformação pela transposta do vetor de coordenadas, nessa ordem?
    obrigado.

  • Vinícius Godoy de Mendonça
    avatar

    Uma matriz 2x2 é apenas capaz de fazer transformações lineares. Portanto, ela não faz translações. Você pode fazer:
    - Rotação
    - Reflexo
    - Escala
    - Shearing (itálico).

    Se você quiser fazer translação, rotação e escala, você deve usar uma matriz 3x3. Note que é uma matrix 3x3 que representa operações bidimensionais, pois ela trabalha no sistema de coordenadas homogêneo.

    Para obter uma matriz que faz ao mesmo tempo rotação, translação e escala, basta multiplicar matrizes que fazem cada operação dessas individualmente. O resultado, é uma matriz 3 em 1, que faz todas as operações ao mesmo tempo.

    Para obter as coordenadas de um ponto, você deve então multiplicar o vetor do ponto por essa matriz. A ordem exata da multiplicação depende se seu sistema de cordenada é da mão direita ou esquerda.

    Se for o da mão direita a multiplicação é geralmente feita na ordem: translação, rotação, escala. Se for da mão esquerda, é ao contrário escala, rotação e translação.

  • mateus
    avatar

    Hummmmmmmmmmmmmmm, valeu mesmo,
    ótimo trabalho, continuem assim! :lol:

  • andre
    avatar

    muito bom

    sou de Portugal e nunca vi nada assim parecido

    mt completo, mt elucidativo e principal em português

    obrigado

  • Jonathan Sansalone  - Movimentar braço
    avatar

    Olá Vini! Tudo bem? Estou modelando um robo simples em OpenGL 3D e queria saber como eu poderia fazer os braços dele se movimentarem, quais técnicas eu poderia utilizar?

  • Roney  - Duvida
    avatar

    Blz Cara , muito bom o post mais fiquei com uma duvida estou fazendo animaçao 3d e os parametros de transformaçao sao rotaçoes(Coseno e seno) , só que tem um problema , a animaçao esqueletica ela inclui pesos para cada vertice e estou fazendo o seguinte :
    Estou transformando o seno e o coseno em angulo e fazendo
    Angulo*PesoVertice .
    só que ele ficou totalmente deformado , entao eu queria perguntar eu vou ter que usar quaternions ou posso usar esse metodo ?

  • JeffProg  - Dúvida para rotacionar um triângulo
    avatar

    Não sei se eu poderia fazer este tipo de pergunta aqui, mas tenho um código bem simples de OpenGL onde tento fazer uma animação rotacionando um triângulo mas só consigo rotacionar manualmente alterando o primeiro parâmetro do glRotatef. Alguém consegue encontrar o problema do código abaixo?

    Código:
    #include
    #include //Biblioteca básica para usar os camando de glut e OpenGL

    double ang = 0.0f;

    void Desenha();//Função para fazer o desenho
    void Inicializa();//Função que inicializa comando que necessitam ser executados apenas uma vez

    int main(int argc, char** argv){

    //Comando necessário para iniciar o glut
    glutInit(&argc,argv);

    //Avisa ao GLUT o modo de exibição quando a janela é criada
    glutInitDisplayMode(GLUT_DEPTH | GLUT_SINGLE | GLUT_RGB);

    //Tamanho da janela
    glutInitWindowSize(640,480);

    //Título da janela
    glutCreateWindow("Rotacionar";);

    //Desenhar a janela
    glutDisplayFunc(Desenha);

    //Inicializa eventos que só precisam ser determinados uma vez
    Inicializa();

    //Executa o loop de eventos do GLUT
    glutMainLoop();

    return 0;
    }

    void Desenha(){

    //Limpa a janela com a cor de fundo especificada
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);


    glMatrixMode(GL_MODELVIEW);

    //Transforma a atual pilha de matrizes em identidade. Evita alguns erros se colocado após glMatrixMode
    glLoadIdentity();

    //Rotacionar
    glRotatef(ang,0.0f,0.0f,1.0f);

    glBegin(GL_TRIANGLES);
    glColor3f(1,0,0);
    glVertex3f(-0.5,-0.5,0);
    glColor3f(0,1,0);
    glVertex3f(0.5,-0.5,0);
    glColor3f(0,0,1);
    glVertex3f(0.0,0.5,0);
    glEnd();

    ang+=0.1f;

    //Executa os comandos OpenGL
    glFlush();

    glutSwapBuffers();

    }

    void Inicializa(){

    //Define a cor de fundo da janela
    glClearColor(0.0f,0.0f,0.0f,1.0f);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    }

    Obrigado desde já se alguém puder ajudar e desculpe se não for o lugar correto para postar a minha dúvida.

Escrever um comentário
Your Contact Details:
Gravatar enabled
Comentário:
[b] [i] [u] [url] [quote] [code] [img]   
:angry::0:confused::cheer:B):evil::silly::dry::lol::kiss::D:pinch::(:shock:
:X:side::):P:unsure::woohoo::huh::whistle:;):S:!::?::idea::arrow:
Security
Por favor coloque o código anti-spam que você lê na imagem.
LAST_UPDATED2  

Busca

Linguagens

Twitter