Ponto V!

Home OpenGL Texturas – Parte 1
Vinícius Godoy de Mendonça
Texturas – Parte 1Imprimir
Escrito por Vinícius Godoy de Mendonça

No artigo passado, vimos como carregar imagens da SDL e analisar suas propriedades. Neste, veremos como mapear essas imagens na superfície dos nossos objetos, transformando-as em texturas.

Introdução

O mapeamento de texturas permite que você associe uma ou mais imagens a polígonos, o que gera um efeito muito realista. Por exemplo, você poderia associar o mapa mundi a superfície de uma esfera e desenhar o planeta terra. Hoje, essa técnica, chamada mapeamento de texturas (texture mapping), é usada em absolutamente todos os jogos.

As texturas podem ser de três tipos:

  • Unidimensionais: Uma linha contendo um único pixel de altura. Útil para fazer degradée em superfícies, como o céu;
  • Bidimensionais: Uma imagem tradicional, com largura e altura. De longe, o tipo mais usado. E será o tipo que estudaremos.
  • Tridimensionais: Consiste numa imagem tridimensional de modo que, dado a coordenada x, y e z de uma figura, a mesma coordenada x, y e z na imagem corresponderá a cor naquele ponto. Geralmente não é usada pois consome muita memória e porque o interior dos objetos dificilmente é visto.

Uma vez mapeadas a um polígono, as texturas estão sujeitas a todas as transformações que ocorrem naquele polígono. Ou seja, elas irão rotacionar, mover ou escalar juntamente do polígono. Assim, podemos encarar a textura como se fosse efetivamente a “pele” de nossa geometria.

Mapeando texturas

Como vimos anteriormente, nem todos os polígonos da OpenGL são desenhados usando a primitiva GL_QUADS. Por outro lado, todas as texturas bidimensionais são criadas em quadrados perfeitos, como qualquer imagem tradicional. Então, como é possível mapear esse quadrado para um polígono arbitrário?

Além das coordenadas espaciais de um polígono, também podemos fornecer à OpenGL coordenadas de textura, para cada vértice. Essas coordenadas tem a notação (s,t) embora existem autores que as chamem de (u,v). Cada vértice da figura deve conter sua própria coordenada de textura e é o própria OpenGL que se encarrega de alongar ou achatar a imagem para que ela caiba dentro geometria, da forma como foi mapeada. A figura abaixo mostra como é feito um mapeamento de uma textura para um triângulo:

Mapeamento de coordenadas de textura numa geometriaNote que pouco importa a coordenadas reais do triângulo, desde que ele mantenha a mesma proporção. Também é util saber que você poderia aplicar as coordenadas de uma única textura não para um, mas para vários polígonos e recobrir assim uma forma complexa, como uma esfera formada por vários triângulos ou mesmo o modelo de um rosto.

Criando as texturas

Cada textura na OpenGL é um objeto distinto. A OpenGL associa a cada textura um identificador, único. Usamos o comando void glGenTextures(GLsizei n, GLuint *textures); para criar novos objetos de texturas. Após criados, podemos associar esses objetos a imagens. A função possui dois parâmetros. O primeiro indica quantos objetos de textura você vai criar, o segundo, permite que a OpenGL devolva os identificadores desses objetos criados através de um array de inteiros que você deve fornecer.

Em seguida, precisamos informar à OpenGL com que objeto de textura estamos trabalhando. Fazemos isso usando o comando void glBindTexture(GLenum target, GLuint texture);. Esse comando aceita dois parâmetros: o primeiro indica qual é o tipo da textura que iremos trabalhar e pode conter os valores GL_TEXTURE1D, GL_TEXTURE2D ou GL_TEXTURE3D. O segundo, indica o ID do objeto de textura que será manipulado.

Em seguida, basta carregar a textura dentro do objeto. No artigo passado, vimos que podemos usar a SDL para carregar imagens na memória. Após essa carga, é necessário dizer à OpenGL que aquela imagem será uma textura. Uma vez carregada a textura se torna parte do que a OpenGL chama “texture state” (estado de textura). As três funções abaixo, transformam um array de bytes contendo os dados da imagem em texturas:

void glTexImage1D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, void *data);

void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, void *data);

void glTexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, void *data);

Use a função apropriada para texturas 1D, 2D e 3D. É importante ressaltar que a OpenGL copia os dados da imagem quando uma das funções é chamada. Por isso, é possível descartar a SDL image tão logo a textura tenha sido criada.

O parâmetro target indica em que área a textura deve ser criada. Ele pode conter os valores GL_TEXTURE_1D, GL_TEXTURE2D, GL_TEXTURE3D.

O parâmetro level indica qual é o nível do mipmap sendo carregado. Cobriremos mipmaping num próximo tópico. Por hora, usaremos a textura sem esse recurso, simplesmente fornecendo 0 nesse parâmetro.

O próximo parâmetro, chamado internalFormat diz à OpenGL qual é o formato de destino em que a OpenGL irá armazenar a imagem carregada. Ele diz à OpenGL quantos bits ela deve usar para armazenar cada componente de cor da textura, quantos componentes de cor existirão e se a textura é ou não comprimida.

Você pode obter uma lista completa desses parâmetros clicando nos links acima. Usaremos dois dos valores comuns: GL_RGB e GL_RGBA. Para descobrir qual dos dois usar, verificaremos se a imagem carregada tem 3 (RGB) ou 4 (RGBA) bytes por pixel usando a SDL, como visto no artigo anterior.

Os parâmetros width, height e depth (onde apropriados) dizem as dimensões da imagem. Também podemos ler os dois primeiros da SDL. É muito importante saber que até a OpenGL 2.0 esses valores tinham, obrigatoriamente, que ser potências de 2 (2,4,8,16,32,64,128,256, …). Não era necessário que a textura tivesse os dois lados iguais. Texturas fora dessa regra podem ser simplesmente ignoradas em implementações antigas da OpenGL. Muitas das implementações novas, já conformes com a 2.0, também tem perdas significativas de performance quando esse requisito não é atingido. Então, via de regra, sempre use texturas com tamanhos potências de 2.

O parâmetro border diz à OpenGL que uma borda, deve ser adicionada ao redor da imagem. Geralmente, fornecemos 0 nesse valor. Bordas são geralmente usadas em filtros de texturas.

Os parâmetros format e type são parecidos com o internalFormat, mas dizem à OpenGL em que formato a imagem de origem, que foi carregada na memória pela SDL, tem. Existe uma extensa lista de parâmetros para cada uma delas e nossa classe inteligente poderá defini-los dinamicamente usando o que vimos no artigo anterior. Por hora, no exemplo, apenas diferenciaremos entre RGB e ARGB.

Finalmente, no parâmetro data devemos fornecer um array de bytes com a imagem em si.

A OpenGL ainda possui comandos para obtenção de texturas a partir do Color Buffer (glCopyTexImage2D) e substituição de texturas na memória (glTexSubImage3D e glCopyTexSubImage2D) .

Além de tudo isso, precisamos dizer à OpenGL como filtrar a textura. O filtro usado quando a imagem é ampliada ou reduzida. Esse será um dos tópicos dos próximos artigos.

Confuso? Que tal então um exemplo de código? Este exemplo, mostra como carregar uma textura a partir de uma superfície SDL.

void createTexture(SDL_Surface* image)
{   
   //Criamos um objeto de textura e obtemos seu id
    int id = 0;    glGenTextures(1, &id); 

    //Dizemos a OpenGL que iremos trabalhar com o objeto.
   glBindTexture(GL_TEXTURE_2D, id);

    //Filtro. Veremos isso nos próximos artigos.
   glTexParameteri(GL_TEXTURE_2D,
      GL_TEXTURE_MIN_FILTER, GL_NEAREST);

    //Descobrimos o formato a partir da imagem
   GLint format =
      image->format->BytesPerPixel == 3 ? GL_RGB : GL_RGBA;

    //Carregamos a imagem do disco
   glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0,
        format, GL_UNSIGNED_BYTE, image->pixels);

    //Como a OpenGL copiou a imagem, apagamos a SDL_Image.
   SDL_FreeSurface(image);
} 

Usando a textura

Uma vez carregada, apenas três passos são necessários para utilizar uma textura:

  1. Dar o glEnable em GL_TEXTURE1D, GL_TEXTURE2D ou GL_TEXTURE3D. Se você usar só texturas 2D (o que é muito comum) pode dar o glEnable logo no início do programa, como fizemos com a iluminação.
  2. Dizer à OpenGL que textura será aplicada usando o comando glBindTexture(GLenum target, GLuint texture); antes de começar a desenhar os vértices da nossa figura;
  3. Associar cada vértice a uma coordenada de textura através do comando glTexCoord2f, como descrito no início do artigo.

Por exemplo, para o caso daquele triângulo, poderíamos fazer assim:

//Liga a propriedade de texturização.
 glEnable(GL_TEXTURE_2D)

//Diz que usaremos a textura de mármore
 //MARMORE_MARROM seria uma constante com o ID da textura.
glBindTexture(GL_TEXTURE_2D, MARMORE_MARROM);
glBegin(GL_TRIANGLES);
       glTexCoord2f(1.0, 1.0f);
       glVertex2f(50.0f, 50.0f);

       glTexCoord2f(0.5, 0.5f);
       glVertex2f(25.0f, 25.0f);

       glTexCoord2f(0.0, 1.0f);
       glVertex2f(0.0f, 50.0f);
glEnd();

Mas minha textura ficou de cabeça para baixo!

Lembre-se que na SDL, o sistema de coordenadas baseia-se num y igual a 0 no topo da tela, e crescente, até a base da tela. Por isso, é normal que a SDL carregue as texturas de cabeça para baixo.

Você tem três formas de solucionar esse problema:

  • Inverter o fornecimento das coordenadas de textura em y;
  • Inverter as imagens da texturas;
  • Carregar as imagens e rotacioná-las (como explica em inglês, esse tutorial);

Das três soluções, eu geralmente prefiro a segunda. Ela não exige processamento, como a terceira, e é mais fácil de aplicar do que a primeira.
Além disso, não precisa ser aplicada à todas as imagens do jogo. Muitas texturas são disformes e se encaixam perfeitamente no sentido oposto.

Concluindo

Neste artigo, vimos de maneira básica como usar texturas. Você ainda pode baixar o exemplo sobre texturas que eu preparei para que vocês vejam o funcionamento de tudo na prática. Nos próximos artigos veremos o que são mipmaps e como configurar os filtros de texturas. Assim, você finalmente entenderá o que é são os filtros linear, bilinear, trilinear e anisotrópico, que os muitos jogos insistem em colocar nas configurações. Até lá!


Comentários (36)
  • mateus  - glGenTextures
    avatar

    Olá, o glGenTextures não altera o parametro
    textures, na segunda chamada da falha de segmentação!
    precisso de executar alguma função anteriormente?
    obrigado.

  • Vinícius Godoy de Mendonça
    avatar

    Como está o seu código?

    Outra coisa, certifique-se que você está tentando carregar as texturas após inicializar a OpenGL.

  • mateus
    avatar

    Pois é eu não havia testado após inicializar o OpenGl,
    agora funcionou perfeitamente! :lol:
    Obrigado.

  • Vinícius Godoy de Mendonça
    avatar

    Esse erro é bem mais comum do que você imagina. Principalmente quando você organizar o sistema em classes. Você vai ver que temos uma tendência forte a carrregar recursos antes de tudo, até mesmo de iniciar a OpenGL.

    Eu vivo fazendo dessas também.

  • Anônimo  - Dúvida texturas e transformações:
    avatar

    No casa de estarmos trabalhando com essas duas(texturas e transformações) qual seria mais adequado para desenhar na tela?... aplicar as posições sobre a textura(no caso os vértices) ou deixar por conta das transformações?
    Obrigado :D

  • Vinícius Godoy de Mendonça
    avatar

    São coisas diferentes. As texturas indicam como aplicar o desenho sobre a geometria. Não interessa a transformação que a geometria tenha sofrido.

    As transformações indicam qual será a posição que as geometrias serão desenhadas na tela. Uma geometria transformada terá sua textura automaticamente redimensionada.

  • Leonardo  - Entender
    avatar

    [url]eu queria saber se tem um tutorial que ensina criar o nosso próprio Motor 3D tanto em Open GL ou DX?
    Obrigado atenciosamente leonardo
    B)

  • Miguel  - Duvida
    avatar

    Bom dia, eu estou a tentar mapear uma textura para uma circunferência, alguém sabe como se fazer?

  • Bruno
    avatar

    Esse link tem bastante informação: http://vterrain.org/Textures/spherical.html

  • shaianny  - mais coisas
    avatar

    eu quero sobre textura geometrica,ate sexta feira :?: :kiss:

  • Willian  - Duvida modificar Textura
    avatar

    Ola carreguei uma textura, mas quando tento modificar para outra imagem
    o seguinte erro acontece:
    GLUT: Warning in (unamed): GL error: estouro de pilha

    Pode me ajudar?

  • Anônimo
    avatar

    Poste o código em algum serviço como codepad.org que fica mais simples lhe ajudar.

  • Willian
    avatar

    Então deixa explicar melhor, tenho uma classe java usando Gl4java para Opengl java, mas quando tento carregar uma nova textura (.jpg, .png, .gif), ai ocorre a mensagem de erro :
    GLUT: Warning in (unamed): GL error: estouro de pilha
    Mas mesmo assim a textura é carregada.
    Sou novo com Opengl não tenho muito conhecimento.

    http://codepad.org/BB4Wtbtv, http://codepad.org/VszqgoSk

  • Vinícius Godoy de Mendonça
    avatar

    Nossa, GL4Java? Esse projeto nem é mais mantido. Por que não usa a LWJGL?

  • Willian
    avatar

    O Vinícius valeu pela dica, mas é que baixei a api Jartoolkit para Realidade Aumentada e tinha um exemplo de gl4java com RA.
    Ai decidi utilizar, mas depois descobri que não se usasva mais gl4java.

    Alguma dica de como utilizar LWJGL com RA.

  • Vinícius Godoy de Mendonça
    avatar

    Você quer é brincar com visão computacional e RA? Nesse caso, eu recomendo outra API completamente diferente, a javacv: http://code.google.com/p/javacv/

    Ela integra opencv e a ARToolkit, um dos principais frameworks de RA da atualidade, além de classes para captura de vídeo, inclusive com Kinect.

    Para desenhar os modelos, use uma engine, como a JMonkeyEngine:
    http://jmonkeyengine.com/

    Ela vai controlar a OpenGL, te fornecendo um motor gráfico poderoso (com iluminação, shaders de efeitos, etc), associado a um editor de cenários e classes prontas para classe de modelos.

    A única dificuldade que você vai ter é realmente estudar a documentação. A JMonkey é bem documentada, mas a javacv exigirá que você leia documentação escrita para C++. A vantagem é que é muito mais documentação do que você encontraria em libs pequenas como as que você citou.

  • fredy  - Falta arquivos
    avatar

    fiz o download do código exemplo de texturas, no entanto falta os seguintes arquivos: mathutil.h, vector3d.h e vector2d.h.

  • ViniGodoy
    avatar

    Esses arquivos você pode baixar do artigo de vetores: http://bit.ly/usovetores

  • fredy
    avatar

    para na seguinte liha:

    //Desenhamos a face. Observe o mapeamento das coordenadas
    glBegin(GL_QUADS);
    glNormal3f(normal.getX(), normal.getY(), normal.getZ());
    glTexCoord2d(0,1);

    menssagem de erro:

    C:\Users\IronSoft\Desktop\Games\CODIGO\text ura\Cubo.cpp|242|error: 'class math::Vector3D' has no member named 'getX'|
    C:\Users\IronSoft\Desktop\Games\CODIGO\textura \Cubo.cpp|242|error: 'class math::Vector3D' has no member named 'getY'|
    C:\Users\IronSoft\Desktop\Games\CODIGO\textura \Cubo.cpp|242|error: 'class math::Vector3D' has no member named 'getZ'|
    ||=== Build finished: 3 errors, 8 warnings (0 minutes, 2 seconds) ===|

  • Vinícius Godoy
    avatar

    Oi. Não existe método getX(). Você pode acessar o x, y e z do vector diretamente:
    //Desenhamos a face. Observe o mapeamento das coordenadas
    glBegin(GL_QUADS);
    glNormal3f(normal.x, normal.y, normal.z);
    glTexCoord2d(0,1);

    Se você está desenhando 2D usando a OpenGL, eu deixaria o glLighting desligado, para não ter que fornecer normais de luz. Assim a intensidade do desenho você controlaria somente pelo glColor3f.

  • fredy  - duvidas sobre a imagem
    avatar

    + Estou carregando a em imagem 2d em um quadrado. Dúvidas...

    i - ...como inverter a imagem que está de ponta cabeça?
    ii - ...porque as cores estão desbotadas (o laranja fica azul claro)?
    ii - ...porque quando teclo para a direita o personagem desloca-se para a esquerda sendo que o recíproco é verdadeiro?

  • ViniGodoy
    avatar

    I - Simplesmente inverta o y das suas coordenadas de textura. Isso ocorre porque, por padrão, os sistemas de coordenadas da SDL e da OpenGL são invertidos;
    II - Na função setupOpenGL, experimente deixar essa linha assim:
    SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 24);
    III - Sem ver seu código, fica impossível responder.

  • fredy  - re:
    avatar

    Srs, primeiramente obrigado pela atenção...

    i - deu certo (modifiquei as coordenadas do quadrado e da textura)!

    glBegin(GL_QUADS);

    glTexCoord2f(0.0, 0.0);
    glVertex3f(-0.5, 0.5, 0.0);

    glTexCoord2f(0.0, 1.0);
    glVertex3f(-0.5, -0.5, 0.0);

    glTexCoord2f(1.0, 1.0);
    glVertex3f(0.5, -0.5, 0.0);

    glTexCoord2f(1.0, 0.0);
    glVertex3f(0.5, 0.5, 0.0);

    glEnd();

    ii - ...continua com uma imagem pálida e de baixa definição;
    iii - deu certo após a correção do item i;

  • Vinícius Godoy de Mendonça
    avatar

    Oi.

    No caso do item 2, qual é o formato de imagem que você está utilizando? Observe que o software de textura que coloquei serve apenas para imagens no padrão RGB (como PNG) e não BGR (como o BMP).

  • fredy  - mapa
    avatar

    Obrigado Godoy!
    tenho mais uma questão.... como carregar um cenário (em 2d) maior que a área gráfica (ex: como o Age of Empires) e deslocar-me por ele através dos direcionais do teclado?

    ...fiz isso há uns 7 anos atrás utilizando o vc++ e directx e era bem mais simples.

  • fredy  - quadrado sem cor
    avatar

    como desenhar um quadrado sem cor e totalmente transparente?

    //Limpa a tela
    glClearColor(0.0, 0.0, 1.0, 0.0); //

  • Anônimo
    avatar

    O glClearColor apenas especifica a cor para ser usado no clear.

    Para limpar a tela, use glClear: http://www.opengl.org/sdk/docs/man/xhtml/glClear.xml

  • Anônimo  - re: quadrado com transparência
    avatar

    ...desculpe, o meu texto saiu incompleto....

    Limpa a tela
    glClearColor(0.0, 0.0, 1.0, 0.0);

  • Anônimo
    avatar

    E qual a dúvida? glClearColor não limpa a tela, como expliquei.

  • fredy  - quadrado com transparência
    avatar

    novamente o texto saiu incompleto, segue o endereço...

    http://notepad.cc/share/foW2aT8Ogi

  • Anônimo
    avatar

    Penso que o que você esta vendo é o canal alpha da textura e não a cor de fundo do polígono. Tem que se configurar as operações de alpha do OpenGL para a transparência funcionar, mas é algo que não lembro de cabeça.

  • Vinícius Godoy de Mendonça
    avatar

    Leia o nosso capítulo sobre Blending: http://www.pontov.com.br/site/index.php/opengl/223-combinando-cores-bl ending

  • fredy  - quadrado incolor
    avatar

    ...vou ler novamente.... inclusive já setei diversos valores e configrações da API e o máximo que consegui foi uma transparência translúcida e/ou opaca, mesmo assim agradeço a atenção.

  • fredy  - re: quadrado incolor
    avatar

    deu certo... obrigado...

  • programadorOpenGL  - Como posso montar a expressão de uma arcada dentar
    avatar

    Não estou conseguindo inicializar no Open GL e mto menos entendi como monto uma arcada dentária

  • Pedro  - Como pegar o "w" e "h"
    avatar

    Na função glTexImage2D(), exige que eu especifica a largura e altura da imagem, devo utilizar alguma função ou são valores arbitrários?

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