Departamento de Informática
COMPUTAÇÃO GRÁFICA COM WEBGL
Aluno: Ian Albuquerque Raymundo da Silva
Orientador: Hélio Côrtes Vieira Lopes
Introdução:
WebGL é uma API (Application Program Interface - do inglês, Interface de
Programação de Aplicativos) em JavaScript para a renderização de um contexto 3D para a
web [1]. Possui as mesmas funcionalidades do OpenGL ES 2.0 por ser derivada deste, porém
aplicadas num contexto HTML. A utilização dessa nova tecnologia foi possível recentemente
junto com o lançamento do elemento canvas do padrão HTML 5, em 2014, e possui a
proposta de possibilitar à plataforma web o desenvolvimento de aplicações que utilizem
computação gráfica, somente com o uso de navegadores. Isso aumenta a portabilidade dos
softwares desenvolvidos, uma vez que o mesmo código que funciona em um laptop, por
exemplo, funcione em um smartphone com os recursos necessários.
Objetivos:
O principal objetivo foi estudar as possibilidades tecnológicas que o WebGL oferece
como extensão natural da computação gráfica para a plataforma web. Objetivou-se reproduzir
em WebGL resultados já conhecidos em OpenGL adicionando-se os diversos recursos
fornecidos pelos elementos característicos dessa plataforma às aplicações. O principal
resultado esperado foi o desenvolvimento de um ambiente de visualização 3D e a
implementação do algoritmo Marching Cubes [2] para a renderização de isosuperfícies.
A escolha do algoritmo Marching Cubes se deu devido à sua enorme aplicação em
diversas áreas da computação gráfica, entre elas o mapeamento, visualização e identificação
de dados obtidos de tomografias ou de relevos. Uma vez desenvolvido esse algoritmo, é
possível proceder para a criação de aplicações com impacto significativo.
Também foi objetivo do estudo a elaboração de uma documentação atualizada
contendo os principais elementos e módulos desenvolvidos, de modo a facilitar futuros reusos
de código.
Metodologia:
Através da utilização dos modelos de ambientes tridimensionais básicos em OpenGL
apresentados no curso de Elementos Matemáticos da Computação Gráfica da PUC-Rio [3],
buscou-se o desenvolvimento de uma biblioteca própria com sintaxe e uso próximo ao do
GLUT (OpenGL Utility Toolkit) [4] para a flexibilização e facilitação da criação de aplicações
web com a funcionalidade do WebGL. Com a utilização de módulos facilitadores, como o
require.js [5], as funcionalidades desejadas foram subdivididas em módulos que formaram um
componente maior denominado Canvas WebGL Utility.
Para cada módulo foi distribuída uma função diferente dentro do ambiente de
visualização, sendo as principais funções o processamento matricial das transformações
matemáticas realizadas, o gerenciamento de eventos da aplicação, o processamento de
shaders, além da renderização dos objetos em cena tanto num contexto bidimensional quanto
tridimensional.
Departamento de Informática
Como primeira forma de averiguar o funcionamento e funcionalidade do Canvas
WebGL Utility desenvolveu-se uma aplicação para a renderização de funções reais e de curvas
de níveis no plano através do uso do algoritmo Marching Squares. Uma vez alcançado esse
resultado, expandiu-se a aplicação para atingir-se o resultado principal de renderizar-se
isosuperfícies num espaço tridimensional através do algoritmo Marching Cubes.
Neste processo, diversas dificuldades foram encontradas, dentre elas a definição dos
módulos do projeto buscando-se seguir padrões de desenvolvimento de software, a integração
do módulo require.js com os elementos introduzidos pela WebGL e a adaptação dos padrões
de computação gráfica em C++ e OpenGL para JavaScript e WebGL.
O Canvas WebGL Utility:
O Canvas WebGL Utility possui como finalidade gerar funções e procedimentos que
permitam a criação rápida e de forma prática de ambientes bidimensionais e tridimensionais
utilizando a funcionalidade do elemento canvas do HTML5. O Canvas WebGL Utility é
subdividido em diversos módulos que devem ser chamados de acordo com suas funções.
Figura 1: Inicialização do elemento Canvas WebGL Utility
Para inicializar uma instância do Canvas WebGL Utiity basta associá-lo a um
elemento canvas de alguma página HTML. Essa biblioteca possui um funcionamento
orientado a eventos. Dessa forma, sempre que um evento pertinente ocorre, a função
designada pelo usuário para ser chamada naquela circunstância é chamada. Deve-se, portanto,
atribuir para cada um evento uma função correspondente.
Figura 2: Designação das funções a serem chamadas.
Na função de display, que é chamada sempre que uma nova cena deve ser desenhada,
pode-se utilizar ferramentas de desenho de imagens, assim como chamar funções matriciais
que alteram a cena. Existem duas principais matrizes responsáveis por alterar a visualização
da cena: a matriz de projeção, responsável por aplicar a transformação linear referente à
visualização em perspectiva tridimensional, por exemplo, e a matriz de model view.
Departamento de Informática
Figura 3: Exemplo de função de display.
Para desenhar objetos na tela escolhe-se uma cor de desenho e em seguida começa-se
um desenho com uma primitiva, como LINE_LOOP, no exemplo abaixo. Após a primitiva,
define-se diversos pontos no espaço, sequencialmente, que serão desenhados de forma
diferente, conforme a primitiva escolhida. Por exemplo, a primitiva LINE_LOOP resulta na
criação de uma linha contínua, formada por diversos segmentos de retas, definidos pelos
vértices dados.
Figura 4: Exemplo do desenho e uma esfera composta por círculos.
A função loop é chamada periodicamente, em intervalos de tempo pequenos. Ela
recebe como parâmetro o intervalo de tempo entre sua última chamada, que é útil para que a
aplicação possua o mesmo comportamento, independente das capacidades de hardware do
sistema em que o software está sendo rodado. Um exemplo de utilização da função loop é a
realização de animações das cenas desenhadas.
Departamento de Informática
Também é possível estabelecer a interatividade com o mouse, que é muito útil por
exemplo para a interação do usuário da aplicação com a cena. Sempre que o mouse for
movido, a função mouse_move é chamada. Já quando um botão do mouse é pressionado ou
solto, as funções mouse_down e mouse_up são chamadas. Esta últimas recebem como
parâmetro o botão que foi pressionado no mouse. Já todas elas possuem como parâmetro as
coordenadas horizontal e vertical do mouse em relação a tela, convertidos em uma escala de
zero a um.
Figura 5: Exemplo de funções de controle de mouse.
Como resultado do código de exemplo acima, temos a visualização de uma cena
tridimensional em perspectiva, composto por um cubo e uma esfera.
Departamento de Informática
Figura 6: Resultado dos códigos de exemplo a cima.
O Algoritmo Marching Squares:
O algoritmo Marching Squares possui como objetivo desenhar numa região
bidimensional uma aproximação de uma curva, dado sua equação implícita.
Seja 𝑆 = [π‘Ž, 𝑏] × [𝑐, 𝑑] βŠ‚ ℝ2 , a região do plano em que se deseja visualizar a
aproximação de uma dada curva 𝐢
Seja 𝑝(π‘₯, 𝑦) = 0 a equação implícita da curva 𝐢, aonde 𝑝: 𝑆 β†’ ℝ. A curva 𝐢 é a curva
de nível zero da função 𝑝.
Sejam 𝑛, π‘š ∈ β„•, o número de divisões em que deseja-se particionar a região S.
π‘βˆ’π‘Ž
Definimos π‘₯𝑖 = (
𝑛
) 𝑖 + π‘Ž e 𝑦𝑗 = (
π‘‘βˆ’π‘
π‘š
) 𝑗 + 𝑐.
Dessa forma, dividimos 𝑆 em diversas regiões retangulares da forma [π‘₯𝑖 , π‘₯𝑖+1 ] ×
[𝑦𝑗 , 𝑦𝑗+1 ], aonde 𝑖 = 0,1,2,3 … (𝑛 βˆ’ 1) 𝑒 𝑗 = 0,1,2,3 … (π‘š βˆ’ 1).
Dado 𝑖 ∈ [0, 𝑛 βˆ’ 1] , sejam 𝑣1 = (π‘₯𝑖 , 𝑦𝑗+1 ), 𝑣2 = (π‘₯𝑖+1 , 𝑦𝑗+1 ), 𝑣3 = (π‘₯𝑖 , 𝑦𝑗 ) 𝑒 𝑣4 =
(π‘₯𝑖+1 , 𝑦𝑖 ), os vértices de cada divisão retangular.
Figura 7: Esquematização dos vértices em cada uma das divisões.
Para cada aresta, podemos aproximar o ponto em que a igualdade 𝑝(π‘₯, 𝑦) = 0 é
satisfeita utilizando-se os valores de 𝑝(𝑣𝑖 ) π‘π‘Žπ‘Ÿπ‘Ž 𝑖 = 1,2,3 𝑒 4. Caso, em uma aresta definida
pelos vértices 𝑣 e 𝑀, tenhamos 𝑝(𝑣)𝑝(𝑀) < 0 (isto é, os sinais de 𝑝(𝑣) e 𝑝(𝑀) são opostos) e
supormos a função 𝑝 contínua, é possível garantir que existe um ponto z em que a curva 𝐢
atravessa a aresta sendo analisada. Podemos então aproximar esse ponto com um custo
computacional baixo através de uma aproximação linear. Assim, temos:
|𝑝(𝑀)|
𝑧 = (𝑣 βˆ’ 𝑀) (
)+𝑀
|𝑝(𝑣) βˆ’ 𝑝(𝑀)|
Departamento de Informática
(π‘Žπ‘œπ‘›π‘‘π‘’ 𝑣 𝑒 𝑀 𝑠ãπ‘œ π‘œπ‘  π‘‘π‘œπ‘–π‘  𝑣éπ‘Ÿπ‘‘π‘–π‘π‘’π‘  π‘žπ‘’π‘’ π‘‘π‘’π‘“π‘–π‘›π‘’π‘š π‘Ž π‘Žπ‘Ÿπ‘’π‘ π‘‘π‘Ž π‘ π‘’π‘›π‘‘π‘œ π‘π‘œπ‘›π‘ π‘–π‘‘π‘’π‘Ÿπ‘Žπ‘Ÿπ‘Žπ‘‘π‘Ž)
Para cada uma das configurações de sinais de vértices, deve-se traçar segmentos de
retas de modo a obter-se a aproximação da curva desejada. Todas as combinações dos sinais
dos vértices de cada divisão podem ser separadas em quatro casos. Os demais casos não
explicitados abaixo são uma inversão de sinais ou alguma rotação da região sendo observada.
Figura 8: Casos possíveis dos sinais dos vértices das divisões.
O caso quatro é considerado ambíguo, uma vez que não é possível decidir-se ao certo
quais das configurações abaixo a curva irá possuir. Existem várias formas de se contornar a
ambiguidade. A mais simples delas é simplesmente escolher arbitrariamente uma das
configurações abaixo. Outra consiste em subdividir a região sendo analisada em novas subregiões e utilizar o algoritmo Marching Cubes novamente, sendo esta opção muitas vezes
mais complexa computacionalmente.
Figura 9: Ambiguidade presente no quarto caso.
O algoritmo consiste na iteração em cada umas divisões [π‘₯𝑖 , π‘₯𝑖+1 ] × [𝑦𝑗 , 𝑦𝑗+1 ], aonde
𝑖 = 0,1,2,3 … (𝑛 βˆ’ 1) 𝑒 𝑗 = 0,1,2,3 … (π‘š βˆ’ 1). Em cada divisão determina-se os valores da
função nos pontos e traça-se sua aproximação para aquele pequeno domínio. Como resultado,
têm-se uma aproximação da curva em S.
Versões mais refinadas do algoritmo obtêm os pontos π‘₯𝑖 e 𝑦𝑗 de uma forma não
distribuída uniformemente. Nessas versões, analisa-se a sinuosidade da curva e procura-se
aumentar o número de divisões de S nas regiões com mais sinuosidade.
O Algoritmo Marching Cubes:
O algoritmo Marching Cubes possui um funcionamento muito parecido com o
algoritmo Marching Squares, sendo este sua versão em três dimensões. Ao invés de
subdividir uma região 𝑆 = [π‘Ž, 𝑏] × [𝑐, 𝑑] βŠ‚ ℝ2 , subdivide-se uma região 𝐺 = [π‘Ž, 𝑏] ×
[𝑐, 𝑑] × [𝑒, 𝑓] βŠ‚ ℝ3 e analisa-se essas divisões sobre os valores de uma função 𝑓: 𝐺 β†’ ℝ
aonde a equação implícita da superfície é dada por 𝑓(π‘₯, 𝑦, 𝑧) = 0. Dessa forma, a superfície
que deseja-se uma aproximação é uma superfície de nível de 𝑓.
Departamento de Informática
Devido ao maior número de vértices em cada divisão realizada, a quantidade de casos
diferentes de combinações de sinais é maior do que o número de casos do Marching Cubes.
Também existem mais casos em que existem ambiguidades.
No caso do Marching Cubes, devido ao número grande de casos, é vantajoso a
implementação de um array que armazene cada um dos casos para cada uma combinação de
sinais nos vértices de cada divisão. Como cada divisão possui oito vértices, é possível definir
uma máscara de bits aonde cada bit representa o sinal de cada vértice de uma divisão. Assim,
com apenas um byte de informação, é possível armazenar as permutações de sinais possíveis.
Por exemplo, o byte 0000 0000 representa uma divisão em que todos os vértices possuem
valor de 𝑓 negativo. Já o byte 1000 0010 representa uma divisão em que somente os vértices
um e sete possuem valores de 𝑓 positivos.
Conclusões:
Ao alcançar a visualização de isosuperfícies através do algoritmo Marching Cubes
com o uso do componente Canvas WebGL Utility foi possível atingir-se o objetivo de
averiguar a capacidade do WebGL na plataforma web através do desenvolvimento de uma
aplicação em módulos. Com esses resultados é possível desenvolver-se diversas aplicações de
computação gráficas em diversas áreas de atuação que possam ter benefícios maiores por
utilizarem a plataforma portátil da web.
Apesar de o objetivo ter sido alcançado, não é possível garantir a ausência de falhas
ainda não detectadas no projeto desenvolvido devido à própria natureza do desenvolvimento
de software. Contudo, devido à documentação desenvolvida junto com o projeto e à sua
modularização, o processo de depuração de erros é facilitado, permitindo a continuação de seu
desenvolvimento no futuro.
Referências:
1 – KHRONOS WEBGL WORKING GROUP. WebGL Specification. Version 1.0.3, 27
October 2014. Disponível em: <https://www.khronos.org/registry/webgl/specs/1.0/#8>.
Acesso em: 30 jun. 2015.
2 – CLINE Harvey E, LORENSEN William E. Marching Cubes: A High Resolution 3D
Surface Construction Algorithm. Computer Graphics, Volume 21, Number 4, July 1987.
Disponível em: <https://www.cs.virginia.edu/johntran/GLunch/marchingcubes.pdf>. Acesso
em: 30 jun. 2015.
3 – PESCO Sinésio, LOPES Hélio C. V., UESU Dirce, SANTOS Geovan T. dos.
Fundamentos da Matemática para Computação Gráfica. Disponível em:
<http://www.mat.puc-rio.br/~sinesio/Apostila_C++.pdf> Acesso em: 30 jun. 2015.
4 – KHRONOS WEBGL WORKING GROUP. GLUT – The OpenGL Utility Toolkit.
Disponível em: <https://www.opengl.org/resources/libraries/glut/glut-3.spec.pdf>. Acesso
em: 30 jun. 2015.
5 – CHUNG, Andy. Require.js – A JavaScript Module Loader. 2011-2015. Disponível em
<http://requirejs.org/>. Acesso em: 30 jun. 2015.
Download

Ian Albuquerque Raymundo da Silva