Computação Gráfica Geração de Geometria - Terrenos António Ramires Fernandes + Luís Paulo Santos - Computação Gráfica 08/09 Mapas de Alturas Intensidade por pixel pode representar uma altura numa grelha regular DI-UM Computação Gráfica 06/07 2 Terrenos a partir de Imagens • Objectivo: – Dada uma imagem criar uma grelha regular em que a altura de cada ponto da grelha corresponde à intensidade do pixel correspondente. • Tarefas: – Carregar a imagem – Criar a geometria do terreno a partir da matriz de pixels extraída da imagem. – Colocar todas as entidades do modelo na altura correcta DI-UM Computação Gráfica 06/07 3 Carregar a Imagem - tgalib • Em www.lighthouse3d.com é disponibilizado código para carregar TARGA (.TGA): tgaInfo * tgaLoad(char *filename); typedef struct { int status; unsigned char type, pixelDepth; short int width, height; unsigned char *imageData; }tgaInfo; DI-UM Computação Gráfica 06/07 4 Alternativa: DevIL • http://openil.sourceforge.net/ “A full featured cross-platform image library” • Abrir um ficheiro de imagem ilInit(); ilGenImages(1,ima); // unsigned int ima[...] ilBindImage(ima[0]); ilLoadImage(filename); // char *filename DI-UM Computação Gráfica 06/07 5 Alternativa: DevIL • Aceder aos dados e informações da imagem int width = ilGetInteger(IL_IMAGE_WIDTH); int height = ilGetInteger(IL_IMAGE_HEIGHT); unsigned char *imageData = ilGetData(); DI-UM Computação Gráfica 06/07 6 Alternativa: DevIL • Converter para escala de cinzentos ilConvertImage(IL_LUMINANCE,IL_UNSIGNED_BYTE); outras opções: IL_RGB, IL_RGBA DI-UM Computação Gráfica 06/07 7 Alternativa: DevIL • Exemplo para carregar uma imagem: unsigned int t; ilGenImages(1,&t); ilBindImage(t); ilLoadImage("bla.jpg"); tw = ilGetInteger(IL_IMAGE_WIDTH); th = ilGetInteger(IL_IMAGE_HEIGHT); imgData = ilGetData(); DI-UM Computação Gráfica 06/07 8 Geração de geometria z (0,0) Mundo zt x (0,0) H-Map xt • Gerar o terreno como uma strip de triângulos, sendo y dados pelo valor do h-map no ponto (xt,zt) • Origem (0,0) no centro do mundo e canto do H-Map • Atenção aos diferentes sistemas de eixos DI-UM Computação Gráfica 06/07 9 Geração de geometria z zt (0,0) Mundo (0,0) x for (z=0 ; z < for (x=0 ; x glVertex3f glVertex3f glEnd(); } MapL-1 < MapW (x0+x, (x0+x, H-Map xt ; z++) { glBegin(GL_TRIANGLE_STRIP); ; x++) { Map[x][z+1], z0-(z+1)); Map[x][z], z0-z); } DI-UM Computação Gráfica 06/07 10 Geometria: Display Lists • Conjunto de comandos pré-compilados que podem ser reutilizados: // Create the id for the display list terrainDL = glGenLists(1); // create the display list glNewList(terrainDL,GL_COMPILE); for (z=0 ; z < MapL-1 ; z++) { glBegin(GL_TRIANGLE_STRIP); for (x=0 ; x < MapW ; x++) { glVertex3f (x0+x, Map[x][z+1], z0-(z+1)); glVertex3f (x0+x, Map[x][z], z0-z); } glEnd(); } glEndList(); DI-UM Computação Gráfica 06/07 11 Geometria: Display Lists • Na função que desenha a cena (ex., renderScene()) basta chamar a display list: glCallList (TerrainDL); • Permite um aumento de desempenho significativo devido à précompilação dos comandos de especificação da geometria • Uma display list pode ser alterada executando de novo glNewList() .. glEndList() • Uma display list pode ser removida com glDeleteLists() DI-UM Computação Gráfica 06/07 12 Geometria: terrain.cpp • O ficheiro terrain.cpp disponibiliza o esqueleto de código para: – Carregar o h-map a partir e um ficheiro (usando tgaLoad()) int terrainLoadImage (char *filename, int normals); – Criar a display list devolvendo o seu ID int terrainCreateDL (float xOff, float yOff, float zOff); – Dadas as coordenadas do mundo (x,z) devolver a respectiva altura de acordo com o height map float terrainGetHeight (float x, float z); DI-UM Computação Gráfica 06/07 13 Exercício • Adapte a aplicação desenvolvida nas sessões anteriores para que: – Carregue um height map e desenhe o terreno de acordo com estes – Posicione os vários elementos (indios, cowboys, arvores, tesouro) à altura apropriada – A câmara móvel faça surface following, isto é, se desloque ao longo da superfície adaptando-se à respectiva altura DI-UM Computação Gráfica 06/07 14 Interpolação bilinear • As coordenadas no mundo são números reais, as coordenadas no mapa de textura são inteiros (melhor, o h-map só está definido para coordenadas inteiras) • Solução: interpolação bilinear hb z2 x1 = int(x); xFrac = frac(x); x2 = x1+1; z1 = int(z); zFrac = frac(z); z2 = z1+1; (x,z) ha = h(x1,z1)*(1-xFrac) + h(x2,z1)*xFrac; hb = h(x1,z2)*(1-xFrac) + h(x2,z2)*xFrac; zFrac z1 x1 ha x2 h = há*(1-zFrac) + hb*zFrac; xFrac DI-UM Computação Gráfica 06/07 15 Mapeamento • Neste momento, a área do terreno é determinado pela resolução do h-map. Modifique o código de forma a que o utilizador possa indicar a resolução pretendida para o terreno, invocando a função terrainDim (int wWidth, int wLength); • Note que para passar de coordenadas (x,z) do mundo para (xt, zt) do h-map deverá aplicar a função: ( xt, zt ) f ( x, z ) ( x * GridWidth GridWidth GridLength GridLength , z* ) 2 2 wWidth wLength DI-UM Computação Gráfica 06/07 16