Os seguintes exercícios propõem
prática e fixação do mapeamento de
texturas usando OpenGL.
1. Especificando coordenandas de textura
manualmente e usando múltiplas texturas.
Criem um objeto simples usando quads (para
simplificar) ou triângulos em Opengl (não precisa usar a
classe malha). Digamos, um cubo. Agora, usando 6 imagens de textura que
vocês mesmos podem criar no Paint ou onde preferirem, transformem
o cubo em um dado. Basicamente, será necessário passar as
coordenadas dos vértices, um por um, e as coordenadas de
textura, uma a uma. Será também necessário criar
as 6 texturas a partir de 6 arquivos e fazer o binde de cada uma.

Fig. 1. Exemplo de resultado
esperado
2. Combinando texturas
Agora, experimentem combinar duas ou mais texturas
em um único objeto, sobrepondo-as.
Primeiro, criem um ambiente com mais de um objeto e mapeiem uma textura
em cada. Têm total liberdade para escolher como modelar os
objetos e como passar as coordenadas de textura. Para começar,
eu sugiro usar os objetos que já usamos nas aulas anteriores e
mesmo nesta.
Em seguida, experimentem mapear as duas texturas
sobre o mesmo objeto. Como?
Usaremos uma extensão da OpenGL (ARB) que
está definida no arquivo: #include <GL/glew.h>
Este arquivo permite fazer chamadas para a função:
|
glClientActiveTexture( id da textura ); // id da textura será GL_TEXTURE0 ou GL_TEXTURE1
|
Isso permite alterar parâmetros de cada
textura separadamente. Assim, podemos usar o modo BLEND e MODULATE com
o GL_TEXTURE_ENV_MODE
para a segunda textura.
Baixem a glew a partir de: http://glew.sourceforge.net
Ajustem os includes e as libraries para o compilador e o ligador.
Usuários do
Dev-C++:
O Dev-C++ não entende a estrutura do arquivo .lib da glew. Uma
solução é usar a glew32.dll diretamente no ligador
do Dev. Depois de baixar os binários Windows do site da GLEW,
copiem o glew32.dll no diretório do seu projeto. No Dev-C++
façam:
> Project
> Project Options
> Parameters
> Add Library or
Object
> Troque o Files Type
para todos os arquivos (*.*)
> Selecione glew32.dll
> Clique OK
|
glActiveTexture(GL_TEXTURE0);
glEnable( GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,textureObjects[0]);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glActiveTexture(GL_TEXTURE1);
glEnable( GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,textureObjects[1]);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
Um detalhe que falta é que será
preciso também enviar as coordenadas de textura separadamente
para cada textura.
Com a abordagem clássica:
|
glBegin( GL_QUADS );
glMultiTexCoord2f(
GL_TEXTURE0_ARB, 0.0f, 0.0f );
glMultiTexCoord2f(
GL_TEXTURE1_ARB, 0.0f, 0.0f );
glVertex3f( -1.0f, -1.0f, 0.0f );
glMultiTexCoord2f(
GL_TEXTURE0_ARB, 0.0f, 1.0f );
glMultiTexCoord2f(
GL_TEXTURE1_ARB, 0.0f, 1.0f );
glVertex3f( -1.0f, 1.0f, 0.0f );
(...)
glEnd();
|
Com a abordagem mais moderna e rápida:
|
// na drawMesh ou
função equivalente
glVertexPointer(3,GL_FLOAT,0,m->verts); //passa os
vértices
glClientActiveTexture(GL_TEXTURE0);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2,GL_FLOAT,0,m->uvs); // passa as
coord de textura para a primeira textura
glClientActiveTexture(GL_TEXTURE1);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2,GL_FLOAT,0,m->uvs); //
passa as coord de textura para a segunda textura
glDrawElements
(GL_TRIANGLES,m->nbrTris*3,GL_UNSIGNED_INT,m->tris);
|
Obs. O mesmo
efeito pode ser obtido carregando duas imagens,
modulando as duas em uma terceira imagem e só então
fazendo o bind dessa terceira imagem na textura. A
modulação pode ser qualquer operação entre
cada pixel. Se quiserem, experimentem intuitivamente várias
possibilidades. Essa abordagem tem a desvantagem de ser processada via
software na CPU, enquanto que a anterior é feita pelo hardware
da GPU.
3. Textura de elevações
Estamos acostumados a usar texturas como imagens,
carregando informação de cor. No entanto, existem
diversas outra aplicações para a textura. Experimentem
agora usar a informação da textura na modelagem de um
terreno acidentado.
Carreguem dois arquivos de imagem: um em tons de cinza para as
elevações; um colorido para a textura de cor do terreno.
O arquivo de elevações será usado em tempo de
modelagem, dentro de uma função createMesh, que
usará dois laços encadeados para gerar uma malha
retangular de triângulos ou quads. Pensem em dar o número
de triângulos ou quads e a altura máxima como
parâmetro para a função. Dentro dela, para cada
vértice gerado no plano (x, y), usem a imagem em cinza para
produzir z. Por exemplo, se o valor (u, v) da imagem for preto, z
será 0. Se for 1, z será a altura máxima. Outros
tons de cinza gerarão alturas intermediárias.
Chamem a função na init() para gerar a malha. Exibam a
malha gerada na display mapeando a textura de cor sobre ela.
Experimentem usar cores que correspondem a altura. Por exemplo: altura
0 coloquem cor de água; altura acima de 3000 cor de neve.
4. Bump mapping e outros efeitos
Texturas também podem ser usadas para alterar o
comprimento e a orientação dos vetores normais de uma
malha para produzir efeitos de realismo, como relevo, sem alterar a
geometria. Como as operações de rendering envolvendo as
normais são executadas para cada pixel, em OpenGL padrão
é bastante complicado aplicar bumps. Faremos bump e relieve
mapping mais tarde quando estudarmos a programação de
shaders. Aí, faremos implementações personalizadas
do programa de shading de vértices e fragmentos para modular
cores e normais.