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.