edinalda maria de souza um estudo sobre um algoritmo para...
TRANSCRIPT
Edinalda Maria de Souza
Um Estudo sobre um Algoritmo para Visualização de Terrenos
Dissertação de Mestrado
Dissertação apresentada como requisito parcial para obtenção do título de Mestre pelo Programa de Pós-Graduação em Informática da PUC-Rio.
Orientador: Prof. Marcelo Gattass
Rio de Janeiro, agosto de 2003
Edinalda Maria de Souza
Um Estudo sobre um Algoritmo para Visualização de Terrenos
Dissertação apresentada como requisito parcial para obtenção do título de Mestre pelo Programa de Pós-Graduação em Informática da PUC-Rio. Aprovada pela Comissão Examinadora abaixo assinada.
Marcelo Gattass Orientador
Departamento de Informática-PUC-Rio
Prof. Waldemar Celes Filho Departamento de Informática-PUC-Rio.
Prof. Luiz Fernando Campos Ramos Martha Departamento de Engenharia Civil-PUC-Rio.
Prof. Alberto Barbosa Raposo Departamento de Informática-PUC-Rio.
Prof. Roberto Beauclair Seixas Instituto Nacional de Matemática Pura e Aplicada(IMPA).
Prof. Ney Augusto Dumont Coordenador(a) Setorial do Centro Técnico Científico - PUC-Rio
Rio de Janeiro, 04 de julho de 2003
Todos os direitos reservados. É proibida a reprodução total ou parcial do trabalho sem autorização da universidade, da autora e do orientador.
Edinalda Maria de Souza Graduou-se em Ciências da Computação na UFG (Universidade Federal de Goiás) em 1997. Especializou-se em Redes de Computadores também na Universidade Federal de Goiás em 1999. Trabalhou como Analista de Sistemas na Telegoiás S/A entre 1997 e 2000, onde atuou no desenvolvimento e manutenção de sistemas para transferência de assinaturas telefônicas. Desde 2002 está trabalhando no desenvolvimento das interfaces e algoritmos para visualização dos dados do projeto SISMOSEG3D (parceria Tecgraf/PUC-Rio e Petrobras) cujo principal objetivo é auxiliar na interpretação de dados sísmicos 3D selecionados em camadas.
Ficha Catalográfica
Souza, Edinalda Maria de Um estudo sobre um algoritmo para visualização de terrenos / Edinalda Maria de Souza; orientador: Marcelo Gattass. – Rio de Janeiro : PUC, Departamento de Informática, 2003. [12], 78 f. : il. ; 30 cm Dissertação (mestrado) – Pontifícia Universidade Católica do Rio de Janeiro, Departamento de Informática. Inclui referências bibliográficas. 1. Informática – Teses. 2. Refinamento dependente da visão. 3. Visualização de terrenos. 4. Malha de triângulos. 5. Tempo real. I. Gattass, Marcelo. II. Pontifícia Universidade Católica do Rio de Janeiro. Departamento de Informática. III. Título.
CDD: 004
Aos meus pais, meu irmão e minha irmã.
Agradecimentos
Ao meu orientador Marcelo Gattass pelo apoio, dedicação e paciência que
tornaram este trabalho possível.
À CAPES e à PUC-Rio pelo apoio financeiro.
À Paula Frederick pela ajuda importante na fase de implementação deste trabalho.
Aos membros da banca examinadora pelas correções e sugestões.
Ao professor Luiz Henrique de Fiqueiredo pelas sugestões.
Ao Centro de Instruções Almirante Sylvio de Camargo da Marinha do Brasil pela
utilização do programa SJD-Vis3D e dos terrenos representando a região de
Itaóca-ES.
A Anselmo Montenegro pela disponibilização dos terrenos cvzbuffalo e ilha.
À Carolina Alfaro de Carvalho pela revisão do texto desta dissertação.
Aos meus professores de Mestrado Marcus Vinicius Soledade Poggi de Aragão,
Paulo Cézar P. Carvalho, Sinésio Pesco, Bruno Feijó e Luiz Velho pelos
conhecimentos transmitidos.
Aos colegas e amigos do Tecgraf, do departamento de Informática da PUC-Rio e
do Instituto Social do Rio de Janeiro pelas experiências e momentos de
descontração compartilhados.
À minha família e a Deus por tudo.
Resumo
Souza, Edinalda M.; Gattass, Marcelo(Orientador). Um Estudo sobre um Algoritmo para Visualização de Terrenos. Rio de Janeiro, 2003. 78p. Dissertação de Mestrado - Departamento de Informática, Pontifícia Universidade Católica do Rio de Janeiro.
Algoritmos para visualização interativa de terrenos são complexos e, ao
mesmo tempo, de grande importância para muitas aplicações como jogos e
planejamento de atividades sobre terrenos. Em função desta complexidade e
importância, o tema merecido, na última década, muita atenção da comunidade de
pesquisadores em Computação Gráfica e, conseqüentemente, muitas estratégias
têm sido desenvolvidas. Entre as mais bem sucedidas estratégias, destacam-se os
recentes trabalhos de Lindstrom e Pascucci. O algoritmo proposto por estes
autores possui diversas implementações disponíveis na Internet e merece ser re-
avaliado. Esta dissertação faz esta re-avaliação através de uma implementação
independente feita pela autora e testada sobre uma base de terrenos reais. Com o
objetivo de tornar esta análise mais completa e dar suporte a algumas conclusões,
resultados comparativos de outros algoritmos da área também são apresentados.
Palavras-chave Refinamento dependente da visão, visualização de terrenos, malha de
triângulos, tempo real.
Abstract
Souza, Edinalda M.; Gattass, Marcelo(Advisor). A Study of Terrain-Visualization Algorithm. Rio de Janeiro, 2003. 78p. MSc. Dissertation – Departamento de Informática, Pontifícia Universidade Católica do Rio de Janeiro.
Algorithms for the interactive visualization of terrains are very complex
and, at the same time, of great importance to many applications, such as games
and activity-planning over terrains. Due to such complexity and importance, in the
past decade this subject has received great attention by researchers on Computer
Graphics. As a consequence, a number of strategies have been developed. Among
the most successful strategies, one can highlight recent works by Lindstrom and
Pascucci. The algorithm proposed by these authors has various implementations
available in the Internet and deserves to be reevaluated. The present work makes
such reevaluation by means of an independent implementation developed by the
author and tested over a base or real terrains. With the purpose of making this
analysis more complete and to support some conclusions, comparative results
with other algorithms in the area are also presented.
Keywords View-dependent refinement, terrain visualization, triangle mesh, real-time.
Sumário
1 Introdução 1
2 Conceitos Básicos e Trabalhos Relacionados 3
2.1. Conceitos Básicos 3
2.1.1. Representação e Reconstrução de Terrenos 3
2.1.2. Métricas de Erro 4
2.1.3. Malha Válida 6
2.1.4. Construção da Hierarquia de Malhas 7
2.1.5. Representação por Níveis de Detalhes Dependente da Visão 8
2.1.6. Descarte de Regiões Invisíveis 10
2.1.7. Transições Suaves na Geometria 10
2.2. Trabalhos Relacionados 11
3 Descrição do Algoritmo 15
3.1. Refinamento 17
3.2. Métricas de Erro 19
3.3. Pré-Processamento 20
3.4. Procedimento para Refinamento em Tempo Real 26
3.5. Procedimento para Culling da Malha fora da Visão 30
3.6. Calculando o Frustum de Visão 32
3.7. Procedimento para Geomorphing 37
4 Testes 40
4.1. Breve Descrição da Aplicação 40
4.2. Descrição dos Testes com a Aplicação SJD-Vis3D 40
4.2.1. Verificando o Culling da Malha fora da Visão 46
4.2.2. Verificando o Geomorphing 49
4.2.3. Verificando a Strip de Triângulos 53
4.2.4. Verificando o Pré-Processamento 55
4.2.5. Comparando os Algoritmos de Lindstrom & Pascucci e de De Boer56
4.2.6. Verificando o Número de Triângulos da Malha Gerada 61
5 Conclusão 65
5.1. Trabalhos Futuros 67
6 Referências Bibliográficas 69
Apêndice A – Descrição da Aplicação SJD-Vis3D 71
A1. Definição dos Terrenos para o SJD-Vis3D 73
A1.1. Mapa de Alturas 73
A.1.2 Textura 74
Apêndice B – Descrição do Módulo Terreno 76
Lista de Figuras
Figura 1 - Exemplo de Malha produzida pelo algoritmo em estudo. ...........5
Figura 2 - Erro absoluto e erro relativo. ......................................................6
Figura 3 - Exemplo de vértice T e aresta sem face. ...................................7
Figura 4 - Seqüência de malhas da mesma superfície...............................7
Figura 5 - a) Vértice T formado entre diferentes níveis de detalhes; b)
Transição suave entre diferentes níveis de detalhes...........................9
Figura 6 - Modelo de multi-resolução de uma superfície: a) nível 0; b) nível
1; c) nível 2 e d) nível 3. ......................................................................9
Figura 7 - a) Aresta de i para j no DAG; b) Destacando arestas no DAG de
uma malha.........................................................................................16
Figura 8 - Malha com esferas envolventes ...............................................18
Figura 9 - Terreno dividido recursivamente em blocos. ............................21
Figura 10 - Vértices de um bloco. .............................................................22
Figura 11 - Destacando os vértices que aproximam os vértices
eventualmente ausentes. ..................................................................22
Figura 12 - Bloco processado pelo procedimento IniciaErros...................23
Figura 13 - Os blocos ímpares estão circulados e os pares não. .............24
Figura 14 - Malha-base.............................................................................26
Figura 15 - Destacando filhos direito e esquerdo do vértice j. ..................27
Figura 16 – Animação da renderização de uma strip de triângulos. .........30
Figura 17 - Esferas Envolventes Aninhadas.............................................32
Figura 18 - Frustum de Visão ...................................................................33
Figura 19 - Caminho sobre o terreno Itaoca1 ...........................................42
Figura 20 - Caminho sobre o terreno Itaoca2. ..........................................43
Figura 21 - Caminho sobre o terreno Washington1..................................44
Figura 22 - Caminho sobre o terreno Washington2..................................45
Figura 23 - Comparação do número de triângulos gerados com e sem a
operação de culling fora da visão. .....................................................48
Figura 24 - Quadro do terreno Washington1 ............................................49
Figura 25 - Gráficos comparativos entre o número de triângulos
desenhados. ......................................................................................52
Figura 26 - Gráficos comparativos entre o número total de triângulos ou
vértices enviados para o pipeline gráfico e o número de triângulos
válidos. ..............................................................................................55
Figura 27 - Comparação dos algoritmos de Lindstrom & Pascucci e de De
Boer nas plataformas P1 e P2...........................................................59
Figura 28 - Imagens do terreno ilha..........................................................62
Figura 29 - Imagens do Terreno cvzbuffalo ..............................................63
Figura 30 - Janela do SJD-Vis3D. ............................................................72
Figura 31 - Diagrama de entradas e saídas das funções
TrnPreprocessamento e TrnGeraMalha. ...........................................76
Lista de Tabelas
Tabela 1 - Planos que formam o frustum de visão ...................................34
Tabela 2 - Dados dos Terrenos. ...............................................................41
Tabela 3 - FPS Médio de cada caminho feito com e sem culling na
plataforma 1. .....................................................................................46
Tabela 4 - FPS Médio de cada caminho feito com e sem culling na
plataforma 2. .....................................................................................46
Tabela 5 - FPS Médio de cada caminho feito com e sem geomorphing na
plataforma 1. .....................................................................................50
Tabela 6 - FPS Médio de cada caminho feito com e sem geomorphing na
plataforma 2. .....................................................................................50
Tabela 7 - Tempo médio do pré-processamento de cada terreno............56
Tabela 8 - Comparação do caminho Itaoca1 com ambos os algoritmos e
ambas as plataformas. ......................................................................57
Tabela 9 - Comparação do caminho Itaoca2 com ambos os algoritmos e
ambas as plataformas. ......................................................................57
Tabela 10 - Comparação do caminho Washington1 com ambos os
algoritmos e ambas as plataformas...................................................57
Tabela 11 - Comparação do caminho Washington2 com ambos os
algoritmos e ambas as plataformas...................................................57
Tabela 12 - Características dos terrenos testados. ..................................61
Tabela 13 - Número de triângulos gerados para o terreno ilha. ...............62
Tabela 14 - Número de triângulos gerados para o terreno cvzbuffalo......63
1 Introdução
A visualização de terrenos tem sido amplamente utilizada em muitas
aplicações, como jogos de entretenimento tridimensionais, simuladores de vôos
industriais, aplicações militares, científicas, geológicas e assim por diante.
Recentemente, com a difusão do uso da Realidade Virtual em diversas áreas, esta
lista tem crescido ainda mais.
O problema é que os dados que representam digitalmente um terreno são
geralmente bastante volumosos. Assim, mesmo os hardwares mais modernos
enfrentam dificuldades para gerar quadros em taxas interativas e com imagens de
boa qualidade visual. Portanto, a visualização de terrenos ainda é considerada um
problema desafiador na Computação Gráfica e muitos pesquisadores têm se
dedicado a ele. A verdade é que, nas aplicações que fornecem suporte para
aplicações de realidade virtual (incluindo a visualização de terrenos), mesmo
considerando toda a evolução da indústria de hardware, normalmente ainda
obtemos melhores resultados investindo em algoritmos suficientemente eficazes
que em hardwares especializados e caros[1]. Além disso, independente da
evolução constante da indústria de hardware, assumimos que será muito difícil,
senão impossível, que estes, sozinhos, consigam atender à crescente demanda
atual. Afinal, à medida que a indústria de hardware evolui, tem crescido também o
volume dos dados de terrenos (com superfícies cada vez mais complexas). Além
disso, a tendência é que as aplicações e, em última instância, os usuários, exijam
representações cada vez mais fiéis da realidade.
Deste modo, nos últimos anos têm sido propostos vários algoritmos e
estratégias para visualização de terrenos. Dentre as estratégias para melhorar a
visualização de terrenos, destacam-se a representação por níveis de detalhes
dependente da visão, o descarte rápido de regiões temporariamente invisíveis do
terreno (culling da malha fora da visão) e técnicas para realizar transições suaves
na geometria da malha (geomorphing). Estas estratégias serão discutidas mais
adiante.
2
Todos os algoritmos desenvolvidos para visualização de terrenos trabalham
no sentido de tentar melhorar a interatividade e a qualidade visual das imagens
produzidas. Contudo, a maioria emprega técnicas algorítmicas complexas e
portanto difíceis de serem implementadas. O algoritmo proposto por Lindstrom &
Pascucci em [2] e estendido em [3] destaca-se sobretudo pela eficiência e
simplicidade.
Assim, esta dissertação procura investigar e compreender o problema da
visualização interativa de terrenos e, mais especificamente, o algoritmo
desenvolvido por Lindstrom & Pascucci em [2] e estendido em [3]. Ela foi
organizada em cinco capítulos, conforme descrito, resumidamente, a seguir.
O capítulo 2 está dividido em duas seções principais. A primeira delas
apresenta, sinteticamente, alguns conceitos básicos importantes para o
entendimento do trabalho. A segunda seção apresenta um resumo dos trabalhos
mais importantes, recentes e relacionados ao problema da visualização interativa
de terrenos.
O capítulo 3 descreve o algoritmo título do trabalho, incluindo pseudo-
códigos das diferentes etapas.
O capítulo 4 apresenta os testes realizados através de nossa implementação
com o propósito de verificar e entender o comportamento prático do algoritmo.
Finalmente, o capítulo 5 encerra este trabalho com uma seção de conclusão
e outra contendo possíveis trabalhos futuros.
2 Conceitos Básicos e Trabalhos Relacionados
Neste capítulo apresentamos, resumidamente, alguns conceitos básicos
necessários para o entendimento do trabalho. Uma descrição mais detalhada
destes conceitos pode ser encontrada em [4]. Depois, segue-se uma seção
resumindo alguns outros trabalhos importantes encontrados na literatura e
relacionados ao problema principal tratado neste trabalho que é a visualização
interativa de terrenos.
2.1. Conceitos Básicos
Os conceitos básicos considerados importantes para o entendimento deste
trabalho tratam da representação e reconstrução de terrenos, métricas de erro,
requisitos de malhas, construção da hierarquia de malhas, representação por níveis
de detalhes, descarte de regiões invisíveis e transições suaves na geometria. A
seguir, apresentamos, brevemente, cada um destes conceitos.
2.1.1. Representação e Reconstrução de Terrenos
A geometria de um terreno é normalmente representada de forma discreta,
ou seja, guardando algumas amostras que representem o terreno. Neste caso, cada
amostra contém suas coordenadas x, y e z, onde z representa a altura do terreno
naquele ponto (daí a nomenclatura “campos de altura”, comumente utilizada para
se referir a este tipo de dado). Estas amostras podem ser regularmente espaçadas,
de modo que todas juntas formem uma grade, ou podem ser irregularmente
espaçadas.
A reconstrução do terreno a partir da representação discreta mencionada
acima e tratada neste trabalho consiste em gerar uma aproximação através de uma
malha de polígonos (geralmente triângulos, onde cada vértice corresponde a uma
4
amostra). Finalmente, esta malha é coberta com alguma textura que represente a
radiação luminosa dos materiais do terreno para uma dada iluminação.
Com amostras irregularmente espaçadas é possível obter maior eficiência
em termos de armazenamento. Neste caso, é possível adequar o número de
amostras à geometria do terreno, ou seja, guardar um número maior de amostras
para representar as regiões mais acidentadas e um número menor de amostras para
representar as regiões menos acidentadas do terreno. No caso das amostras
regularmente espaçadas isto não é possível e, normalmente, acontece uma
redundância nas regiões mais planas do terreno. Entretanto, não ter os dados
dispostos em uma grade implica não poder tirar vantagem de estruturas de dados
simples e de rápido acesso como árvores quaternárias e matrizes. Na prática, isto
implica ter algoritmos bem mais complexos para a geração da malha do terreno.
Por questão de simplicidade, atualmente, a maioria das representações de
terrenos utiliza grades regulares. Assim, o algoritmo estudado neste trabalho
baseia-se nesta representação. Na Figura 1 apresentamos uma malha construída
pelo algoritmo descrito neste trabalho. Repare que ela, de fato, é construída sobre
uma grade regular e pode ser enxergada através de quatro árvores binárias de
triângulos. Conforme será visto mais adiante, na verdade esta malha aproximada é
construída executando-se um procedimento recursivo em cada uma destas quatro
árvores binárias de triângulos.
2.1.2. Métricas de Erro
Gerar a malha completa, contendo todas as amostras do terreno, se torna
impraticável para terrenos de grande ou mesmo médio porte. Por isso, os
algoritmos dependentes da visão procuram gerar uma aproximação que contenha
o menor número de triângulos e que, ao mesmo tempo, mantenha a melhor
qualidade da imagem.
Enfim, como estamos falando em malhas aproximadas, então é necessário
ter meios para medir o quanto esta aproximação se distancia da malha original. Na
literatura, existem diferentes propostas de métricas de erro, porém a métrica mais
comumente usada consiste em medir a diferença entre a altura de uma amostra do
terreno e a altura do ponto correspondente na malha aproximada e, depois,
5
projetar esta medida no espaço da tela. Geralmente, isto é computado apenas nos
vértices, mas poderia ser computado sobre triângulos ou mesmo sobre a região de
influência de um vértice.
Figura 1 - Exemplo de Malha produzida pelo algoritmo em estudo.
Além disso, pode-se medir o erro em termos absolutos, isto é, a distância
entre a malha aproximada atual e a malha de resolução máxima, ou pode-se
escolher medir um erro relativo, ou seja, entre níveis consecutivos de resolução da
malha.
De antemão, podemos dizer que, no algoritmo discutido neste trabalho, a
escolha de qual métrica de erro utilizar é ortogonal ao algoritmo de construção da
1 2 3
1
2
3
4
4
b) Malha vista como quatro árvores binárias de triângulos.
a) Malha aproximada construída sobre a grade tracejada.
6
malha a cada quadro. Além disso, Lindstrom & Pascucci analisam estes dois tipos
de erro. Segundo eles, de fato, usando o erro absoluto ou erro máximo, conforme
nomeado por eles, produz-se uma malha com um número um pouco maior de
triângulos e que portanto representa mais fielmente o terreno. Contudo,
computacionalmente é bem mais caro trabalhar com erro absoluto e a diferença
entre o número de triângulos gerados não é grande. Assim, considerando a relação
custo-benefício, eles sugerem trabalhar com erro incremental. Por isso, em nossa
implementação e nossos resultados apresentados neste trabalho, estamos
utilizando sempre o erro relativo ou incremental.
Na Figura 2, tentamos ilustrar com um exemplo simples e unidimensional a
diferença entre erro absoluto ou máximo e erro relativo ou incremental. Note que
a figura procura destacar estes dois tipos de erros no ponto 1 e para o nível de
resolução 0.
Figura 2 - Erro absoluto e erro relativo.
2.1.3. Malha Válida
Uma malha pode ser definida como um conjunto de faces e, no nosso
contexto, ela será considerada válida ou consistente se não contiver vértices T
nem arestas sem face. Em vez disso, toda aresta será uma fronteira entre duas e
somente duas faces diferentes. Neste caso, consideramos a região exterior à malha
como uma face.
A Figura 3a ilustra um vértice T visto de cima. Já a Figura 3b ilustra o
vértice T visto em perspectiva, quando a fenda ou descontinuidade provocada por
ele se torna visível. Finalmente, a Figura 3c ilustra uma aresta que não é fronteira
entre duas faces e que, portanto, é uma aresta inválida. O esquema proposto por
Lindstrom & Pascucci sempre gera malhas válidas.
Erro absoluto ou máximoErro relativo ou incremental
0 2 4 6 8Nível 0
Nível 1
Nível 2(máximo)
7
Figura 3 - Exemplo de vértice T e aresta sem face.
2.1.4. Construção da Hierarquia de Malhas
A hierarquia de malhas permite extrair malhas de complexidades diferentes
para representar o mesmo terreno. A construção desta hierarquia, porém, pode
acontecer através de dois processos distintos e inversos: simplificação e
refinamento. Veja a representação deste dois processos na Figura 4. No processo
de simplificação o algoritmo trabalha no sentido de baixo para cima. Portanto, ele
parte da malha de resolução máxima e vai combinando triângulos enquanto o erro
não excede uma tolerância especificada pelo usuário. Já no processo de
refinamento, o algoritmo trabalha no sentido de cima para baixo. Neste caso, ele
parte de uma malha grosseira e vai dividindo triângulos enquanto o erro for maior
que uma tolerância especificada.
Figura 4 - Seqüência de malhas da mesma superfície.
a) Vértice T b) Vértice T em perspectiva c) Aresta sem face
8
Como os algoritmos de simplificação sempre partem da malha de resolução
máxima em direção à malha de saída e os algoritmos de refinamento da malha de
resolução mínima em direção à malha de saída, então a complexidade
computacional dos algoritmos de simplificação é sempre diretamente proporcional
à malha de resolução máxima, enquanto nos algoritmos de refinamento esta
complexidade é proporcional à malha de saída. Portanto, como a malha de saída
costuma ser muito menor que a malha de resolução máxima, os algoritmos de
refinamento também costumam ser mais rápidos.
Por outro lado, os algoritmos de simplificação costumam gerar malhas com
menos triângulos. A razão disso é que eles começam analisando o erro em todos
os pontos, enquanto os algoritmos de refinamento precisam usar alguma
aproximação ou artifício para iniciar analisando o erro em grandes regiões de uma
só vez.
Vários algoritmos, por exemplo aqueles citados em [4], [5] e [9], em tempo
de pré-processamento, dividem o terreno em blocos e utilizam uma estrutura de
árvores quaternárias para organizar estes blocos hierarquicamente. Em tempo real,
a construção da malha aproximada será feita percorrendo tal árvore quaternária.
Contudo, conforme será visto mais a frente, o algoritmo deste trabalho
dispensa este modelo explícito de árvores quaternárias, embora, de certo modo,
seja inspirado nele.
2.1.5. Representação por Níveis de Detalhes Dependente da Visão
Uma representação por níveis de detalhes, ou seja, usando uma estrutura de
multi-resolução, requer o uso simultâneo de diferentes escalas de representação
para o mesmo objeto, que no nosso caso trata-se de um terreno. Isto permite dar
maior destaque ao que está mais próximo do observador e regiões menos
uniformes do objeto, representando-os com mais detalhes (maior resolução ou
maior número de triângulos). Por outro lado, o que está mais distante do
observador e áreas mais uniformes podem ser representados com menos detalhes
(menor resolução ou menor número de triângulos) sem que o usuário perceba
degradação na qualidade visual da imagem.
9
Entretanto, se não houver uma transição suave entre diferentes níveis de
detalhes (ou resolução), vértices T e conseqüentes fendas aparecerão nas
fronteiras entre os diferentes níveis. Então, para garantir uma malha final sem
vértices T e fendas, é preciso um tratamento especial nas fronteiras entre
diferentes níveis de resolução. Veja as figuras 5a e 5b.
Nos últimos anos, muito esforço de pesquisa tem sido dedicado à geração
eficiente de modelos de multi-resolução, empregados não apenas para a
visualização de terrenos mas, em geral, para quaisquer objetos ou cenas
tridimensionais complexos. Alguns autores propõem esquemas complexos e que
requerem um considerável tempo de pré-processamento.
Figura 5 - a) Vértice T formado entre diferentes níveis de detalhes; b) Transição suave
entre diferentes níveis de detalhes.
A Figura 6 ilustra um modelo de multi-resolução, iniciado com uma malha-
base de dois triângulos e depois construído conforme um esquema de partição da
maior aresta.
Figura 6 - Modelo de multi-resolução de uma superfície: a) nível 0; b) nível 1; c) nível 2
e d) nível 3.
a) b)
b) c) d) a)
10
2.1.6. Descarte de Regiões Invisíveis
A idéia, neste caso, é que durante um vôo sobre um grande terreno, na
maioria das vezes somente uma fração do terreno estará visível. Portanto, se todo
o terreno for enviado para renderização, muito esforço computacional estará
sendo desperdiçado. Por outro lado, se houver uma maneira rápida de identificar e
descartar as regiões que caem fora do volume ou frustum de visão, o desempenho
da aplicação pode ser consideravelmente melhorado.
Assim, este descarte rápido de regiões não visíveis, ou seja, o culling da
malha fora do campo de visão, acaba se tornando imprescindível para as
aplicações que desejam executar a visualização de terrenos relativamente grandes
obtendo taxas interativas.
2.1.7. Transições Suaves na Geometria
Muitas vezes, estabelecer um erro tolerável muito pequeno para a malha
aproximada implica gerar um número de triângulos muito grande mesmo para os
hardwares gráficos mais avançados. Ao aumentar o erro tolerável este problema é
minimizado, mas aí ocorre o aparecimento de alguns artefatos temporais. Isto
acontece porque cada inserção de vértice resulta em uma mudança brusca na
geometria da ordem da tolerância (em pixels). O resultado na navegação sobre
terrenos é que montanhas e picos do terreno ficam aparecendo ou desaparecendo
bruscamente, produzindo uma sensação bastante desagradável.
Obviamente, na busca por realismo é crucial que estes artefatos visuais
sejam eliminados. Afinal de contas, em um sobrevôo por um terreno de verdade,
as montanhas e picos são vistos aparecendo ou desaparecendo de forma
relativamente suave. Para simular isto, estes picos e montanhas devem ser
desenhados com alturas intermediárias, de acordo com a distância do observador,
como uma espécie de animação, comumente denominada geomorphing. Vários
esquemas para fazer estas animações têm sido propostos, como em [4], [6] e [7].
Alguns, porém, baseados em tempo, necessitam guardar informações históricas e
são bastante complexos para serem implementados.
11
Entretanto, o algoritmo discutido neste trabalho propõe um esquema de
geomorphing bastante simples, baseado apenas na distância de cada ponto até o
observador e que produz um resultado bastante satisfatório, conforme será visto
mais adiante.
2.2. Trabalhos Relacionados
Nos últimos anos, vários pesquisadores têm se dedicado intensamente à área
de visualização de terrenos e à criação e gerenciamento de níveis de detalhes para
objetos 3D genéricos. Destacamos aqui apenas alguns trabalhos importantes e
recentemente publicados na área de visualização de terrenos dependente da visão,
em ordem cronológica.
Em [5] Lindstrom et al. propõem um algoritmo interativo para renderização
de terrenos cujos dados estão representados sobre uma grade regular e utilizando
um limiar no espaço da tela para limitar o erro da imagem projetada na tela. Este
algoritmo trabalha no sentido de baixo para cima, combinando triângulos e
executando recursivamente um tipo de partição da maior aresta. Na verdade, uma
simplificação num nível grosseiro é realizada para selecionar níveis de detalhes
por bloco. Em seguida, vértices individuais, dentro do bloco selecionado, são
analisados para remoção.
Em tempo de pré-processamento, os dados do terreno são organizados em
blocos formando uma árvore quaternária. Entretanto, devem ser tomados cuidados
especiais para assegurar que não haja vértices T e fendas entre blocos. Para isto, é
mantido um esquema de dependências entre vértices. O problema é que este
esquema é custoso, tanto em termos computacionais quanto de armazenamento.
Além disso, a complexidade deste algoritmo independe da malha final gerada,
pois, por ser baseado em simplificação, ele sempre começa com a malha completa
(de resolução máxima).
Em [6] Hoppe propõe um algoritmo que é uma especialização de seus
trabalhos anteriores para malhas de objetos tridimensionais genéricos aplicado ao
caso de terrenos. Neste trabalho, Hoppe reconhece a importância da visualização
de terrenos. O algoritmo deste trabalho é similar ao desenvolvido em [5], porém
estendido para malhas irregulares. Além disso, é proposto um tipo de
12
geomorphing, ou seja, eliminação de artefatos visuais que explora a coerência
temporal, suavemente interpolando a geometria ao longo do tempo. Um novo
método de cálculo para a aproximação do erro em tempo de pré-processamento é
sugerido. A questão é que, segundo ele, a aproximação do erro somente em pontos
da grade é inadequada para níveis de detalhes dependentes da visão executado
sobre malhas irregulares. O problema desta abordagem é a sua grande
complexidade e dificuldade de implementação.
Em [7] Duchaineau et al. propuseram um algoritmo que sugere várias
melhorias ao trabalho de Lindstrom et al.[5]. Assim como no algoritmo descrito
em [5], o algoritmo de Duchaineau et al. é executado sobre uma grade uniforme.
Porém, como eles organizam os dados em uma árvore binária, nenhum cuidado
especial precisa ser tomado para evitar vértices T ou fendas na malha final
aproximada. Além disso, o algoritmo explora a coerência entre quadros para
melhorar a interatividade. Um esquema de geomorphing temporal é proposto e os
requisitos de memória são similares aos de [5]. Por fim, o algoritmo também
promete flexibilidade na escolha da métrica de erro a ser utilizada. Novamente, o
problema desta abordagem é que ela ainda é considerada complexa e implementar
todas as melhorias sugeridas neste trabalho não parece ser uma tarefa simples.
Em [4] Toledo desenvolve uma proposta que se caracteriza por ser uma
combinação de duas estratégias conhecidas: malhas progressivas e árvores
quaternárias. Em tempo de pré-processamento, o terreno é inicialmente dividido
em uma grade de blocos, onde cada bloco contém um certo número de triângulos.
A malha é simplificada, mantendo-se os vértices das fronteiras para evitar fendas
em junções tipo T. A partir de um certo nível de simplificação, quatro blocos
adjacentes no sentido da árvore quaternária são unidos em um único bloco,
permitindo a eliminação dos vértices entre eles. Neste momento formam-se os
primeiros nós internos da árvore quaternária. Estes nós, por sua vez, possuem
como filhos as quatro malhas progressivas dos nós que os geraram. Este processo
de baixo para cima prossegue até que se obtenha a raiz da árvore quaternária.
Os resultados obtidos foram considerados bons e atendem aos propósitos
estabelecidos. Entretanto, a implementação desta proposta é complexa e a fase de
pré-processamento é demorada.
Ainda inspirado no trabalho desenvolvido em [5], De Boer[8] propõe um
algoritmo para visualização de terrenos dependente da visão que agora procura
13
tirar proveito das facilidades para a renderização 3D implementadas em hardware.
Assim, utiliza-se uma abordagem baseada em blocos organizados em uma árvore
quaternária. Deste modo, um tratamento especial deve ser executado para evitar
vértices T e fendas entre blocos com diferentes níveis de resolução. O
processamento geométrico e a rasterização sempre foram considerados os grandes
gargalos nos algoritmos para visualização de terrenos. Desta forma, a idéia central
deste trabalho parte do princípio de que agora o estágio de rasterização
praticamente deixou de ser um gargalo e, portanto, a ordem é enviar tantos
triângulos para a rasterização quanto o hardware puder manipular. Assim, a idéia
é fazer cálculos aproximados, de forma a reduzir a sobrecarga da CPU por conta
do processamento geométrico. Esta abordagem é simples, porém não se preocupa,
por exemplo, com o formato dos triângulos gerados e, por ser baseada em blocos,
ainda exige tratamento especial para conseguir garantir uma malha final sem
vértices T e fendas.
Finalmente, destacamos um trabalho bastante recente publicado em [9]. Este
trabalho tem como objetivo atender às necessidades da visualização de terrenos
em aplicações de realidade virtual, executando uma visualização estereoscópica
dependente da visão. O problema da estereoscopia é que ela necessita dobrar a
velocidade de geração do correspondente monoscópico para alcançar a mesma
interatividade, já que neste caso é preciso produzir duas imagens, uma para o olho
direito e outra para o olho esquerdo. O algoritmo, conforme tantos outros
trabalhos, representa os dados em um modelo de multi-resolução baseado em
árvores quaternárias e utiliza um esquema de partição da maior aresta. Assim,
para evitar vértices T e fendas, é mantido um esquema de dependências entre
vértices. A novidade é que, para não perder informações de profundidade,
essenciais na visualização estereoscópica, adota-se um critério de simplificação
diferente, ou seja, um limiar de erro angular baseado na distância. Além disso, as
duas imagens, para o olho direito e para o olho esquerdo, são geradas
simultaneamente. Tira-se proveito do fato de que estas duas imagens são muito
parecidas, então operações como culling da malha fora do volume de visão são
realizadas uma única vez. Com o intuito de melhorar a qualidade visual, uma
operação de geomorphing também é incluída.
Vale ressaltar que a grande contribuição desse trabalho está nas idéias que
incluem a estereoscopia. Se estas idéias fossem utilizadas mescladas ao algoritmo
14
principal descrito neste trabalho, provavelmente seriam obtidos resultados ainda
melhores.
3 Descrição do Algoritmo
Neste capítulo vamos descrever as idéias principais do algoritmo proposto
por Lindstrom & Pascucci e estudado neste trabalho.
Em síntese, o objetivo deste algoritmo é gerar uma malha com o menor
número possível de triângulos e que ao mesmo tempo seja uma boa aproximação
para a malha completa. O algoritmo trata com um terreno representado por
amostras regularmente espaçadas, ou seja, dispostas no formato de uma grade.
Uma restrição é que esta grade de pontos deve necessariamente formar uma
matriz bidimensional com (2n/2 +1) vértices em cada direção, onde n é o número
de níveis de refinamento, necessariamente maior ou igual a 2. Desta forma,
quando o terreno não se encaixa neste formato é preciso estendê-lo fazendo a
alocação de uma área de memória às vezes bem maior que o tamanho dos dados
do próprio terreno. Porém, depois de executado o refinamento, as áreas sem dados
reais podem ser cobertas com uma textura transparente e não haverá nenhum
prejuízo mais sério que algum relativo desperdício de memória e de
processamento.
Em primeiro lugar, destacamos que se trata de um algoritmo dependente da
visão, o que significa dizer que a malha de triângulos gerada dependerá do ponto
onde o observador estiver localizado. Afinal de contas, a cada quadro é feita a
verificação de quais são os vértices ativos, isto é, que deverão estar presentes na
malha final.
Esta verificação é feita projetando na tela um erro no espaço do objeto,
armazenado em tempo de pré-processamento, no próprio vértice. Somente se este
erro projetado for maior que uma tolerância previamente especificada é que o
vértice deverá ser ativado. O erro no espaço do objeto de um vértice i, é, em
princípio, a diferença vertical entre a altura real de i e altura aproximada no ponto
correspondente a i quando i não está presente na malha.
Destacamos ainda que se trata de um algoritmo de refinamento. Ele inicia
com uma malha-base grosseira, em geral contendo quatro triângulos. Em seguida,
16
estes triângulos vão sendo divididos, conforme o critério de refinamento e de
modo que a malha vá se adaptando ao terreno. Assim, a decisão de dividir ou não
um triângulo dependerá das posições do observador e do próprio triângulo.
A forma de executar a divisão de um triângulo não é inovadora. Ela é feita
através do esquema de partição da maior aresta. Todos os triângulos aqui são
retângulos e isósceles. Quando um vértice é inserido na metade da hipotenusa de
um triângulo, dois outros triângulos, também isósceles, são criados. Note que isto
já sugere algum procedimento recursivo para fazer tal divisão dos triângulos.
Além disso, note que a malha produzida por este esquema pode ser
representada por um grafo acíclico direcionado (DAG – sigla que vem do inglês
directed acyclic graph) de vértices. Neste grafo, convencionamos que uma aresta
(i, j) partindo do vértice i em direção ao vértice j indica que i é pai de j. Além
disso, a aresta (i, j) partindo de i para um dos seus filhos j corresponde à partição
de um triângulo onde j é inserido na metade da hipotenusa deste triângulo,
conforme mostrado na Figura 7.
Deste modo, repartindo recursivamente a malha-base grosseira, criaremos
uma malha onde todos os vértices que não são folhas e nem estão localizados na
fronteira possuem exatamente quatro filhos e dois pais. Enquanto isto, os vértices
localizados na fronteira da malha possuem apenas dois filhos e um pai.
Finalmente, os vértices-folhas são aqueles que não possuem filhos.
Figura 7 - a) Aresta de i para j no DAG; b) Destacando arestas no DAG de uma malha.
Outro ponto importante identificado verificando-se a natureza desta malha é
que se um vértice for inserido e seu pai não, isto gerará um vértice T indesejável e
uma possível fenda na malha final. Então, para assegurar uma malha válida, a
seguinte propriedade deve ser mantida: se um vértice está ativo, isto é, presente na
i
j
a) b)
17
malha final, então os seus pais (e por indução todos os seus ancestrais) também
estarão.
O problema é que neste grafo direcionado acíclico (DAG) pode-se alcançar
um vértice filho sem, obrigatoriamente, passar por todos os seus ancestrais.
Esquemas de dependências explícitas entre vértices têm sido propostos para
resolver este problema. Todavia, tal abordagem é considerada
computacionalmente ineficiente e cara do ponto de vista de armazenamento.
Em vez disto, uma forma mais elegante e eficiente é a utilização de
esquemas implícitos de dependências entre vértices. Desta forma, uma importante
contribuição de Lindstrom e Pascucci [2] é que eles propõem uma maneira
razoavelmente simples, sem a exigência de um pré-processamento pesado e
embutida no próprio critério de refinamento. A seguir descrevemos como isto
pode ser feito, mas já adiantamos que um aninhamento dos erros é utilizado.
3.1. Refinamento
O objetivo do refinamento realizado aqui é seguir dividindo a malha-base de
forma a ir ajustando-a ao terreno e ao mesmo tempo garantir uma malha contínua.
Para isto, Lindstrom & Pascucci criaram um esquema de refinamento
independente da métrica de erro utilizada e baseado em esferas aninhadas.
Já vimos que uma malha contínua e sem vértices T é obtida quando nenhum
filho é introduzido sem que seus pais e seus ancestrais também o sejam. Além do
mais, poderíamos assegurar isto se conseguíssemos aninhar os erros no espaço da
tela, ou seja, assegurando que o erro de um vértice-pai seja maior ou igual ao erro
de todos os seus descendentes. Afinal, um vértice estará ativo ou inativo
dependendo do valor do seu erro no espaço da tela comparado à tolerância
especificada.
Portanto, o primeiro passo na tentativa de, em última análise, garantir uma
malha contínua consiste em propagar os erros no espaço do objeto dos filhos para
os pais (e todos os seus ancestrais). Seja δi o erro no espaço do objeto do vértice i,
ou seja, a diferença vertical entre a altura real de i e a altura aproximada no ponto
correspondente a i quando i não está presente na malha. Assim, considerando que
18
este erro já tenha sido calculado e armazenado para todos os vértices da malha,
poderemos fazer a propagação de erros do seguinte modo:
( )
=ji
ii
δδδ
δ,max
Deste modo, já temos os erros no espaço do objeto aninhados. Porém, esta
condição ainda não é suficiente, pois ainda não conseguimos aninhar os erros no
espaço da tela, conforme desejado. Observe que um filho pode estar
arbitrariamente próximo do observador e seu pai arbitrariamente longe, de modo
que, ao serem projetados na tela, o erro do pai ainda será menor que o do filho.
Isto poderá implicar o filho ser ativado sem a ativação do pai e, portanto, gerar o
indesejável vértice T.
Então, ainda é necessário definir uma esfera envolvente para cada vértice da
malha, englobando o próprio vértice e todos os seus descendentes. Sendo ri o raio
da esfera centrada no vértice i, teremos que:
( )
+−=
,max,0
jjii
rppr
A Figura 8 mostra, no plano, estas esferas envolventes para um pequeno
trecho de malha. Observe que, para deixar a figura mais simples e clara, as esferas
foram representadas por círculos.
Figura 8 - Malha com esferas envolventes
, se i é um vértice-folha , para todo j descendente de i
para todo j descendente de i se i for um vértice-folha
19
Agora, definimos o erro no espaço da tela do vértice i como proporcional ao
seu erro no espaço do objeto e inversamente proporcional à distância até o ponto
de vista do observador subtraída do raio da esfera envolvente de i. Assim,
finalmente temos que o erro no espaço da tela do vértice i será maior ou igual ao
erro de j, para todo j descendente de i (pois o raio de i é maior que o raio de j).
Conseqüentemente, se j estiver ativo, então todos os seus ancestrais também
estarão e garantimos uma malha final contínua, conforme desejado.
Vale ressaltar que tanto o raio da esfera envolvente quanto o erro no espaço
do objeto de cada vértice devem ser calculados e propagados adequadamente na
malha, tal como descrito anteriormente, em tempo de pré-processamento. Além, é
claro, dos dados do terreno, estes são os únicos termos necessários para executar o
procedimento de refinamento recursivo, conforme será mostrado mais adiante. O
pseudo-código para o pré-processamento também será apresentado mais adiante.
3.2. Métricas de Erro
A escolha de qual métrica de erro utilizar, em princípio, é ortogonal ao
algoritmo de refinamento que vem sendo descrito aqui. A condição é que a
posição do erro no espaço do objeto possa ser incluída em uma esfera envolvente.
Além disso, deve-se decidir antecipadamente se será utilizado um erro medido em
termos absolutos ou relativos, pois os erros precisam ser propagados em tempo de
pré-processamento.
Então, dado um erro no espaço do objeto (δi), o algoritmo dependente da
visão o projeta na tela (para obter ρi) e a forma mais simples de fazer isto é:
opi
ii
−= λδρ (eq. 1)
onde λ = ϕω e ω é a largura da tela em pixels, ϕ é o campo de visão ou a
abertura da câmera e o é o ponto onde está localizado o olho do observador .
Como o objetivo é maximizar ρi e ρi será máximo quando opi − for
mínimo, então se o não pertence à esfera envolvente de i, então ii rop −−
maximizará o erro no espaço da tela. Para o dentro da esfera, este termo é zero e o
vértice é ativado. Desta forma, temos que:
20
ii
ii
rop −−= λδρ (eq. 2)
3.3. Pré-Processamento
Antes de começar a executar o refinamento em tempo real é preciso preparar
os dados do terreno, colocando-os no formato exigido pelo algoritmo de
refinamento. Veremos que comparativamente com outros algoritmos para
visualização de terrenos, aqui o pré-processamento é relativamente simples e não
muito demorado. A complexidade computacional deste pré-processamento é
O(m2) para um terreno de dimensões (m+1) x (m+1), onde m é uma potência de
dois, portanto, já incluindo os dados fictícios eventualmente necessários para que
o terreno se encaixe no formato (2n +1) x (2n +1). Já vimos que cada amostra ou
vértice deve armazenar consigo, além da sua altura (no caso, a coordenada z),
também um raio e um erro no espaço do objeto.
Em linguagem C, podemos dizer que cada vértice pode ser representado
pela seguinte estrutura: Struct VerticeTrn { float z; /* altura */ float sigma; /* erro no espaço do objeto */ char ativo; /* indica se o vértice estará presente na malha final atual */ float r; /* raio do vértice */ }; VérticeTrn **MatrizTrn;
Assim, uma matriz bidimensional desta estrutura (MatrizTrn neste caso)
representará o terreno e as coordenadas x e y serão, implicitamente, representadas
pelos índices dentro desta matriz.
As coordenadas x, y e z devem ser lidas na entrada e a variável ativo será
atualizada durante o refinamento. Portanto, em suma, resta ao pré-processamento
calcular e armazenar adequadamente o erro no espaço do objeto e o raio para cada
um dos vértices do terreno.
Desta forma, o pré-processamento começa calculando o erro no espaço do
objeto para cada vértice. Inicialmente, ainda não nos preocupamos com o requisito
de que o erro de um vértice-pai deve ser maior ou igual ao erro de todos os seus
descendentes. Vale destacar que esta etapa foi inspirada na estrutura de blocos
21
criada no trabalho feito por Lindstrom et al.[5] em 1996 e depois detalhado no
capítulo 11 de [10]. Aqui não existe mais a necessidade de uma estrutura física
para blocos, mas a malha final continua com o mesmo formato e não incorremos
em nenhum erro ao pensarmos nela como dividida em blocos. Enfim, mais adiante
ficará claro que pensar na malha como sendo constituída por blocos é apenas um
artifício para facilitar esta etapa de pré-processamento.
Todavia, se estamos falando em blocos, então é necessário discutirmos
alguns conceitos relacionados a eles. No trabalho citado anteriormente, o terreno
inteiro é visto como um grande bloco que é formado por quatro blocos menores e
recursivamente cada um destes quatro blocos também é formado por quatro outros
blocos. A recursão pára quando o bloco possui dimensão três, ou seja, contém 3x3
amostras, e não faz mais sentido dividi-lo em quatro blocos. A Figura 9 ilustra o
bloco-pai, envolvendo todo o terreno, e seus quatro filhos (o direito superior - DS,
o esquerdo superior - ES, o direito inferior - DI e o esquerdo inferior - EI).
Figura 9 - Terreno dividido recursivamente em blocos.
Uma vez visto como o terreno pode ser virtualmente dividido em blocos,
agora destacamos que existem dois tipos de blocos: pares e ímpares. Adiantamos
que esta classificação permite identificar quem são os dois pais do vértice central
de um bloco, conforme pode ser visto nas figuras 10b e 10c. Esta informação será
útil mais adiante. O bloco inicial englobando o terreno inteiro e todo bloco que é
filho direito superior (DS) ou esquerdo inferior (EI) é necessariamente par. Por
outro lado, todo bloco que é filho esquerdo superior (ES) ou direito inferior (DI) é
necessariamente ímpar. O segundo ponto é que os quatro vértices-filhos do vértice
central de um bloco estão sempre posicionados conforme mostrado na Figura 10a.
A posição dos pais do vértice central, porém, varia dependendo de se o bloco que
o engloba é par ou ímpar, conforme ilustrado nas figuras 10b e 10c. A dimensão
DSES
EI DI
ES DS
EI DI
22
do bloco varia de acordo com a posição dele na árvore de blocos. O bloco grande,
envolvendo o terreno inteiro e raiz da árvore, possui dimensão (2n +1) x (2n +1). Já
os blocos-folhas possuem dimensão 3x3 e os blocos intermediários possuem
dimensões intermediárias.
Um bloco completo contém todos os vértices, como na Figura 10. Contudo,
um bloco não necessariamente precisa ser completo. O vértice central e seus 4
filhos podem eventualmente serem retirados. Repare que, quando um vértice é
retirado do bloco, a altura no ponto correspondente a ele será aproximada pela
média das alturas de seus dois vizinhos dentro do bloco. A Figura 11 ilustra este
esquema para um bloco ímpar. Para um bloco par é análogo, só que o vértice
central será eventualmente aproximado pelos vértices localizados na diagonal
oposta.
a) b) Par c) Ímpar
Figura 10 - Vértices de um bloco.
Em a) destaque para os quatro filhos do vértice central. Em b) e c) destaque para os pais
do vértice central e para um bloco par e ímpar, respectivamente.
Figura 11 - Destacando os vértices que aproximam os vértices eventualmente ausentes.
As setas partem do vértice que pode estar ausente e vai até os vértices que o
aproximam.
Desta forma, o procedimento que calcula o erro no espaço do objeto para
todos os vértices percorre o terreno recursivamente como se ele estivesse dividido
em blocos. Uma vez identificado um bloco, já sabemos quais os vértices que
Filho 1
Filho 3
Pai 1
Pai 2
Pai 1
Pai 2
Filho 2 Filho 4
23
aproximarão a altura de cada um dos cinco vértices que podem estar ausentes.
Então, o erro no espaço do objeto será a diferença de altura entre a altura original
do vértice e a média de alturas entre os dois vértices que o aproximarão caso ele
esteja ausente no bloco. O pseudo-código para este cálculo é mostrado a seguir.
IniciaErros(int ileft, int jlower, int dim, int paridade)
Se (dim > 2) {
/* Bloco-Filho Superior Esquerdo */ IniciaErros(ileft, jlower – dim, dim/2, 1); /* Bloco-Filho Superior Direito */ IniciaErros(ileft + dim, jlower - dim, dim/2, 0); /* Bloco-Filho Inferior Esquerdo */ IniciaErros(ileft, jlower, dim/2, 0); /* Bloco-Filho Inferior Direito */ IniciaErros(ileft + dim, jlower, dim/2, 1);
} Para cada um dos 5 vértices (com coordenadas x,y) que podem ser retirados do bloco
Erro = CalculaErroObj(Altura_vertDir, Altura_vertEsq, Altura_Vertice); MatrizTrn[x][y].sigma = Erro;
float CalculaErroObj (float Alt_Dir, float Alt_Esq, float Alt_Vértice) Media = (Alt_Dir + Alt_Esq)/2; ErroObj = || Alt_Vértice – Media||; Retorne ErroObj;
Note que inicialmente o procedimento IniciaErros é chamado com os
seguintes parâmetros: 0 para ileft, tamanho da matriz em potência de 2 que
envolve o terreno inteiro para jlower e para dim, e finalmente 1 para paridade. Em
outras palavras, inicialmente o procedimento é chamado para o bloco maior e a
partir daí é como se ele fosse subdividindo o terreno em blocos menores (veja a
Figura 12).
Figura 12 - Bloco processado pelo procedimento IniciaErros
É importante também iniciar todos os raios com valor zero. Uma vez feito
isso, enfim é o momento de atualizar os erros no espaço do objeto e os raios de
todos os vértices de modo que o erro e o raio de qualquer vértice sejam sempre
ileft ileft+dim jlower-dim
jlower
24
maiores ou iguais a todos os seus descendentes. Em outros termos, vamos
propagar os erros e os raios dos filhos para os pais.
Lembre-se que permanecemos pensando na malha como virtualmente
constituída por blocos. Então, podemos simultaneamente ir atualizando o erro no
espaço do objeto e o raio de todos vértices, agora percorrendo a hierarquia de
malhas no sentido de baixo para cima. Assim, começamos processando os blocos
menores e vamos subindo até atingir o bloco que engloba o terreno inteiro, e neste
caso todos os erros e raios já estarão corretos e o pré-processamento pode ser
encerrado.
Embora continue sendo fundamental saber se um bloco é par ou ímpar (para
identificar os pais do vértice central do bloco), como estamos indo de baixo para
cima não sabemos quem é filho superior, inferior, direito ou esquerdo, então não
podemos usar isto para descobrir se o bloco é par ou ímpar. Por outro lado, repare
que sempre começamos com um bloco par, no sentido da esquerda para a direita e
de cima para baixo. Além disso, a partir daí eles se alternam, um bloco par
seguido por um bloco ímpar, depois outro bloco par e assim por diante, não
importa em qual resolução estejamos. (Veja a Figura 13).
A seguir apresentamos o pseudo-código para a propagação simultânea dos
erros no espaço do objeto e dos raios dos filhos para os pais, como acabamos de
descrever.
Figura 13 - Os blocos ímpares estão circulados e os pares não.
PropagaErrosRaios(int ileft, int jlower, int dimAtual) Enquanto (dimAtual <= dimMatriz) { ipar = 1; Para (i = ileft; i <= (dimMatriz - dimAtual); i=i+dimAtual) {
jpar = -1; Para (j = jlower; j >= (dimAtual); j=j-dimAtual)
25
{ paridade = jpar * ipar; PropagaRaiosBloco(i, j, dimAtual, paridade); PropagaErrosBloco(i, j, dimAtual, paridade); jpar = jpar * (-1); }/* fim Para j...*/ ipar = ipar *(-1); }/* fim Para i... */ dimAtual = (dimAtual*2); }/* fim Enquanto */ PropagaRaiosBloco(int ileft, int jlower, int dimAtual, int paridade) Obtém coordenadas e raio do vértice central do bloco atual; dist = 0; Para cada um dos 4 filhos do vértice central { obtém coordenadas e raio do filho; Se (dist < distância até o filho + raio do filho) dist = distância até o filho + raio do filho; } if (dist > raio do vértice de central) raio do vértice central = dist; Obtém coordenadas dos 2 vértices pais do vértice central; Se (paridade= 1) /*Bloco é ímpar */ { xpai1 = ileft + dimAtual; ypai1 = jlower - dimAtual; xpai2 = ileft; ypai2 = jlower; } senão /*se bloco é par */ { xpai1 = ileft; ypai1 = jlower - dimAtual; xpai2 = ileft + dimAtual; ypai2 = jlower; } Se (existe pai1 ) Se (raio do pai1 < (raio do vértice + distância do vértice até pai1)) raio do pai1 = (raio do vértice + distância do vértice até pai1); Se (existe pai2 ) Se (raio do pai2 < (raio do vértice + distância do vértice até pai2)) raio do pai2 = (raio do vértice + distância do vértice até pai2); PropagaErrosBloco(int ileft, int jlower, int dimAtual, int paridade) Obtém coordenadas e erro do vértice central do bloco atual; erro = 0; Para cada um dos 4 filhos do vértice central { obtém coordenadas e erro do filho; Se (erro < erro do filho) erro = erro do filho; } Se (erro > erro do vértice de central) erro do vértice central = erro; Obtém coordenadas dos 2 vértices pais do vértice central;
Se (existe pai1 ) Se (erro do pai1 < (erro do vértice central)) erro do pai1 = (erro do vértice central);
Se (existe pai2 )
26
Se (erro do pai2 < (erro do vértice central)) erro do pai2 = (erro do vértice central);
Inicialmente PropagaErrosRaios é chamado com os seguintes parâmetros: 0
para ileft, dimensão da matriz envolvendo o terreno todo para jlower e para
dimAtual.
3.4. Procedimento para Refinamento em Tempo Real
O algoritmo de refinamento, aqui denominado RefinaMalha, inicia com uma
malha-base contendo quatro triângulos, conforme mostrado na Figura 14 e pode
ser descrito pelo seguinte pseudo-cógido: RefinaMalha (V, n)
paridade (V) = 0; V = ( iso, iso); RefinaSubMalha (V, ic, is, n);
AnexaStrip (V, ise,1); RefinaSubMalha (V, ic, il, n);
AnexaStrip (V, ine,1); RefinaSubMalha (V, ic, in, n); AnexaStrip (V, ino,1); RefinaSubMalha (V, ic, io, n); AnexaStrip (V, iso,1);
Aqui a variável n é o número de níveis de refinamento, ic o vértice
localizado no centro da malha, iso, ise, ine e ino os quatro vértices localizados nos
cantos da grade e, por fim, is, il, in e io são os vértices introduzidos no primeiro
nível de refinamento, conforme mostrado na Figura 14. O vetor de triângulos
inicia com duas cópias do vértice localizado no canto inferior esquerdo da malha
para permitir que o teste na primeira linha do procedimento AnexaStrip possa ser
executado. No momento da renderização o primeiro vértice do vetor pode, então,
ser descartado.
Figura 14 - Malha-base.
il io
is
in
ise
ine ino
iso
ic
27
Internamente, o algoritmo RefinaMalha invoca o procedimento
RefinaSubMalha para cada um dos quatro triângulos mostrados na Figura 14. Este
procedimento realiza o percurso mais interno na hierarquia de malhas e fd e fe são
os vértices filhos de j no DAG (grafo direcionado acíclico) do triângulo atual (veja
a Figura 15). RefinaSubMalha é então chamado recursivamente com j como o
novo vértice-pai para cada um dos dois novos triângulos criados.
Observe que um vetor de vértices é retornado pelo procedimento.
Figura 15 - Destacando filhos direito e esquerdo do vértice j.
RefinaSubMalha (V, i, j, l) Se (l > 0) && (ativo(i) ==1)) RefinaSubMalha(V,j, fe, l-1); AnexaStrip(V, i,(l % 2)); RefinaSubMalha(V,j,fd, l-1); AnexaStrip (V, v, p)
Se (( v != vn-1) && (v != vn) Se (p != paridade(V))
paridade (V) = p; senão V = (V, vn-1); V = (V, v); Através da sequência de imagens da Figura 16, tentamos ilustrar a
renderização de uma strip de triângulos produzida pelo procedimento de
refinamento descrito nesta seção. A strip deste exemplo constrói a malha
mostrada na figura t39 e que, conforme pode ser observado, mapeia em cima de
uma grade.
t1) t2) t3)
i
j
fdfe
28
t4) t5) t6)
t7) t8) t9)
t10) t11) t12)
t13) t14) t15)
t16) t17) t18)
29
t19) t20) t21)
t22) t23) t24)
t25) t26) t27)
t28) t29) t30)
t31) t32) t33)
30
t34) t35) t36)
t37) t38) t39) Strip de vértices: 0, 9, 6, 9, 17, 4, 17, 10, 6, 10, 1, 10, 7, 4, 2, 4, 8, 4, 3, 4, 5, 9, 0
Figura 16 – Animação da renderização de uma strip de triângulos.
Note que os procedimentos de refinamento e renderização podem ser
paralelizados. Contudo, nossa implementação não explora esta potencialidade do
algoritmo.
3.5. Procedimento para Culling da Malha fora da Visão
No algoritmo sendo descrito neste capítulo, o culling da malha fora do
volume de visão pode ser feito simultaneamente com o refinamento, explorando a
natureza hierárquica da malha e das esferas aninhadas. A partir daí, podem-se
descartar grandes regiões sempre que possível. Para adicionar o culling ao
refinamento básico, basta trocar, no procedimento RefinaMalha, as chamadas para
RefinaSubMalha por chamadas para o procedimento RefinaSubMalhaVisivel,
cujo pseudo-código é apresentado abaixo.
RefinaSubMalhaVisivel (V, i, j, l, dentro) Se (dentro[k] p/ k de 0 a 5) // totalmente dentro RefinaSubMalha (V, i, j, l); Senão se (l > 0) && (ativo(i)) && (Visível(i, dentro)) //se intercepta RefinaSubMalhaVisível(V,j, fe, l-1); AnexaStrip(V, i,(l % 2)); RefinaSubMalhaVisível(V,j, fd, l-1);
31
Visivel (i, dentro) Para cada plano do frustum de visão <nk, dk>
Se (não dentro[k]) s = nk • pi + dk;
Se (s > ri) return falso; Se (s < -ri) dentro[k] = verdadeiro; retorne verdadeiro; O procedimento de culling descrito aqui usa os seis planos do frustum ou
volume de visão. Por conta disso, as equações implícitas de cada um deles devem
ser calculadas antecipadamente, no espaço do objeto, e passadas ao longo do
refinamento. A seção seguinte apresenta o pseudo-código para obter estas
equações. Além disso, é necessário manter uma variável sinalizadora (flag) para
cada um dos planos, indicando se a esfera centrada no ponto está completamente
dentro do volume com relação a cada plano. Assim, como a esfera centrada em i
contém i e todos os seus descendentes, então se a esfera de i estiver
completamente dentro do volume o vértice i e todos os seus descendentes também
estarão e não é mais necessário fazer testes de visibilidade para os descendentes
de i. Neste caso, a partir daí pode-se chamar o procedimento RefinaSubMalha em
lugar de RefinaSubMalhaVisivel.
Se, por outro lado, a esfera centrada em i estiver completamente fora do
volume de visão, então significa que i e todos seus descendentes podem ser
descartados e o refinamento pode terminar.
É importante destacar que este culling não introduz vértices T, pois as
esferas aninhadas se encarregam de manter os relacionamentos entre vértices-pais
e os filhos. Em outros termos, repare que aqui também nenhum filho é introduzido
na malha final sem que seus ancestrais também sejam.
Para efeito ilustrativo, considere a Figura 17. Uma possibilidade de gerar
um vértice T nesta malha seria incluir o vértice j sem incluir um dos seus pais i1
ou i2. Contudo, note que é impossível imaginar algum plano que deixe j do seu
lado interior sem, simultaneamente, cortar a esfera envolvente de i1 e deixar a
esfera de i2 completamente no seu interior ou vice-versa. Neste caso, se pelo
critério de erro j for ativado, então tanto i1 quanto i2 também serão e não teremos
vértice T.
32
Figura 17 - Esferas Envolventes Aninhadas
3.6. Calculando o Frustum de Visão
Cada um dos seis planos que formam o frustum de visão, ou seja os planos
near, far, left, right, bottom e top (conforme a Figura 18), possui uma equação que
pode ser escrita da seguinte forma, em coordenadas no espaço do objeto:
0=+++ dczbyax
Também podemos escrever que •Tn p' = 0 ⇒ [ ]dcba *
1zyx
= 0
Onde nT é a normal transposta do plano e p é um ponto deste mesmo plano.
Depois que cada plano do frustum é multiplicado pelas matrizes
MODELVIEW e PROJECTION do OpenGL, obtemos os chamados planos de
clipping. Poderíamos dizer, então, que aqui a equação de cada plano seria algo do
tipo:
0''''''' =+++ dzcybxa
j
i1
i2
33
De forma análoga à anterior, podemos escrever •Tn' p = 0 ⇒
[ ]'''' dcba *
1'''
zyx
= 0
Figura 18 - Frustum de Visão
Neste caso, o frustum é mapeado para coordenadas dentro de um cubo com
coordenadas entre –1 e + 1 (conforme mostrado na Figura 18b). Na realidade o
clipping é feito em coordenadas homogêneas, antes da divisão por w, para evitar
que objetos que estejam atrás do olho apareçam na cena. Assim, podemos
escrever os planos de clipping como:
Near: z + w = 0
Far: z – w = 0
Left: x + w = 0
Right: x – w = 0
b) Sistema de coordenadas de clipping.
Near
Far
ze
ye
xe
ye
ze
xe
−−−
111
111 Near
Far
Left
Right
Top
Bottom
TopLeft
Right
Bottom
a) Sistema de coordenadas do objeto. M = Projection * Modelview
34
Bottom: y + w = 0
Top: y – w = 0
Ou seja, podemos montar a seguinte tabela:
'a 'b 'c 'd
Near 0 0 -1 -1
Far 0 0 1 -1
Left -1 0 0 -1
Right 1 0 0 -1
Bottom 0 -1 0 -1
Top 0 1 0 -1 Tabela 1 - Planos que formam o frustum de visão
Vamos chamar de M a matriz MODELVIEW multiplicada pela matriz
PROJECTION. Sabemos que M é quem faz a transformação do sistema de
coordenadas do objeto para o sistema de coordenadas de clipping (as coordenadas
entre –1 e +1), isto é:
=
1
*
''''
zyx
M
wzyx
Então, a equação de cada plano do frustum no espaço do objeto também pode ser
escrita como:
[ ] 0
1
*** 1 =
−
zyx
MMdcba
pois M-1 * M = I, onde I é a matriz identidade.
Substituindo
1
*zyx
M por
''''
wzyx
, obtemos [ ] 0
''''
** 1 =
−
wzyx
Mdcba
Disto, podemos tirar que [ ] [ ] 1*'''' −= Mdcbadcba ou
35
=
−
dcba
M
dcba
T *
''''
⇒ 'n = TM − * n ou n = MT * 'n
Assim, através da equação obtida acima e da tabela montada anteriormente,
podemos obter os planos que formam o frustum de visão no espaço do objeto,
conforme exigido no procedimento que faz o refinamento da malha de triângulos
simultaneamente com o culling do trecho da mesma que cai fora do frustum de
visão.
Se
=
]3][3[]2][3[]1][3[]0][3[]3][2[]2][2[]1][2[]0][2[]3][1[]2][1[]1][1[]0][1[]3][0[]2][0[]1][0[]0][0[
mpvmpvmpvmpvmpvmpvmpvmpvmpvmpvmpvmpvmpvmpvmpvmpv
M , então
=
]3][3[]3][2[]3][1[]3][0[]2][3[]2][2[]2][1[]2][0[]1][3[]1][2[]1][1[]1][0[]0][3[]0][2[]0][1[]0][0[
mpvmpvmpvmpvmpvmpvmpvmpvmpvmpvmpvmpvmpvmpvmpvmpv
M T
Para o plano Near na tabela anterior, podemos escrever:
−−
=
11
00
TM
dcba
De onde obtemos que:
]0][3[]0][2[ mpvmpva −−=
]1][3[]1][2[ mpvmpvb −−=
]2][3[]2][2[ mpvmpvc −−=
]3][3[]3][2[ mpvmpvd −−=
Para o plano Far na tabela anterior, podemos escrever:
−
=
1100
TM
dcba
De onde obtemos que:
]0][3[]0][2[ mpvmpva −=
36
]1][3[]1][2[ mpvmpvb −=
]2][3[]2][2[ mpvmpvc −=
]3][3[]3][2[ mpvmpvd −=
Para os planos Left/Right na tabela anterior, podemos escrever:
−
±
=
1001
TM
dcba
De onde obtemos que:
]0][3[]0][0[ mpvmpva −±=
]1][3[]1][0[ mpvmpvb −±=
]2][3[]2][0[ mpvmpvc −±=
]3][3[]3][0[ mpvmpvd −±=
Por fim, para os planos Bottom/Top na tabela anterior, podemos escrever:
−
±=
101
0
TM
dcba
De onde obtemos que:
]0][3[]0][1[ mpvmpva −±=
]1][3[]1][1[ mpvmpvb −±=
]2][3[]2][1[ mpvmpvc −±=
]3][3[]3][1[ mpvmpvd −±=
Como 222 cbanorma ++=
Então para obter um vetor unitário do tipo ( cba ˆ,ˆ,ˆ ) e uma equação
0ˆˆˆˆ =+++ dzcybxa , devemos fazer
normaaa =ˆ ;
normabb =ˆ ;
normacc =ˆ e
normadd =ˆ , para cada um dos os
planos citados.
Assim, finalmente, apresentamos a seguir o pseudo-código para obter as
equações dos seis planos que formam o frustum de visão no espaço do objeto.
37
ComputaPlanosFrustum()
Obtém matrizes MODELVIEW e PROJECTION do OpenGL; mpv = PROJECTION * MODELVIEW; Para (i = 0; até i != 6; i=i+1) /* Para cada um dos 6 planos do Frustum */ {
k = i / 2; Para (j = 0; até j != 4; j = j+1) /*Para cada componente da equação */ { Se ((i mod 2) = 0) fator = +1; senão fator = -1; componente[j] = fator*mpv[k][j] - mpv[3][j]; } norma=sqrt((componente[0]* componente[0]) + (componente[1]*
componente[1]) + (componente[2]* componente[2])); nx[i] = (float) (componente[0]/norma); ny[i] = (float) (componente[1]/norma); nz[i] = (float) (componente[2]/norma); d[i] = (float) (componente[3]/norma);
}
3.7. Procedimento para Geomorphing
O geomorphing é uma espécie de animação para suavizar as transições na
geometria da malha durante um sobrevôo e que na prática tenta evitar artefatos
visuais como o surgimento ou desaparecimento brusco de montanhas. No
algoritmo estudado neste trabalho, foi incorporado um geomorphing baseado na
posição do observador. Assim, o parâmetro de geomorphing para um vértice é
uma função da distância dele até o observador.
Deste modo, em vez de definir um valor de tolerância para o erro no espaço
da tela, define-se uma faixa de tolerância (τmin, τmax) e quando o erro no espaço da
tela do vértice cai nesta faixa o geomorphing é aplicado.
O parâmetro t para cada vértice pode ser definido como:
minmax
min
τττρ−
−=t (eq. 3)
Onde ρ é o erro no espaço da tela, τmin é a tolerância mínima e τmax a
tolerância máxima especificada.
Então, quando t for menor ou igual a zero o vértice estará inativo, enquanto
para t maior ou igual a 1 o vértice estará ativo e será desenhado com sua altura
original. Para t entre zero e um, porém, a altura do vértice será dada por:
38
2)1()( de
izzttztz +−+= (eq. 4)
onde zi é a altura real do vértice i e ze e zd são as alturas dos vértices (direito
e esquerdo) que formam a aresta que aproximará a altura de i se i for removido da
malha. Como as alturas destes vértices (ze e zd) também podem ter passado por um
geomorphing, ou seja, pode acontecer uma espécie de geomorphing em cascata,
então os próprios valores de ze e zd devem ser passados como parâmetro no
procedimento que executa o percurso na hierarquia de malhas.
Agora, usando a definição de t e do erro projetado na tela(ρ) temos:
minmax
min)(ττ
τδλ
−
−−= rdt (eq. 5)
Então, definindo uma faixa (dmin, dmax) para a distância entre o vértice e o
observador, temos:
1) d = dmin quando t = 1, ou seja, o vértice será desenhado com a sua altura
real.
Então, substituindo t pelo valor 1 e d por dmin na (eq.5), teremos:
⇒=−⇒−−
=−⇒
−
−−=
maxminmin
minminmax
minmax
min
min )(1τ
λδτλδττττ
τδλrd
rdrd
rrd +=+= δνδτ
λmin
maxmin (eq. 6)
2) d = dmax quando t = 0, ou seja, o vértice estará inativo e nem será
desenhado.
Então, analogamente ao caso anterior, substituindo t pelo valor 0 e d por
dmax na (eq.5) teremos:
⇒=−⇒−−
=⇒
−
−−
=min
maxminmaxminmax
min
max 0)(
0τ
λδτλδττ
τδλrd
rdrd
rrd +=+= δνδτ
λmax
minmax (eq. 7)
Como ρ e d são inversamente proporcionais, ρ = τmin quando d = dmax e ρ =
τmax quando d = dmin, então em vez de escrever t como na (eq. 3), poderíamos, de
maneira equivalente, escrevê-lo como:
39
maxmin
max
ddddt
−−
= ou, equivalentemente (após multiplicar ambos os lados da
equação por –1): minmax
max
dddd
t−−
=
Finalmente, escolhendo trabalhar com as distâncias ao quadrado (para não
nos preocuparmos com questões de sinal), temos que t pode ser definido como:
2min
2max
22max
ddddt
−−= (eq. 8)
Finalmente, note, no pseudo-código do refinamento básico, que precisamos
alterar o procedimento AnexaStrip que recebe o índice do vértice como parâmetro
para que, em vez disso, ele agora receba as coordenadas x, y e z do vértice a ser
anexado no vetor de triângulos a ser renderizado.
Em seguida apresentamos o pseudo-código para o geomorphing tal como
descrito acima:
RefinaSubMalhaMorph (V, i, j, l, zl, za, zr) t = Morph(i); Se (l > 0) && (t > 0)) z = t*zi + (1-t)*za; m = (zl + zr)/2; RefinaSubMalhaMorph(V,j, fe, l-1, zl,m, z); AnexaPonto(V, xi, yi, z,(l % 2)); RefinaSubMalhaMorph(V,j,fd, l-1,z, m, zr); Morph (i) d = ||pi – o||; dmax = νmax* δI + ri; Se (d < dmax) dmin = νmin * δi + ri; Se (d > dmin) retorne (dmax
2 – d2)/(dmax2 - dmin
2); senão retorne 1; senão retorne 0;
4 Testes
Neste capítulo apresentamos uma aplicação que permite realizar vôos sobre
terrenos utilizando o algoritmo discutido ao longo deste trabalho. Em seguida,
adicionamos e comentamos alguns testes realizados utilizando esta aplicação.
4.1. Breve Descrição da Aplicação
O programa SJD-Vis3D[11] simula um vôo sobre um terreno e está sendo
desenvolvido pelo Tecgraf para a Marinha do Brasil. O algoritmo discutido neste
trabalho é utilizado para obter, a cada quadro, a malha do terreno sendo
sobrevoado. Vale destacar que o programa SJD-Vis3D é implementado em
linguagem C++, utiliza a biblioteca gráfica OpenGL[12] e arquivos de descrição
feitos na linguagem de scripts Lua[13]. Para maiores detalhes sobre a descrição do
programa SJD-Vis3D, veja o apêndice A.
4.2. Descrição dos Testes com a Aplicação SJD-Vis3D
Todos os nossos testes foram realizados nas seguintes plataformas:
1) Computador Intel® Pentium® 4 CPU 1700 MHZ AT/AT Compatible
com 512 MB de RAM, equipado com uma placa gráfica NVIDIA GeForce4 Ti
4200.
2) Computador Intel® Pentium® 4 CPU 2.53 GHz com 3,00 GB de RAM,
com uma placa gráfica NVIDIA Quadro FX1000.
Durante os testes, a plataforma 1 executava o sistema operacional Microsoft
Windows 2000 e a plataforma 2 o Microsoft Windows XP. Além disso, em todos
os testes o tamanho da janela utilizada foi sempre de 800x600 pixels.
A Tabela 2 apresenta os principais dados dos quatro terrenos utilizados em
nossos testes. Os dois primeiros pertencem à Marinha do Brasil e representam a
região de Itaóca, localizada no litoral do estado brasileiro do Espírito Santo. Os
41
outros dois foram obtidos a partir de imagens disponibilizadas em [14] e
representam uma região de Washington, nos Estados Unidos.
Dados dos
terrenos
Dimensões do
terreno (km2)
Número de
amostras
Dimensões de
uma célula de
amostra (m3)
Dimensões da
matriz utilizada
Itaoca1 26,2 x 34,8 525 colunas e
697 linhas =
365.925 50x50x1 1025 x 1025
Itaoca2 26,2 x 34,8
1312 colunas e
1741 linhas =
2.284.192
amostras
20x20x1 2049x2049
Washington1 163,84x163,84
1025 colunas e
1025 linhas =
1.050.625
160x160x0,1 1025 x 1025
Washington2 163,84x163,84
4097 colunas e
4097 linhas =
16.785.409
40x40x0,1 4097x4097
Tabela 2 - Dados dos Terrenos.
Em algoritmos dependentes da visão, como o tratado neste trabalho, o
número de triângulos gerados depende sobretudo da distância da câmera, do erro
tolerável especificado e se a região vista é mais ou menos plana. Assim, por
exemplo, regiões vistas de longe e mais planas geram menos triângulos.
Todavia, com o intuito de analisar o algoritmo em condições variadas,
construímos quatro caminhos (um sobre cada um dos terrenos mostrados na
Tabela 2) e depois realizamos algumas medidas. As figuras 19, 20, 21 e 22
apresentam graficamente cada um dos caminhos de teste. Cada caminho é
composto por 1500 quadros e leva o mesmo nome do terreno sobre o qual foi
executado. Em geral, procuramos incluir nos caminhos as regiões mais
montanhosas de cada terreno. Além disso, repare que todos iniciam com a câmera
posicionada no centro do respectivo terreno. (Observação: as informações escritas
sobre as imagens (no canto superior esquerdo) em (b), (c), (d) e (e) de cada figura
podem ser desprezadas neste ponto).
42
a) Caminho sobre o terreno
b) Vista em (a), quadro 200. c) Vista em (b), quadro 600.
d) Vista em (c), quadro 920. e) Vista em (d), quadro 1200.
Figura 19 - Caminho sobre o terreno Itaoca1
a b
c d
43
a) Caminho sobre o terreno
b) Vista em (a), quadro 90. c) Vista em (b), quadro 580.
d) Vista em (c), quadro 900. e) Vista em (d), quadro 1200.
Figura 20 - Caminho sobre o terreno Itaoca2.
a b
c
d
44
a) Caminho sobre o terreno
b) Vista em (a), quadro 512. c) Vista em (b), quadro 970.
d) Vista em (c), quadro 1160. e) Vista em (d), quadro 1200.
Figura 21 - Caminho sobre o terreno Washington1
a b c
d
45
a) Caminho sobre o terreno
b) Vista em (a), quadro 400. c) Vista em (b), quadro 670.
d) Vista em (c), quadro 980. e) Vista em (d), quadro 1300.
Figura 22 - Caminho sobre o terreno Washington2
a b
c
d
46
4.2.1. Verificando o Culling da Malha fora da Visão
Para analisar a operação de culling da malha fora da visão, executamos cada
um dos caminhos de teste com o culling e depois repetimos o mesmo caminho
sem o culling. Realizamos este procedimento nas duas plataformas usadas para
teste e então, com os resultados coletados, construímos os gráficos mostrados na
Figura 23 e nas tabelas 3 e 4. As tabelas apresentam o valor médio em FPS
(frames per second) obtido ao longo de cada caminho nas plataformas 1 e 2,
respectivamente. Já os gráficos realçam o contraste entre a quantidade de
triângulos desenhados quando a operação de culling está sendo utilizada e quando
não está. Repare que, em todos os caminhos e em todos os momentos, esta
operação sempre permite descartar um número significativo de triângulos e
aumentar o desempenho da aplicação.
FPS Médio Itaoca1 Itaoca2 Washington1 Washington2
Com Culling 48,6 31,6 33,0 20,7
Sem Culling 17,7 9,2 10,4 4,8
Tabela 3 - FPS Médio de cada caminho feito com e sem culling na plataforma 1.
FPS Médio Itaoca1 Itaoca2 Washington1 Washington2
Com Culling 79,0 50,9 52,0 35,3
Sem Culling 31,4 15,9 17,1 8,3
Tabela 4 - FPS Médio de cada caminho feito com e sem culling na plataforma 2.
Podemos observar, através destes gráficos, que, quanto maior o terreno,
mais importante se torna esta operação. Tomemos como primeiro exemplo o
caminho Itaoca1 executado na plataforma 2. Neste caso, como o terreno é
pequeno e a plataforma é relativamente potente, então mesmo sem o culling de
visão ainda conseguimos obter uma taxa de 31,4 quadros por segundo.
Agora tomemos como segundo exemplo o caminho Washington2 também
executado na plataforma 2. Repare que obtemos uma boa taxa média de 35,3
quadros por segundo quando utilizando o culling da malha fora da visão.
Eliminando esta operação a taxa média cai para 8,3 quadros por segundo. Neste
exemplo, fica evidenciado que a operação de culling da malha fora da visão
tornou-se essencial para assegurar taxas interativas (normalmente acima de 20
FPS) ao longo do caminho.
47
Caminho Itaoca1
0
5000
10000
15000
20000
25000
30000
10 210 410 610 810 1010 1210 1410
Número do Quadro
Triâ
ngul
os D
esen
hado
s
C/ culling S/ culling
a)
Caminho Itaoca2
010000200003000040000500006000070000
10 210 410 610 810 1010 1210 1410
Número do Quadro
Triâ
ngul
os D
esen
hado
s
C/ culling S/ cullling
b)
48
Caminho Washington1
0
10000
20000
30000
40000
50000
60000
10 210 410 610 810 1010 1210 1410
Número do Quadro
Triâ
ngul
os D
esen
hado
s
C/ culling S/ culling
c)
Caminho Washington2
020000400006000080000
100000120000140000
10 210 410 610 810 1010 1210 1410
Número do Quadro
Triâ
ngul
os D
esen
hado
s
C/ culling S/ culling
d)
Figura 23 - Comparação do número de triângulos gerados com e sem a operação de
culling fora da visão.
Além disso, através da seqüência de imagens geradas a partir de um quadro
do terreno Washington1 e apresentadas na Figura 24 é possível verificar
visualmente a diferença entre uma malha produzida quando a operação de culling
da malha fora da visão está sendo utilizada e quando não está.
49
a) Quadro com textura. b) Quadro em wireframe e sem textura.
c) Malha do quadro em a, com culling. d) Malha do quadro em a, sem culling. Figura 24 - Quadro do terreno Washington1
4.2.2. Verificando o Geomorphing
Analogamente ao método usado para a operação anterior, para analisar a
operação de geomorphing executamos o algoritmo com o geomorphing e, depois
sem o geomorphing, mas sem modificar o erro tolerável e, finalmente, sem o
geomorphing, porém usando um erro tolerável bem pequeno. A idéia aqui é que
para se obter um resultado visual equivalente ao geomorphing, o erro tolerável
deve ser pequeno. O propósito do geomorphing é permitir especificar um erro
tolerável relativamente grande, buscando reduzir o número de triângulos gerados,
portanto aumentando o desempenho da aplicação e, ao mesmo tempo, sem
produzir artefatos visuais desagradáveis (como montanhas aparecendo e
desaparecendo bruscamente) à medida que a câmera se movimenta.
Além disso, conforme já explicado no capítulo anterior, para utilizar o
geomorphing devemos especificar uma faixa de erro tolerável (diferença entre as
tolerâncias mínima e máxima especificadas). Quanto maior esta faixa mais suave
50
serão as transições durante o vôo, porém mais triângulos serão gerados. Neste
caso, estamos utilizando uma tolerância máxima igual 3/2 * tolerância mínima.
Esta fórmula foi sugerida por Lindstrom & Pascucci[3] e confirmada em nossos
testes como fornecedora de bons resultados.
Desta forma, eliminando o geomorphing, temos duas opções. A primeira é
continuar usando um erro tolerável grande, ou seja, igual à tolerância máxima do
caso anterior. Neste caso, conforme pode ser confirmado pelas tabelas 5 e 6 e nos
gráficos da Figura 25, o número de triângulos gerados diminui e a taxa de quadros
por segundo aumenta. O inconveniente é que também perdemos em qualidade de
apresentação, pois grandes montanhas começam a aparecer e desaparecer
instantaneamente quando a câmera se move.
Como exemplo, vamos considerar o caminho Itaoca2 realizado na
plataforma 1. Neste caso, utilizando o geomorphing alcançamos uma taxa média
de 32,0 quadros por segundo. Retirando o geomorphing a média obtida sobe para
45,6 quadros por segundo. Contudo, claramente, as montanhas do terreno
aparecem e desaparecem bruscamente quando a câmera se movimenta.
Por outro lado, usando a segunda opção, ou seja, um erro tolerável pequeno
o bastante para que estes artefatos visuais não sejam percebidos, a taxa de quadros
ou o FPS médio cai para apenas 10,4.
Repare que, analogamente ao culling da malha fora da visão, a operação de
geomorphing também torna-se mais importante à medida que aumentamos o
tamanho do terreno.
FPS Médio Itaoca1 Itaoca2 Washington1 Washington2
Com Geo 48,4 32,0 33,1 21,7 Sem Geo e Tol
grande 61,5 45,6 48,2 28,5
Sem Geo e Tol pequena 21,7 10,4 10,9 5,6
Tabela 5 - FPS Médio de cada caminho feito com e sem geomorphing na plataforma 1.
FPS Médio Itaoca1 Itaoca2 Washington1 Washington2
Com Geo 79,0 50,9 52,0 35,3 Sem Geo e Tol
grande 85,0 66,3 69,6 51,4
Sem Geo e Tol pequena 34,2 16,4 17,2 9,2
Tabela 6 - FPS Médio de cada caminho feito com e sem geomorphing na plataforma 2.
51
Caminho Itaoca1
0
5000
10000
15000
20000
25000
10 210 410 610 810 1010 1210 1410
Número do Quadro
Triâ
ngul
os D
esen
hado
s
C/ Geo S/ Geo e Tol G S/ Geo e Tol P
a)
Caminho Itaoca2
0
10000
20000
30000
40000
50000
60000
10 210 410 610 810 1010 1210 1410
Número do Quadro
Núm
ero
de T
riâng
ulos
Com Geo S/Geo e Tol G S/Geo e Tol P
b)
52
Caminho Washington1
0
10000
20000
30000
40000
50000
10 210 410 610 810 1010 1210 1410
Número do Quadro
Núm
ero
de T
riâng
ulos
C/ Geo S/ Geo e Tol G S/ Geo e Tol P
c)
Caminho Washington2
0
20000
40000
60000
80000
100000
120000
10 210 410 610 810 1010 1210 1410
Número do Quadro
Triâ
ngul
os D
esen
hado
s
C/ Geo S/ Geo e Tol G S/ Geo e Tol P
d)
Figura 25 - Gráficos comparativos entre o número de triângulos desenhados.
1) (C/Geo): a operação de geomorphing é usada. 2) (S/ Geo e Tol G): o geomorphing
não é usado e o erro tolerável é tão grande quando no primeiro caso. 3) (S/Geo e Tol P):
o geomorphing não é usado, mas o erro tolerável é pequeno a ponto de oferecer uma
sensação visual similar ao caso em que o geomorphing está sendo usado.
53
4.2.3. Verificando a Strip de Triângulos
Para analisar a eficiência da strip ou lista de vértices que é construída pelo
algoritmo de refinamento, vamos considerar todos os nossos quatro caminhos de
teste. Em cada intervalo de dez quadros ao longo de cada caminho, coletamos o
número total de triângulos enviados para o pipeline gráfico e o número de
triângulos válidos, ou seja, triângulos com área não nula de um quadro de
amostra. Apresentamos os resultados obtidos nos gráficos da Figura 26.
Além disso, considerando os caminhos Itaoca1 e Itaoca2 inteiros, obtivemos
que o número total de triângulos ao longo do caminho dividido pelo número de
triângulos válidos resultou em 1,56. Em outras palavras, neste caso, para desenhar
cada triângulo da malha gerada, estamos enviando uma média de 1,56 vértices
para o pipeline gráfico. No caso dos caminhos Washington1 e Washington2, o
número total de triângulos dividido pelo número de triângulos válidos resultou em
1,57, ou seja, estamos enviando em média 1,57 vértices para desenhar cada
triângulo da malha. Repare pelos gráficos que esta razão permanece constante ao
longo de todos os caminhos.
Portanto, podemos considerar esta strip ou lista de vértices eficiente, pois
sem ela teríamos que informar sempre 3 vértices para cada triângulo a ser
desenhado.
Caminho Itaoca1
0
2000
4000
6000
8000
10000
12000
10 210 410 610 810 1010 1210 1410
Número do Quadro
Núm
ero
de T
riâng
ulos
Total Válidos
a)
54
Caminho Itaoca2
0
5000
10000
15000
20000
25000
30000
10 210 410 610 810 1010 1210 1410
Número do Quadro
Núm
ero
de T
riâng
ulos
Total Válidos
b)
Caminho Washington1
0
5000
10000
15000
20000
25000
10 210 410 610 810 1010 1210 1410
Número do Quadro
Núm
ero
de T
riâng
ulos
Total Válidos
c)
55
Caminho Washington2
05000
10000150002000025000300003500040000
10 210 410 610 810 1010 1210 1410
Número do Quadro
Núm
ero
de T
riâng
ulos
Total Válidos
d)
Figura 26 - Gráficos comparativos entre o número total de triângulos ou vértices enviados
para o pipeline gráfico e o número de triângulos válidos.
4.2.4. Verificando o Pré-Processamento
Muitos algoritmos para visualização de terrenos mencionam estratégias
complexas e tempos consideráveis para esta etapa. A Tabela 7 mostra o tempo em
segundos gasto na etapa de pré-processamento de cada um dos quatro terrenos
utilizados em nossos testes nas plataformas 1 e 2. Os tempos fornecidos nesta
tabela englobam a leitura dos arquivos contendo o campo de alturas e a textura,
além, é claro, do procedimento de preparação dos dados de entrada para o
refinamento em tempo real. O tempo consumido nesta etapa é proporcional ao
tamanho do terreno e dependente do poder de processamento da plataforma.
Porém, note que mesmo para o terreno maior, o Washington2, composto por mais
de 16 milhões de amostras, o pré-processamento não atinge 2 minutos.
Além disso, pode-se executar o pré-processamento para cada terreno uma
única vez e depois mantê-los armazenados em disco. A partir daí quando
desejarmos sobrevoar um terreno basta ler o respectivo arquivo pré-processado e a
partir dele executar o refinamento em tempo real.
56
Repare na Tabela 7 que para todos os terrenos, exceto Washington2, os
valores de tempo são bem próximos nas duas plataformas. No caso do terreno
Washington2 na plataforma 1 o que acontece é que, com nossas estruturas de
dados, ele ocupa algo em torno de 900MB em memória e a plataforma 1 só dispõe
512 MB de memória RAM. Desta forma, o sistema precisa utilizar memória
virtual e isto justifica um consumo de tempo maior.
Tempo (em s) do Pré-
Processamento Plataforma 1 Plataforma 2
Itaoca1 0,9 0,7 Itaoca2 2,6 2,0
Washington1 1,1 0,8 Washington2 111,0 13,8
Tabela 7 - Tempo médio do pré-processamento de cada terreno.
4.2.5. Comparando os Algoritmos de Lindstrom & Pascucci e de De Boer
Esta seção dedica-se a uma comparação da nossa implementação do
algoritmo analisado ao longo deste trabalho e proposto por Lindstrom &
Pascucci[2] com uma implementação do algoritmo proposto por De Boer[8] feita
por Eduardo Ribeiro Poyart. Este último também trabalha com malhas regulares e
é ainda mais simples que o primeiro. A idéia principal do trabalho de De Boer é
aproveitar o máximo do potencial oferecido pelos mais recentes hardwares
gráficos, enviando o máximo de triângulos que o processador for capaz de gerar e,
ao mesmo tempo, que o hardware gráfico suportar. Vale ressaltar, porém, que De
Boer não supõe a necessidade de nenhum esquema de geomorphing. Assim, para
não obter o efeito desagradável de montanhas aparecendo e desaparecendo
bruscamente, é preciso usar sempre uma resolução e, conseqüentemente uma
tolerância, bem pequenas. Desta forma, procuramos escolher uma tolerância para
o algoritmo de De Boer que fornecesse resultados visuais mais ou menos
equivalentes aos resultados fornecidos pelo algoritmo de Lindstrom & Pascucci.
Assim, para realizar esta comparação utilizamos todos os caminhos de teste
citados anteriormente. Executamos cada caminho uma vez usando o algoritmo de
Lindstrom & Pascucci e outra usando o algoritmo de De Boer. Além disso,
repetimos isto nas duas plataformas utilizadas para teste.
Os resultados obtidos são mostrados nos gráficos da Figura 27 e nas tabelas
8, 9, 10 e 11. Nestas figuras e tabelas, P1 denota o respectivo algoritmo executado
57
na plataforma 1 e analogamente P2 na plataforma 2. Assim, por exemplo,
Lindstrom-P1 refere-se aos resultados obtidos com o algoritmo de Lindstrom &
Pascucci executado na plataforma 1 e assim por diante.
Para desenhar estes gráficos, coletamos o número de triângulos desenhados
em um quadro de amostra a cada dez quadros produzidos. Portanto, ao longo de
cada caminho, que é composto por 1.500 quadros ou frames, coletamos 150
valores.
As tabelas 8, 9, 10 e 11 apresentam o FPS médio e o tempo consumido na
etapa de inicialização para os caminhos Itaoca1, Itaoca2, Washington1 e
Washington2, respectivamente.
Caminho Itaoca1 Lindstrom-P1 DeBoer-P1 Lindstrom-P2 DeBoer-P2
FPS Médio do Caminho 48,4 42,8 79,0 52,4
Tempo de Inicialização 2,6 0,7 0,7 0,5
Tabela 8 - Comparação do caminho Itaoca1 com ambos os algoritmos e ambas as
plataformas.
Caminho Itaoca2 Lindstrom-P1 DeBoer-P1 Lindstrom-P2 DeBoer-P2
FPS Médio do Caminho 31,9 21,1 50,9 23,8
Tempo de Inicialização 2,6 1,5 2,1 1,1
Tabela 9 - Comparação do caminho Itaoca2 com ambos os algoritmos e ambas as
plataformas.
Caminho Washington1
Lindstrom-P1 DeBoer-P1 Lindstrom-P2 DeBoer-P2
FPS Médio do Caminho 33,0 25,8 52,0 29,1
Tempo de Inicialização 1,2 1,1 0,9 0,6
Tabela 10 - Comparação do caminho Washington1 com ambos os algoritmos e ambas
as plataformas.
Caminho Washington2
Lindstrom-P1 DeBoer-P1 Lindstrom-P2 DeBoer-P2
FPS Médio do Caminho 20,7 7,4 35,3 8,0
Tempo de Inicialização 98,6 11,8 13,8 5,6
Tabela 11 - Comparação do caminho Washington2 com ambos os algoritmos e ambas
as plataformas.
58
Caminho Itaoca1
020406080
100120140160
10 210 410 610 810 1010 1210 1410
Número do Quadro
FPS
Méd
io
Lindstrom-P1 Lindstrom-P2 DeBoer-P1 DeBoer-P2
a)
Caminho Itaoca2
020406080
100120140160
10 210 410 610 810 1010 1210 1410
Número do Quadro
FPS
Méd
io
Lindstrom-P1 Lindstrom-P2 DeBoer-P2 DeBoer-P1
b)
59
Caminho Washington1
0
50
100
150
200
250
10 210 410 610 810 1010 1210 1410
Número do Quadro
FPS
Méd
io
Lindstrom-P1 Lindstrom-P2 DeBoer-P1 DeBoer-P2
c)
Caminho Washington2
020406080
100120140160
10 210 410 610 810 1010 1210 1410
Número do Quadro
FPS
Méd
io
Lindstrom-P1 Lindstrom-P2 DeBoer-P1 DeBoer-P2
d)
Figura 27 - Comparação dos algoritmos de Lindstrom & Pascucci e de De Boer nas
plataformas P1 e P2.
Note que no caminho Itaoca1 não obtemos grandes diferenças. Como trata-
se de um terreno pequeno, então podemos dizer que conseguimos obter taxas
interativas com ambos os algoritmos e em ambas as plataformas.
Porém, o mesmo não acontece com os outros caminhos, principalmente com
o caminho Washington2. Neste caso, por se tratar de um terreno bem maior,
podemos dizer que o algoritmo de De Boer enviou mais triângulos para o
hardware do que ele podia suportar. Já com o algoritmo de Lindstrom & Pascucci
ainda conseguimos obter taxas interativas, mesmo com este terreno maior. Repare
60
no gráfico que mostra os resultados do caminho Washington2 que nos primeiros
quadros o algoritmo de Lindstrom & Pascucci obtém taxas (FPS) bem elevadas,
mas depois estas taxas decrescem um pouco. Isto acontece porque o terreno dentro
do frustum de visão é mais plano nesta parte inicial do caminho. Já o algoritmo de
De Boer, por não levar em conta a geometria do terreno, não apresenta esta
mesma variação.
Pelo gráfico, podemos ver que, no caminho Washington2 o algoritmo de De
Boer nunca ultrapassa o de Lindstrom & Pascucci. No caminho Itaoca1,
entretanto, na fase final, mais ou menos a partir do quadro 900, o algoritmo de De
Boer consegue obter taxas iguais ou até superiores ao algoritmo de Lindstrom &
Pascucci. O que acontece é que, neste trecho, somente uma parte bem pequena do
terreno (que já é pequeno) está sendo vista. Assim, como o culling da malha fora
da visão de De Boer é mais simples e rápido, o algoritmo de De Boer começa a
ganhar uma certa vantagem.
Note que o algoritmo de Lindstrom & Pascucci invariavelmente apresenta
melhor desempenho na plataforma 2, que é equipada com um processador mais
potente. Já o algoritmo de De Boer em geral apresenta o mesmo desempenho nas
duas plataformas. Isto acontece, provavelmente, porque o hardware gráfico de
cada uma delas tem apresentado desempenhos mais ou menos equivalentes.
Quanto ao pré-processamento, devemos destacar que se no algoritmo de
Lindstrom & Pascucci ele é relativamente simples, no algoritmo de De Boer ele
praticamente inexiste. Os valores de tempo medidos na fase de inicialização, no
caso do algoritmo de De Boer, certamente referem-se ao tempo gasto com a
leitura do mapa de alturas e da textura. No caso dos caminhos Itaoca1, Itaoca2 e
Washington1, podemos dizer que ambos foram bem rápidos nas duas plataformas,
conforme pode ser observado nas tabelas 8, 9 e 10. Já para o caminho
Washington2, obtivemos uma diferença relativamente significativa na plataforma
1. Neste caso, o algoritmo de Lindstrom & Pascucci consumiu mais de um minuto
e meio na inicialização, enquanto o de De Boer consumiu 11,8 segundos.
Contudo, na plataforma 2, que possui um processador mais potente, a diferença
não foi tão considerável, conforme pode ser visto na Tabela 11.
61
4.2.6. Verificando o Número de Triângulos da Malha Gerada
Para investigar o número de triângulos da malha gerada pelo algoritmo
descrito neste trabalho, foi feita uma comparação com um método de
simplificação por inserção gulosa baseada no erro vertical local descrito em[15] e
que promete gerar uma boa malha aproximada para um dado conjunto de
amostras, não necessariamente dispostas em uma grade regular. O algoritmo
descrito em [15] não leva em conta nenhum critério perceptual. Em vez disso, ele
apenas gera uma malha de triângulos aproximada a partir de um conjunto de
amostras e sempre comparando esta malha aproximada com a malha original. Na
verdade, é usado o algoritmo de triangulação de Delaunay incremental, usando um
método de inserção gulosa como critério de seleção baseado no erro vertical local.
Assim, o algoritmo começa com uma triangulação mínima (2 triângulos grandes
envolvendo o terreno inteiro), mantendo uma estrutura tipo heap para guardar o
ponto com maior erro em cada triângulo existente na triangulação corrente. Então,
a cada iteração, escolhe-se o ponto com maior erro dentre estes pontos do heap
para entrar na triangulação de Delaunay. Este procedimento é repetido enquanto o
maior erro for maior que uma tolerância especificada.
Assim, para efetuar a comparação do algoritmo em estudo com o algoritmo
descrito brevemente acima, desabilitamos o culling da malha fora da visão, o
geomorphing e modificamos o erro projetado na tela para também não levar em
conta a posição do observador. Em outras palavras, estamos usando o refinamento
básico e fazendo nosso erro no espaço da tela como sendo igual ao erro no espaço
do objeto.
Executamos nosso algoritmo modificado para dois terrenos usados no
trabalho descrito em [15]. A Tabela 12 abaixo, extraída de [15], mostra os dados
destes dois terrenos.
Terreno Dim X Dim Y Total de
Triângulos
Alt.
mínima
Alt.
máxima
Variação
máxima
Desvio
padrão
cvzbuffalo 120 120 28832 15,80 64,2 48,40 13,22
Ilha 256 256 130050 0,070 17,08 17,01 3,39
Tabela 12 - Características dos terrenos testados.
62
Na Tabela 13 apresentamos os resultados da comparação usando os dois
algoritmos para o terreno ilha.
Delaunay com inserção
gulosa
Lindstrom & Pascucci
modificado Erro
2.498 1.297 0,97
4.998 3.086 0,56
7.498 5.585 0,39
9.998 8.060 0,32
12.498 9.932 0,28
14.998 12.153 0,25
Tabela 13 - Número de triângulos gerados para o terreno ilha.
Na Figura 28 mostramos algumas imagens do terreno ilha.
a) Vista superior com textura b) vista de um quadro qualquer
c) quadro (a) em wireframe e sem textura d) quadro (b) em wireframe e sem textura. Figura 28 - Imagens do terreno ilha
Na Tabela 14 apresentamos os resultados da comparação usando os dois
algoritmos para o terreno cvzbuffalo.
63
Delaunay com inserção
gulosa
Lindstrom & Pascucci
modificado Erro
2.497 4.098 2,10
4.998 7.380 1,00
7.498 9.823 0,50
9.947 11.451 0,33
12.497 14.535 0,08
14.998 16.110 0,00
Tabela 14 - Número de triângulos gerados para o terreno cvzbuffalo
Na Figura 29 mostramos algumas imagens do terreno cvzbuffalo. Repare
que não temos uma textura específica para este terreno.
a) Vista superior b) vista de um quadro qualquer
Figura 29 - Imagens do Terreno cvzbuffalo
Pelas tabelas 13 e 14, podemos verificar que para o terreno ilha o algoritmo
de Lindstrom & Pascucci modificado consegue obter uma malha aproximada com
menor número de triângulos que a malha produzida pelo algoritmo de Delaunay
com inserção gulosa. Já para o terreno cvzbuffalo acontece o contrário. Neste
caso, a malha gerada pelo algoritmo de Delaunay com inserção gulosa contém
menos triângulos que a malha gerada pelo algoritmo de Lindstrom & Pascucci
modificado.
O que acontece é que estes dois terrenos não encaixam-se no formato
(2n/2+1) x (2n/2+1) exigido pelo algoritmo de Lindstrom & Pascucci e então eles
precisaram ser estendidos. Porém para o terreno ilha esta estensão consiste de
apenas uma faixa de um vértice em cada direção.
Enfim, podemos concluir que o algoritmo de Lindstrom & Pascucci, quando
trabalha com terrenos que possuem dimensões (2n/2+1) x (2n/2+1) ou valores bem
64
próximos disto (como o terreno ilha que possui dimensões 2n/2 x 2n/2), funciona
muito bem, gerando uma malha aproximada provavelmente bem próxima a uma
malha ótima. Porém, quando o terreno não se encaixa neste formato e é necessário
estendê-lo, não se pode continuar afirmando o mesmo.
5 Conclusão
O objetivo deste trabalho foi compreender o problema da visualização
interativa de terrenos de modo geral e, simultaneamente, investigar o algoritmo
proposto por Lindstrom & Pascucci para este problema. Sendo assim, a tarefa de
implementação deste algoritmo, seguida dos testes realizados em diferentes
situações e incluindo a comparação prática com outro algoritmo da área, nos
forneceu uma experiência importante.
Muitas de nossas constatações, de certo modo, corroboram a maioria das
afirmações antecipadas nos trabalhos de Lindstrom & Pascucci. Assim,
primeiramente, é preciso destacar os bons resultados fornecidos pelo algoritmo.
Em nossos testes em condições normais, o algoritmo sempre conseguiu fornecer
taxas interativas ou acima de 20 FPS (frames per second) em média. Além disso,
foi possível verificar que a tarefa de implementação do algoritmo, de fato, é
relativamente simples, principalmente quando comparada com alguns outros da
área, bem mais complexos.
Apesar de o algoritmo poder ser implementado e executado sem incorporar
as operações de culling da malha fora da visão e geomorphing, nossos testes
revelaram que elas se tornam imprescindíveis à medida que as dimensões do
terreno aumentam. Contudo, a escolha de exatamente o que utilizar ou dispensar
depende das necessidades específicas de cada aplicação. Por exemplo, a partir de
nossos testes, obtivemos bons resultados para o terreno menor, o Itaoca1, em
praticamente todas as condições. Em outros termos, se a aplicação irá trabalhar
somente com terrenos bem pequenos, como o Itaoca1, então não parece tão
necessário implementar culling da malha fora da visão e geomorphing. Na
verdade, neste caso, o algoritmo de De Boer, provavelmente, será suficiente.
Por outro lado, devemos ressaltar que em nossos testes foram analisadas
somente questões relativas à malha que aproxima o terreno. Contudo, aplicações
reais podem e devem utilizar recursos como texturas de melhor qualidade,
66
iluminação e fog (neblina) adequados com o intuito de melhorar a qualidade final
das apresentações.
Além disso, devemos dizer que, neste trabalho, não foram feitos testes para
comparar o número de triângulos gerados pelo algoritmo de refinamento estudado
aqui e uma malha ótima (possivelmente, gerada por um algoritmo de
simplificação). Porém, segundo Lindstrom & Pascucci[3], este algoritmo de
refinamento produz uma malha bem próxima a uma malha ótima.
Outra questão não implementada neste trabalho foi o esquema de multi-
threads, também sugerido por Lindstrom & Pascucci, possivelmente uma thread
sendo responsável pelo refinamento e outra pela renderização da malha produzida.
Espera-se que isto melhore ainda mais o desempenho da aplicação, o que é
confirmado por Lindstrom & Pascucci através de uma análise neste sentido
mostrada em [3]. Em princípio, e conforme já dito e mostrado por nossos testes,
mesmo sem usar multi-threads o algoritmo tem fornecido bons resultados.
Provavelmente o uso de multi-threads se tornará importante quando executando
terrenos de dimensões bem maiores que os terrenos usados em nossos testes.
Também não implementamos o esquema de organização dos dados proposto
por Lindstrom & Pascucci em [2] e [3] para trabalhar de modo eficiente com
terrenos que não cabem completamente na memória. Por conta disso, não
conseguimos trabalhar, em nossas plataformas de teste, com um terreno de
dimensões 16.385 x 16.385 também disponibilizado em [14] e representando uma
região de Washington, nos Estados Unidos. Segundo os próprios Lindstrom &
Pascucci, este terreno ocuparia algo em torno de 5 GB em memória e nossa
plataforma de teste mais potente está equipada com 3 GB de memória RAM.
Contudo, devemos destacar que nossa implementação, ou seja, nosso
módulo Terreno, está sendo utilizado no desenvolvimento de aplicações no
laboratório Tecgraf. Destacamos entre elas, um sistema para análise e visualização
de dados sísmicos tridimensionais selecionados em camadas e depois agrupados
por um algoritmo baseado em rede neurais híbridas que está sendo desenvolvido
em parceria com a Petrobras. Outro destaque é o sistema de jogos didáticos para
treinamento e ensino que inclui um simulador de vôos sobre terrenos reais e está
sendo desenvolvido em parceria com a Marinha do Brasil.
Resumidamente, comprovamos que os trabalhos de Lindstrom & Pascucci e,
especificamente, o algoritmo estudado neste trabalho, sem dúvida trouxeram
67
contribuições significativas para o problema da visualização interativa de terrenos.
Inclusive, imagina-se que não será fácil superá-lo tão cedo. Contudo, ainda não se
pode considerar que está tudo resolvido e o principal ponto fraco deste algoritmo é
o alto consumo de memória.
Sendo assim, apesar dos bons resultados apresentados pelos recentes
trabalhos de Lindstrom & Pascucci, as pesquisas nesta área ainda não devem ser
consideradas concluídas. Aplicações exigindo terrenos cada vez maiores e com
superfícies cada vez mais complexas sinalizam no sentido inverso. No entanto, a
tendência parece ser a utilização de estratégias de software inteligentes e que, ao
mesmo tempo, procurem tirar o máximo proveito das facilidades oferecidas pela
indústria de hardware, que também encontra-se em constante evolução.
5.1. Trabalhos Futuros
Nossa implementação pode ser evoluída, ainda seguindo as idéias propostas
por Lindstrom & Pascucci, para trabalhar com terrenos que não podem ser
totalmente carregados para a memória e usando o esquema de multi-threads. Na
verdade, não basta que o mapa de alturas e a textura caibam na memória, pois na
fase de pré-processamento algumas informações são incorporadas aos dados de
entrada e, se o terreno não se encaixar no formato (2n/2 + 1) x (2n/2 + 1), onde n é
um inteiro maior ou igual 2, ele precisa ser estendido. Em outras palavras,
considerando que, em geral, este algoritmo consome uma quantidade significativa
de memória, então para processar terrenos realmente grandes é importante poder
manter parte dos dados em disco.
Além disso, conforme já dito, o uso de multi-threads pode se tornar um
componente importante para acelerar a renderização quando desejarmos trabalhar
com terrenos suficientemente grandes.
Podemos também tentar substituir as esferas envolventes associadas com
cada vértice por outro volume menos folgado. Se não for um volume cujo teste de
interseção com os planos do frustum de visão seja complexo, isto poderia acelerar
o culling da malha fora da visão, permitindo identificar mais cedo se uma região
está localizada dentro ou fora do frustum de visão e, assim, aumentar a velocidade
do algoritmo.
68
Outra possibilidade de trabalho futuro trata-se da utilização das idéias que
incluem estereoscopia publicado em [9] em conjunto com o algoritmo de
Lindstrom & Pascucci estudado neste trabalho.
Finalmente, é importante prosseguir investindo na busca por alternativas
que não exijam um terreno de dimensões (2n/2 + 1) x (2n/2 + 1), simplifiquem ainda
mais a complexidade e o tempo consumido no pré-processamento dos dados, não
consumam tanta memória e que, ao mesmo tempo, mantenham ou
preferencialmente melhorem o desempenho do algoritmo atual.
69
6 Referências Bibliográficas
1 COHEN-OR, D.; CHRYSANTHOU, Y.; SILVA, C. T. A Survey of Visilibity
for Wakthrough Applications. Proceedings of EUROGRAPHICS '00, course
notes, 2000.
2 LINDSTROM, P.; PASCUCCI, V. Visualization of Large Terrains Made
Easy. Proceedings of IEEE Visualization 2001, San Diego, California, October,
2001, pp. 363-370.
3 LINDSTROM, P.; PASCUCCI, V. Terrain Simplification Simplified: A
General Framework for View-Dependent Out-of-Core Visualization. IEEE
Transactions on Visualization and Computer Graphics, May 8, 2002.
4 TOLEDO, R. QuadLod: Uma Estrutura para a Visualização Interativa de
Terrenos. Rio de Janeiro, 2000. Dissertação de Mestrado. Departamento de
Informática, PUC-Rio.
5 LINDSTROM, P. et al. Real-Time, Continuous Level of Detail Rendering of
Height Fields. Proceedings of SIGGRAPH ’96, pp.106-118. Aug.1996.
6 HOPPE, H. View-Dependent Refinement of Progressive Meshes. Proceedings
of SIGGRAPH 97, pp.189-198.Aug.1997.
7 DUCHAINEAU, M. A. et al. ROAMing Terrain: Real-time Optimally
Adapting Meshes. IEEE Visualization ’97, pp.81-88. Nov. 1997.
8 DE BOER, W. H. Fast Rendering Using Geometrical MipMapping. E-mersion
Project, October 2000. Disponível em: <http://www.connectii.net/emersion>.
70
9 GÜDÜKBAY, U.; YILMAZ T. Stereoscopic View-Dependent Visualization
of Terrain Height Fields. IEEE Transactions on Visualization and Computer
Graphics, vol. 8, no. 4, October-December 2002.
10 EBERLY, D. 3D Game Engine Design: A Practical Approach to Real-
Time Computer Graphics, Morgan Kaufmann, San Francisco, 2001.
11 Treinamento e Ensino – Sistemas de Jogos Didáticos.
http://www.cgcfn.mar.mil.br/com_pessoal/secoes/secoesprincipais/cp_sjd.htm.
Acesso em: 06 ago. 2003.
12 WOO, M.; NEIDER, J.; DAVIS, T. OpenGL Programing Guide: The
Official Guide to Learning OpenGL, Version 1.1. Addison-Wesley Developers
Press, 1997.
13 Lua - The Programming Language. http://www.lua.org. Acesso em: 06
ago. 2003.
14 Puget Sound. http://www.cc.gatech.edu/projects/large_models/ps.html.
Acesso em: 06 ago. 2003.
15 MONTENEGRO, A. Investigação de Novos Critérios para Inserção de
Pontos em Métodos para Simplificação de Modelos de Terreno através de
Refinamento. Rio de Janeiro, 1997. Dissertação de Mestrado. Departamento de
Informática, PUC-Rio.
16 IM – Access Library to Bitmap Image Files. http://www.tecgraf.puc-
rio.br/im. Acesso em: 06 ago. 2003.
71
Apêndice A – Descrição da Aplicação SJD-Vis3D
O programa SJD-Vis3D[11], que está sendo desenvolvido pelo laboratório
Tecgraf (vinculado ao Departamento de Informática da PUC-Rio) para a Marinha
do Brasil, permite realizar vôos sobre um terreno. O algoritmo discutido neste
trabalho e, mais especificamente, o módulo Terreno apresentados no apêndice B
são utilizados para obter, a cada quadro, a malha do terreno sendo sobrevoado.
Além disso, o SJD-Vis3D é implementado em linguagem C++, utiliza a biblioteca
gráfica OpenGL[12] e arquivos de descrição feitos na linguagem de scripts
Lua[13].
No SJD-Vis3D a navegação através do terreno pode ser feita com o mouse
ou com as setas do teclado. Conforme pode ser visto na Figura 30, o SJD-Vis3D
imprime na tela algumas informações importantes. São elas: o número de quadros
gerados por segundo (fps, do inglês frames per second); o número de triângulos
desenhados; a velocidade da navegação transformada em quilômetros por hora; as
coordenadas x, y e z da câmera no espaço do objeto; o valor do erro tolerável; o
tamanho percentual do frustum de visão em relação à tela e, finalmente, se as
operações culling da malha fora da visão e geomorphing estão sendo utilizadas ou
não.
A tecla w permite alternar entre mostrar a malha em wireframe, ou seja, com
os polígonos sem preenchimento, e a malha tradicional com os polígonos
preenchidos. A tecla t permite alternar entre exibir a malha com ou sem textura. Já
as teclas 1, 2, 3 e 4 permitem, respectivamente, escolher entre: refinamento
combinado com culling e geomorphing; refinamento sem culling e com
geomorphing; refinamento sem culling e sem geomorphing e, finalmente,
refinamento com culling e sem geomorphing. As teclas 5 e 6 permitem alterar
(diminuindo e aumentando) o erro tolerável. Similarmente, as teclas 7 e 8
permitem alterar o frustum de visão. Além disso, as teclas a e z auxiliam na
navegação, permitindo subir ou descer a câmera em relação ao eixo z. A tecla p
permite congelar e descongelar a navegação e a tecla m permite liberar e vincular
os movimentos do mouse à navegação. A tecla x permite mostrar uma vista no
72
plano xy do terreno inteiro e retornar à vista anterior. A tecla r possibilita alternar
entre a exibição da malha de resolução máxima do terreno e retornar à malha
anterior. A tecla c faz o algoritmo de refinamento parar de ser chamado. Neste
caso, a malha de triângulos pára de ser atualizada, mas os movimentos da câmera
continuam liberados. O objetivo, neste caso, é permitir inspecionar a malha
gerada.
Figura 30 - Janela do SJD-Vis3D.
Conforme já dito, para obter a malha de triângulos aproximada que
representa o terreno, o SJD-Vis3D utiliza um módulo Terreno, desenvolvido em
paralelo a este trabalho e inspirado no algoritmo proposto por Lindstrom &
Pascucci em [2] e estendido em [3]. Na verdade, este módulo implementa os
algoritmos listados no capítulo 3. Além disso, a idéia é que ele possa ser utilizado
por várias aplicações que necessitem realizar um vôo ou passeio por um terreno
ou campo de alturas. Assim, o programa SJD-Vis3D ou qualquer outro programa que utilizar este
módulo fica responsável por implementar tarefas como: leitura dos dados do
terreno, ajuste da câmera, interface com o usuário, chamada às funções do módulo
Terreno preenchendo adequadamente os parâmetros de entrada e, finalmente,
renderização da malha produzida. A fase de renderização da malha foi deixada
para a aplicação, em vez de ser implementada no módulo Terreno, simplesmente
para dar à aplicação a liberdade de escolher como fazer a aplicação da textura. Em
73
outras palavras, o intuito foi deixar o módulo o mais genérico possível. O
apêndice B descreve este módulo em mais detalhes. Antes disso, porém,
apresentamos na próxima seção o formato dos terrenos lidos pelo programa SJD-
Vis3D.
A1. Definição dos Terrenos para o SJD-Vis3D
Esta seção descreve como devem ser definidos os terrenos que serão
utilizados pela aplicação SJD-Vis3D. Cada terreno é formado por um mapa de
alturas e uma textura, sendo que esta última não é obrigatória. A seguir
descrevemos o formato dos arquivos de definição do mapa de alturas e depois
explicamos os arquivos de textura.
A1.1. Mapa de Alturas
O mapa de alturas é definido por dois arquivos: um de cabeçalho com a
extensão .hdr e o outro com extensão .flt contendo os valores das alturas de cada
célula. O nome dos dois arquivos difere apenas pela extensão. O formato do mapa
de alturas é exatamente o formato binário com que o programa ARC/INFO
exporta suas grades a partir de um arquivo-imagem.
O arquivo de cabeçalho (.hdr) é um arquivo texto que descreve as
características da grade. O formato deste arquivo é o seguinte:
ncols <número de colunas da grade>
nrows <número de linhas da grade>
xllcorner <coordenada x do canto inferior esquerdo da grade>
yllcorner <coordenada y do canto inferior esquerdo da grade>
cellsize < tamanho de cada célula>
NODATA_value -9999
byteorder LSBFIRST
Os campos '<descrição>' devem ser substituídos pelo valor correspondente.
O campo 'NODATA_value' contém o valor que foi associado às células que na
verdade não possuem valor nenhum. Já o campo 'byteorder' é a ordem com que os
bytes que compõem os floats com o valor de cada altura estão seqüenciados. De
74
qualquer forma, estas duas linhas não são necessárias, uma vez que o SJD-Vis3D
sempre considera que os valores de 'NODATA_value' e 'byteorder' são -9999 e
LSBFIRST, respectivamente. No momento da execução, o SJD-Vis3D irá
considerar que as células sem valor possuem altura igual a zero.
O arquivo de dados (.flt) é um arquivo binário de floats (32 bits). Cada float,
por sua vez, correspondente à altura de cada célula da grade. O primeiro valor da
seqüência corresponde ao valor da célula localizada no canto superior esquerdo da
grade.
A.1.2 Textura
A textura é uma imagem em qualquer formato aceito pela biblioteca IM[16].
Entre eles podemos citar TIF, JPEG e BMP. Esta imagem pode ser
georeferenciada ou não. Caso ela não esteja georeferenciada, a aplicação SJD-
Vis3D considera que a imagem se encaixa perfeitamente em cima do terreno.
O georeferenciamento da imagem é feito através de um arquivo no formato
'ESRI worldfile', um arquivo-texto com o mesmo nome do arquivo de imagem,
mas com a extensão .tfw. O formato deste arquivo é o seguinte:
escala_x
rotação_x
rotação_y
escala_y
x0
y0
Os campos escala_x e escala_y são respectivamente as escalas horizontal e
vertical da imagem. Os campos x0 e y0 correspondem às coordenadas do centro
do pixel de um dos cantos da imagem. Normalmente este pixel é o canto superior
esquerdo da imagem e por isso a escala_y fica negativa. Os campos rotação_x e
rotação_y são respectivamente os ângulos de rotação em x e y da imagem, mas
atualmente a aplicação SJD-Vis3D desconsidera qualquer rotação da imagem. As
coordenadas reais do centro de cada pixel da imagem são então calculadas da
seguinte forma:
x = x0 + i * escala_x
75
y = y0 + j * escala_y
onde:
i é o número da coluna do pixel em questão
j é o número da linha do pixel em questão
Exemplo:
30.83721033166632
0.00000000000000
0.00000000000000
-30.83721033166632
698365.28008161834000
67343.43848742170700
No exemplo acima pode-se verificar que:
x0 = 698365.28008161834000
y0 = 67343.43848742170700
escala_x = 30.83721033166632
escala_y = -30.83721033166632
rotação_x = 0
rotação_y = 0
Apesar do SJD-Vis3D aceitar qualquer tamanho de imagem, ela só será
exibida na resolução máxima aceita pelo OpenGL, que depende da placa de vídeo.
Na maioria dos casos essa resolução máxima é de 1024x1024.
Apêndice B – Descrição do Módulo Terreno
Este módulo foi escrito em linguagem C e é composto por duas funções
externas, além de outras funções internas. Porém, é importante que os
programadores das aplicações que utilizem este módulo necessitem compreender
somente estas duas funções externas. Em outros termos, eles precisam saber
apenas em que posição dentro da aplicação tais funções devem ser chamadas,
quais os parâmetros devem ser passados e quais os parâmetros retornados por elas.
As duas funções externas são: TrnPreProcessamento e TrnGeraMalha. A
primeira deve ser chamada uma única vez, na fase de inicialização do programa
aplicação. Já a segunda, a função TrnGeraMalha, deve ser chamada toda vez que a
aplicação precisar desenhar um novo quadro (por exemplo, toda vez que a câmera
se mover). Os parâmetros que cada uma delas recebem e retornam estão descritos
detalhadamente no próprio arquivo-cabeçalho do módulo (arquivo terreno.h).
Esquematicamente, porém, isto é mostrado no diagrama da Figura 31.
Figura 31 - Diagrama de entradas e saídas das funções TrnPreprocessamento e
TrnGeraMalha.
A seguir apresentamos a declaração das principais estruturas de dados
utilizadas na interface do módulo Terreno descrito nesta seção.
TrnPreProcessamento
Vetor de vértices
x e y mínimo e máximo
Espaço entre amostras em x e y
Estrutura Terreno
TrnGeraMalha
Estrutura Terreno
Estrutura CameraTrn
Tolerância Mínima e Máxima
Estrutura MalhaTrn
77
/* Estrutura do vetor de pontos */ Estrutura Vetor de Vértices { float x; float y; float z; };
/* Estrutura dos dados de um terreno */ Estrutura Terreno { float xmin; /* valor mínimo da coordenada x */ float ymin; /* valor mínimo da coordenada y */ float deltax; /* espaço entre as amostras em x */ float deltay; /* espaço entre as amostras em y */ VerticeTrn **matrizTer; /* matriz de vértices do terreno */ int tamMatriz; /* tamanho da matriz de vértices do terreno */ }; /* Estrutura que guarda os parâmetros da câmera necessários */ Estrutura CameraTrn {
float ox, oy, oz; /* Coordenadas do olho do observador (no espaço do objeto) */ float largJanela; /* largura da janela em pixels */ float fovx; /* abertura horizontal da câmera */ /* Componentes das equações dos 6 planos do frustum de visão */ float d1, d2, d3, d4, d5, d6; float n1x, n1y, n1z; /* Normal unitária do plano 1 */ float n2x, n2y, n2z; /* Normal unitária do plano 2 */ float n3x, n3y, n3z; /* Normal unitária do plano 3 */ float n4x, n4y, n4z; /* Normal unitária do plano 4 */ float n5x, n5y, n5z; /* Normal unitária do plano 5 */ float n6x, n6y, n6z; /* Normal unitária do plano 6 */ }; /* Estrutura da malha de saída retornada pelo algoritmo */ Estrutura MalhaTrn { float *Vx; /* vetor que armazena as coordenadas x dos vértices que deverão ser desenhados */ float *Vy; /* vetor que armazena as coordenadas y dos vértices que deverão ser desenhados */ float *Vz; /* vetor de alturas */ int tamV; /* quantidade de vértices presentes na malha final */ };
Assim, o parâmetro Vetor de Vértices é, na verdade, um vetor de uma
estrutura composta pelas coordenadas x, y e z de cada vértice ou amostra do
terreno. Os parâmetros referentes aos valores mínimos e máximos de x e y,
respectivamente, e ao espaço entre amostras também nas direções x e y,
respectivamente, devem ser calculados previamente pela aplicação e informados
como entrada para a função TrnPreProcessamento. A partir daí, esta função
78
retornará o parâmetro Estrutura Terreno devidamente preenchido e pronto para ser
passado como parâmetro de entrada para a função TrnGeraMalha. O programador
da aplicação deve lembrar, porém, que é necessário declarar uma variável do tipo
da Estrutura Terreno e alocar uma área de memória para ela, antes de chamar a
função TrnPreProcessamento.
Além disso, antes de chamar a função TrnGeraMalha, o programador da
aplicação que utilizará este módulo deve criar, ainda, uma variável do tipo da
estrutura CameraTrn e preencher os seus campos adequadamente. Os parâmetros
Tolerância Mínima e Tolerância Máxima, porém, são do tipo real e dizem respeito
à faixa de erro para a aproximação da malha gerada. Assim, erros inferiores à
Tolerância Mínima serão aceitos e erros que caem na faixa de tolerância serão
considerados para o geomorphing, conforme já explicado. Finalmente, o
programador deve criar e alocar uma área de memória para a estrutura MalhaTrn.
É nesta estrutura que serão recebidas as coordenadas a serem renderizadas. No
caso de estar utilizando o OpenGL, por exemplo, a renderização basicamente será
um comando glBegin (GL_TRIANGLE_STRIP), seguido por um laço com
chamadas internas glVertex (com as coordenadas recebidas na estrutura MalhaTrn
como parâmetro) e, por fim, o comando glEnd(). O número de iterações deste laço
será igual ao número de vértices armazenado na estrutura e também é recebido
como parâmetro dentro da estrutura MalhaTrn. Dependendo da escolha feita pela
aplicação para a implementação da etapa de aplicação da textura no terreno, o
procedimento de renderização, descrito acima, pode ser ligeiramente modificado.