Adaptación de Algoritmos Geométricos al uso de GPU

Anuncio
Adaptación de Algoritmos Geométricos al uso de GPU
Programable
Rafael J. Segura, José Mª Noguera, Carlos Ogáyar, Antonio J. Rueda, Francisco Feito
Depto. de Informática, Universidad de Jaén, España
{rsegura, jnoguera, cogayar, ajrueda, ffeito}@ujaen.es
Resumen
En este artículo se presentan los objetivos iniciales y resultados
obtenidos en el proyecto de excelencia de la Junta de Andalucía
titulado "Adaptación de Algoritmos Geométricos al uso de
Hardware gráfico programable. Aplicaciones". Se muestran en
primer lugar los objetivos del proyecto, los principales
resultados obtenidos centrados en la resolución de algoritmos
geométricos, tanto en el uso de Shaders como en el uso de
CUDA, y los trabajos futuros, que se centran fundamentalmente
en la aplicación de algunos de los algoritmos.
1. Introducción y objetivos.
La rápida evolución que se está produciendo en el
hardware gráfico está permitiendo en los últimos años un
salto cuantitativo y cualitativo en el rendimiento de las
aplicaciones gráficas. De una parte, la inclusión de
procesadores gráficos cada vez más potentes y capaces de
realizar operaciones específicas utilizadas en Informática
Gráfica permite la optimización de muchos de los
métodos empleados. De otra parte, la posibilidad del
desarrollador de añadir programas en el proceso de
rendering añade la posibilidad de realizar de una manera
mucho más rápida algoritmos que han de procesarse para
los modelos gráficos [1].
Muchos autores han percibido la presencia de las GPUs
(Graphics Processing Unit) en los equipos actuales como
una posibilidad para resolver problemas de tipo genérico,
o simplemente para paralelizar algunos procesos
utilizando de manera conjunta la CPU y la GPU [2]. La
GPU presenta mayor capacidad para realizar cálculos en
coma flotante que la CPU, si bien para que un algoritmo
pueda adaptarse a la GPU debe ser paralelizable. Las
GPUs actuales permiten modificar el pipeline de
visualización a través de vertex, geometry y fragment
shaders sobre datos geométricos, pudiendo utilizarse los
shaders como programas de cálculo de propósito general
que serán utilizados en paralelo. Adicionalmente, las
nuevas arquitecturas propuestas para el hardware gráfico
[3,4] están encaminadas hacia el procesamiento masivo de
datos mediante el uso de la GPU, permitiendo el aumento
de la capacidad de procesos de ordenadores de sobremesa
a un escaso coste adicional.
Todo lo anterior dio lugar a que un grupo de
investigadores del Grupo de Investigación TIC-144
“Geomática e Informática Gráfica” de la Universidad de
Jaén solicitaran financiación a través de la Convocatoria
de Proyectos de Excelencia de la Junta de Andalucía para
el año 2006 para la realización del proyecto “Adaptación
de Algoritmos Geométricos al uso de Hardware gráfico
programable. Aplicaciones (P06-TIC-01403)”. El
proyecto fue seleccionado para su ejecución mediante
resolución de 7 de marzo de 2007 y dotado con una
financiación a tres años de 157.336,30 €.
El proyecto se centra la adaptación de algoritmos básicos
en Informática Gráfica y Geometría Computacional hacia
el uso de Hardware Gráfico Programable. Los objetivos
fundamentales del proyecto se han centrado en el
aprovechamiento de las potencialidades de la GPU desde
una doble perspectiva:
ƒ
Realización de un estudio sobre el aprovechamiento
de las potencialidades de la GPU para la resolución
de problemas geométricos. Este estudio debe partir
de la propuesta de un sistema formal de
representación y especificación de soluciones que
tenga en cuenta el procesamiento vectorial de la
GPU.
ƒ
Aplicación de algoritmos basados en GPU hacia su
integración en Sistemas de Información Geográfica.
El interés de este tipo de sistemas hoy en día es
muy alto, siendo de aplicación en múltiples
ámbitos, tanto en el sector público como en el
privado.
Alrededor de estos dos objetivos principales del proyecto
pueden formularse una serie de objetivos que pasamos a
enumerar a continuación:
ƒ
Construcción de una plataforma software que
incluya el tratamiento de modelos tridimensionales
mediante el uso del hardware gráfico programable.
ƒ
Construcción de software para el tratamiento de
modelos tridimensionales en dispositivos móviles
(ordenadores de mano y teléfonos móviles),
teniendo en cuenta las restricciones de los mismos.
ƒ
Integración de algoritmos basados en el uso de la
GPU en Sistemas de Información Geográfica.
Problemas como el cálculo de superficies, la
determinación de inclusión, el conteo de unidades,
etc. son problemas básicos en este tipo de sistemas
existiendo buenas soluciones, aunque algunas de
ellas siguen siendo costosas en términos
computacionales. El objetivo se centra pues en la
búsqueda de alternativas a estas soluciones que
utilicen las capacidades de la GPU para reducir el
coste.
ƒ
Aplicación de los algoritmos hacia sistemas de
navegación. Este tipo de sistemas se ha
popularizado en los últimos años gracias al
abaratamiento de los costes de los receptores de
GPS, así como a la disponibilidad de cartografía
adecuada. Sin embargo, en la mayoría de los casos
la información mostrada es escasa e inexacta, ya
que se trata de información 2D o, en el mejor de los
casos, un falso 3D. El objetivo que se plantea en
este proyecto consiste en la búsqueda de algoritmos
y métodos que permitan una visualización 3D del
terreno en dispositivos móviles asegurando un
tiempo de respuesta apropiado.
2. Uso de shaders para la resolución de
algoritmos geométricos.
En esta sección vamos a describir muy brevemente
algunas de las soluciones propuestas para la resolución de
algunos algoritmos geométricos mediante el uso de la
GPU.
2.1. Inclusión de puntos.
Uno de los tests más importantes que surgen dentro del
campo de la Geometría Computacional y la Informática
Gráfica es la inclusión de un punto del espacio dentro de
un sólido. En [5], Ogáyar et. al. realizan una profunda
revisión sobre las posibles soluciones de este problema
básico, centradas todas ellas en el uso de soluciones en
CPU. Dentro del ámbito del proyecto se han propuesto
diferentes soluciones para resolver el problema mediante
el hardware gráfico, todas ellas basadas en el algoritmo
descrito en [6] y que aparece en el Algoritmo 1.
Como datos de entrada del problema tomaremos un sólido
definido por su frontera, y un punto. Para optimizar los
resultados y dado que el hardware gráfico está diseñado
especialmente para el tratamiento de triángulos, en el caso
de que la frontera del sólido contenga polígonos de más
de tres lados se procederá a un recubrimiento de dichos
polígonos mediante triángulos tal y como se expone en
[5]. A partir de estos datos de entrada, se han propuesto
diferentes soluciones que podemos clasificar en dos
categorías:
ƒ
ƒ
de ping-pong. Así, en la primera pasada se estudia la
inclusión del punto en cada uno de los tetraedros. En una
segunda pasada se aplica la técnica de reducción para
obtener un único valor resultado. Los casos degenerados
son detectados enviando los puntos que los ocasionan a
una posición específica del frame-buffer, que es
consultada al final del proceso.
Datos
inclusión
0
... T4 T3 T2 T1
Datos de tetraedros
(display list, vertex array, etc.)
Vertex
Program
0
1 0.1
1 0.2 0
1
0
1
0
0
1
0
0 0.3
Estados de inclusión
(framebuffer)
Figura 1. Esquema general de la solución básica out-of-core
para el problema de inclusión de puntos.
La aparición de Shader Model 4 y la arquitectura de la
serie 8 de Nvidia, permiten optimizar la solución inicial
mediante el uso de geometry shaders. En este caso no es
necesario realizar ningún tipo de codificación de la
información, pudiendo enviarse directamente la malla de
triángulos utilizando alguna primitiva indexada. El
resultado es nuevamente almacenado en el frame-buffer, y
en una segunda pasada se realiza la reducción de los
resultados obtenidos.
En el segundo conjunto de soluciones, se realiza una
codificación de la malla de triángulos en textura,
construyendo un tetra-tree [7]. Dicha estructura espacial
permite dividir el espacio mediante tetraedros,
clasificando en cada nodo los triángulos de la malla cuyos
tetraedros del recubrimiento pasan por esa zona del
espacio. Ello permite una consulta rápida sobre un
reducido conjunto de triángulos. En este caso, no es
necesario iterar
sobre los puntos, sino sobre los
triángulos de la malla, permitiendo resolver el problema,
a un mínimo coste adicional, sobre un mayor número de
puntos, lo que es especialmente útil en problemas de
detección de colisión y en operaciones booleanas entre
sólidos.
Soluciones out-of-core.
Soluciones in-core.
En el primer tipo de soluciones, los vértices y triángulos
del sólido están almacenados en la CPU y son enviados al
hardware a través de algunas de las estructuras de datos
disponibles (display lists, vertex arrays, …). Con el fin de
optimizar el uso del ancho de banda del bus que une el
sistema gráfico con el resto del sistema, dichas estructuras
se completan al máximo disponible, de manera que se ha
mostrado experimentalmente que para sólidos con hasta
200000 triángulos el comportamiento de la solución es
aceptable. En la primera de las soluciones, los vértices de
los tetraedros se codifican en algunos de los atributos de
los vértices, y se envían vértices con una posición
específica, con el fin de identificar los tetraedros (figura
1). El algoritmo funciona utilizando la conocida técnica
Figura 2. Esquema general de la solución básica in-core para
el problema de inclusión de puntos
Se han diseñado diferentes soluciones para la resolución
del problema de inclusión de nubes de partículas en
sólidos, si bien, el esquema básico aparece en la Figura 2.
La codificación del Tetra-tree del sólido se almacena
utilizando una estructura similar a la de una tabla hash en
una o varias texturas, para permitir el desbordamiento que
pueda surgir en aquellas zonas del sólido con una alta
densidad de triángulos. A partir de ese esquema básico
pueden configurarse diferentes soluciones de manera que
las tareas realizadas por la GPU se realicen
completamente en el Fragment Shader, en Vertex Shader
y Fragment Shader, en CPU+Fragment Shader, en
Fragment Shader + Fragment Shader, o bien utilizando
Geometry Shader + Fragment Shader. En cualquier caso,
el esquema de las soluciones es similar. En una primera
etapa se determina el tetra-cono en el que se encuentra
cada partícula. En la siguiente etapa del pipeline, se
consulta en el Tetra-tree la lista de tetraedros que se
encuentran en dicho tetra-cono y se determina la inclusión
de la partícula en dichos tetraedros.
En la Tabla 1 se muestran algunos resultados obtenidos
con los algoritmos propuestos, tanto en soluciones out-ofcore como soluciones in-core.
renderiza a una loncha de la textura 3D correspondiente.
Al final del proceso, se recupera la textura 3D.
Figura 3. Esquema general del algoritmo de voxelización.
El principal inconveniente de esta solución es que se
aprovechan poco las capacidades gráficas. Podemos
optimizar el resultado provocando que el cálculo de las
secciones de cada triángulo se calculo en la GPU. Para
ello hay que tener en cuenta que, dependiendo de la
posición de los vértices del recubrimiento respecto al
punto de referencia considerado a la hora de construir el
recubrimiento, pueden producirse situaciones en las que
la intersección del tetraedro con la loncha correspondiente
genere un cuadrilátero (figura 4). Por tanto, es necesario
generar para cada triángulo de la malla dos triángulos que
serán rasterizados o no en función de la loncha en la que
nos encontremos.
Tabla 1. Tiempos de algoritmos de inclusión para 1000 puntos.
2.2. Voxelización.
La representación basada en vóxeles tiene una gran
importancia en aplicaciones tales como visualizaciones
médicas o para visualizar objetos que difícilmente se
pueden representar a partir de sus fronteras, tales como
humo o fuego. Además los vóxeles son entidades
tridimensionales que pueden almacenar información
volumétrica, al contrario que las representaciones basadas
en fronteras (tales como mallas) que tan solo describen la
supercie de los objetos. Las representaciones basadas en
vóxeles ofrecen información de cómo se dispone la
materia en el espacio.
El recubrimiento de sólidos mediante símplices
proporciona un método prácticamente inmediato para
obtener la descomposición espacial del sólido mediante
vóxeles. Para ello basta con resolver la voxelización de
cada uno de los tetraedros del recubrimiento (algoritmo 2)
y posteriormente componer la solución final mediante la
unión de las soluciones parciales (Figura 3). Dentro del
proyecto se han diseñado diferentes soluciones que hace
uso de las nuevas capacidades gráficas para obtener
soluciones mejoradas de este problema.
La primera solución hace uso intensivo de operaciones
gráficas aceleradas. Para ello, en lugar de iterar sobre la
voxelización de cada uno de los tetraedros, se calcula en
CPU la intersección de cada loncha de la voxelización
con todos y cada uno de los tetraedros del recubrimiento.
A continuación, se dibujan los triángulos obtenidos y se
Figura 4. Casos posibles en la rasterización del tetraedro.
A los triángulos generados (dos por cada tetraedro), se les
asocian como parámetros varying los vértices del
tetraedro al que pertenecen. Además, se envía como
parámetro uniforme la altura de la loncha que se desea
generar. Para cada loncha ys el Vertex Shader se encarga
de ordenar los vértices según su coordenada y, y de
calcular la proyección de cada uno los triángulos en el
plano y=ys. Aquellos tetraedros cuyas coordenadas ymax e
ymin quedan fuera de la loncha ys se descartan, enviando
sus coordenadas fuera del volumen de vista, con el fin de
que en la siguiente etapa del proceso de visualización
sean descartados por el hardware gráfico. En el Fragment
Shader pueden codificarse las diferentes funciones de
aspecto que se deseen (figura 5.a)
Nuevamente la aparición de Shader Model 4 permite
simplificar el proceso anteriormente descrito. En este
caso, podemos hacer uso de las nuevas funcionalidades
como la instanciación de geometría y los geometry
shaders[9]. En esta implementación, tan solo se envían al
cauce gráfico dos triángulos por loncha. La GPU se
encarga de generar tantas copias de los triángulos como
sean necesarias (nuevamente dos triángulos por
tetraedro). En las coordenadas de cada vértice se indican
un índice del punto (0-3) y un identificador del triángulo
al que pertenece el punto (0-1). Este esquema se muestra
en la figura 5.b. Nótese que todos los triángulos
instanciados son iguales, por lo que no es posible pasar
los tetraedros como parámetro de los vértices. En lugar de
ello, se genera una textura 2D de flotantes que contiene
todos los vértices de los tetraedros. Esta textura almacena
consecutivamente los vértices ABCD de cada uno de los
tetraedros del objeto a voxelizar, apareciendo ordenados
en cada tetraedro por su coordenada y. La textura es
enviada una única vez a la GPU, en donde se almacena y
es reutiliza para el procesado de cada loncha. De esta
forma, tan solo se ha de enviar la geometría a la GPU una
vez, y no sucesivas veces por cada loncha. Una vez
enviada la textura a la GPU puede liberarse su espacio de
la memoria principal. Además, de esta manera es posible
obtener nuevas voxelizaciones del sólido, o
voxelizaciones parciales del mismo con diferente
resolución, sin necesidad de volcar nuevamente la
información.
Gracias al procesador de geometría, los cálculos de
interpolación que antes se hacían por vértice, ahora
pueden optimizarse a nivel de primitiva. Esto permite que
si el tetraedro no corta la loncha actual, puedan
descartarse completamente los dos triángulos sin
necesidad de enviar sus seis vértices fuera del volumen de
vista. Tan solo se genera aquella geometría que es
estrictamente necesaria, evitando cálculos innecesarios en
etapas posteriores.
Figura 6. Voxelizaciones obtenidas con el algoritmo descrito en
la sección 2.2.
Un programa de vértices recibe los puntos instanciados,
así como el identificador de instancia gl_InstanceID para
cada uno. Empleando este identificador como índice
dentro de la textura, se extraen los vértices ABCD
correspondientes y los usamos para desplazar el punto a
su posición correcta.
Tabla 2. Tiempo de voxelización de las implementaciones GPU
del algoritmo propuestas en la figura 5.
2.3. Dibujado de polígonos curvos.
Figura 5. Diferentes configuraciones para la voxelización de
sólidos mediante la GPU.
Sin embargo, podemos simplificar aún más el proceso
anterior utilizando el procesador de geometría (figura
5.c). En esta implementación, en cada loncha tan solo es
necesario enviar a la GPU el tamaño de la textura, el valor
ys y un único vértice. Las coordenadas del vértice son
intrascendentes. Dicho vértice se envía al hardware,
indicando que se instancie una vez por cada tetraedro.
Esto provoca una ejecución del procesador de geometría
por cada tetraedro. Nótese que tan solo se puede acceder a
la variable gl InstanceID desde el procesador de vértices,
por lo que necesitamos ejecutar un pequeño programa de
vértices que copie ese valor a una de las coordenadas del
vértice. El programa de geometría toma como entrada un
vértice, y genera como salidas:
ƒ
ƒ
ƒ
Dos triángulos, si By>ys>Cy.
Un triángulo si Ay >ys> By o Cy> ys> Dy.
Nada, en otro caso.
Existen multitud de de trabajos centrados en el dibujado
de curvas, ya sean curvas implícitas o curvas
paramétricas. Sin embargo existen pocas soluciones que
resuelvan el problema mediante el uso de hardware
gráfico lo que restringe su uso en aplicaciones en tiempo
real. A partir del modelo basado en cadenas simpliciales
extendidas [10], se ha propuesto un método que permite
el dibujado de polígonos definidos por curvas de Bezier
de grado 3 en GPU [11]. Este método presenta varias
ventajas frente a otras soluciones similares existentes: su
implementación es sencilla, no requiere la triangulación
previa del polígono y puede ser implementado
íntegramente en GPU (no solamente la fase de
rasterización).
La implementación de este algoritmo requiere un
geometry shader y un fragment shader (Figura 7). El
primero se encarga de analizar cada curva de Bézier y
descomponerla en los casos en que no son válidas para su
renderización de manera directa (Figura 8). Además
calcula los coeficientes de la ecuación implícita de la
curva, que son pasados al fragment shader. El fragment
shader evalúa esta ecuación por cada fragmento del
interior del polígono de control de la curva de Bézier,
descartando los píxeles situados en el exterior de la
misma (Algoritmo 4).
implementación tradicional basada en CPU de hasta
400X.
Figura 7. Procesamiento de cada curva de Bezier mediante
geometry y fragment shaders.
A continuación se presentan soluciones propuestas en
CUDA para dos problemas clásicos en Geometría
Computacional [12]. En primer lugar, el problema ya
antes citado de inclusión de puntos en sólidos. Y por otra
parte la determinación de auto-intersección de triángulos
en mallas de triángulos.
Figura 9. Fuentes Postscript generados mediante el algoritmo
de dibujado de polígonos curvos.
Figura 8. Curvas de Bézier válidas (a) y casos inválidos:
serpentina (b) y bucle (c).
Como muestra la Figura 7, por cada curva de Bézier
válida, el procesador de geometría lanza 3 triángulos: dos
definen el cuadrilátero de control de la Bézier y el tercero
une este cuadrilátero con un punto común para todas las
curvas denominado origen. Éste triángulo adicional es
necesario para la construcción de un símplice válido a
partir de la curva [10]. Los símplices resultantes son
rasterizados en el stencil buffer utilizando la operación
G_INVERT y el contenido final es transferido al
framebuffer, aplicando el color o textura que se desee
(Figura 9).
La integración completa del proceso de dibujado del
polígono curvo en GPU tiene interesantes posibilidades:
los puntos de control de las curvas pueden ser generados a
partir de una textura, animados o deformados mediante un
vertex shader. Esto posibilita la animación en tiempo real
de modelos complejos como pelo o ropa. También pueden
implementarse métodos clásicos del procesamiento de
imágenes basados en curvas deformables como los
contornos activos [12].
3. Resolución de problemas geométricos
mediante CUDA.
La aparición de CUDA [3] a finales de 2006 ha supuesto
un cambio radical en los planteamientos de las
investigaciones en GPGPU. En primer lugar, porque
CUDA proporciona un conjunto de librerías y extensiones
que permiten que las aplicaciones sean programables en C
estándar sin necesidad de conocer librerías gráficas o
lenguajes de sombreado. Ello facilita al programador una
curva de aprendizaje rápida. Además, CUDA es un
modelo mucho más flexible que el de la programación
basada en shaders, en tanto en cuanto en la mayor parte
de las ocasiones no requiere de codificaciones especiales
de las estructuras de datos. Y todo ello proporcionando
mejoras en los tiempos de ejecución frente a una
3.1. Inclusión de puntos mediante CUDA.
La solución comentada en la sección 2.1 y descrita en el
Algoritmo 1 tiene como ventaja, además de su eficiencia,
el que es susceptible de ser paralelizada de una manera
casi directa.
Figura 10. Implementación CUDA basada en matrices del test
de inclusión.
El modelo de programación de CUDA es especialmente
útil en problemas cuya solución puede expresarse en
forma matricial. En el caso de la inclusión de puntos, el
problema puede plantearse construyendo una matriz en la
que las filas sean los tetraedros a procesar y las columnas
los puntos a procesar. Esta matriz se divide en bloques de
threads, donde cada thread determina la inclusión del
punto de la columna j con respecto al tetraedro de la fila i,
incrementando el resultado de dicha inclusión al contador
j (Figura 10). Sin embargo, esta solución requiere que las
hebras accedan simultáneamente a la misma posición de
la memoria global, lo que solo puede realizarse mediante
operaciones atómicas. Ello puede resolverse utilizando si
cada hebra almacena el resultado en la posición (i,j) de
una matriz de enteros, pero dicha matriz puede tener un
tamaño demasiado grande en la mayoría de las ocasiones.
En definitiva, el principal inconveniente de este enfoque
es que se requieren muchos accesos simultáneos a
memoria, que es uno de los factores que más afectan al
rendimiento de CUDA.
Otra posible solución consiste en que cada hebra
determine la inclusión de unos pocos puntos sobre la
malla completa. En este caso cada hebra itera sobre la
malla entera, copiando un triángulo de memoria global a
memoria local, para determinar la inclusión de los puntos,
depositando el resultado en un vector que almacena el
valor de inclusión por punto (Figura 11). Podría pensarse
que este enfoque produciría menos resultados en
comparación con la solución anterior, ya que la carga de
trabajo de cada hebra es mayor. Pero en la práctica se
obtiene una ganancia de hasta 77x (Tabla 3).
actualizada por cada hebra cada vez que se añade un par
de triángulos en la lista. (Figura 12).
Los mejores resultados de la solución propuesta se
obtienen como era de esperar en mallas grandes, llegando
la mejora hasta 42x (Tabla 4).
Figura 12. Implementación CUDA del test de auto-intersección.
Figura 11. Implementación CUDA del test de inclusión.
Tabla 4. Tiempos obtenidos para el test de auto-intersección
con CUDA.
4. Visualización de terrenos en dispositivos
móviles.
Tabla 3. Ganancia del test de inclusión en CUDA frente a la
implementación CPU.
A la hora de realizar la implementación deben tenerse en
cuenta que el acceso de los threads a la lista de triángulos
debe intercalarse para evitar accesos simultáneos.
Además, el mayor beneficio se obtiene cuando se
aumenta el número de puntos a testear, esto es, cuando se
aumenta el número de hebras.
3.2. Test de auto-intersección en CUDA.
La determinación de auto-intersecciones en mallas de
triángulos es especialmente útil en muchas aplicaciones
como prototipado rápido o simulación interactiva de
objetos deformables. Existen diferentes soluciones a este
problema para CPU, pero las soluciones basadas en GPU
son más escasas, destacando las propuestas en [13,14,15].
La mejora obtenida respecto a los métodos basados en
CPU llega hasta 17x en el mejor de los casos, si bien
presenta algunos problemas respecto al tamaño de las
mallas a tratar.
Rueda y Ortega [12] han propuesto una solución basada
en CUDA, centrada en calcular la intersección de pares de
triángulos. Cada hebra determina la intersección de un
triángulo ti con los triángulos ti+1, … tn. Los resultados
pueden almacenarse en una matriz de booleanos. Sin
embargo, esta solución también tiene unos altos
requerimientos de memoria. En lugar de ello, generan una
lista de índices con los pares de triángulos que
intersectan, almacenada en un buffer. La primera posición
de este buffer contiene el tamaño de la lista y es
Otro de los objetivos del proyecto se centra en la
visualización de terrenos en dispositivos móviles en
tiempo real. Para ello es necesario, aprovechar al máximo
todas las capacidades gráficas de este tipo de dispositivos,
considerando las importantes restricciones de memoria de
los mismos. Además, y con el fin de alcanzar el mayor
número de dispositivos como sea posible, es necesario
partir de una arquitectura software que limitará en parte el
rendimiento de la aplicación.
La capacidad 3D de los dispositivos móviles es
programada mediante dos librerías estandarizadas:
OpenGL-ES, a la que se accede típicamente desde C o
C++, y M3G, para Java Micro Edition.
OpenGL-ES [16] es una librería de bajo nivel muy ligera
para generar gráficos en 2D y 3D en sistemas embebidos
tales como teléfonos, videoconsolas, PDAs, etc. Es libre
de royalties y multiplataforma. OpenGL-ES ha sido
elegido como el API de gráficos 3D oficial para los
teléfonos móviles pasados en Symbian OS, Android e
iPhone. Además está disponible para teléfonos móviles
basados en Windows Mobile. Consiste en un subconjunto
del API de OpenGL para sistemas de escritorio y
proporciona una poderosa interfaz estandarizada que
permite a los desarrolladores concentrarse más en el
contenido y menos en detalles concretos de la plataforma.
Por su parte, M3G (JSR-184) [17] es un API gráfica y
estandarizada de alto nivel para Java Mobile Edition. Está
diseñado de forma que puede implementarse
eficientemente sobre OpenGL-ES, de manera que
OpenGL-ES proporciona a M3G funcionalidades de bajo
nivel tales como transformaciones, iluminación y
rasterización, mientras que M3G añade características de
alto nivel tales como el grafo de escena o animación.
Agradecimientos.
Actualmente se está diseñando e implementando una
plataforma basada en arquitectura cliente-servidor para la
visualización de terrenos en dispositivos móviles. La
parte de cliente se encuentra en estado muy avanzado, y
se ha diseñado siguiendo los principios de eficiencia y
portabilidad (Figura 13). La parte de servidor se encuentra
aún en fase de diseño.
Este trabajo ha sido financiado por la Junta de Andalucía
y la Unión Europea a través de FEDER, bajo el proyecto
de investigación P06-TIC-01403.
Figura 13. Arquitectura software del visor de terrenos para
dispositivos móviles.
En cualquier caso, los resultados obtenidos son bastante
esperanzadores, obteniendo hasta 50 fps para escenas de
unos 125000 triángulos, con efectos de iluminación. Se
espera que conforme aumente la disponibilidad de
dispositivos móviles dotados de la implementación 2.0 de
OpenGL-ES, que incluye ya pipeline programable, este
rendimiento pueda ser aún mayor.
Figura 14. Visor de terrenos para dispositivos móviles
5. Conclusiones y futuros trabajos
En este artículo se ha presentado un resumen de los
principales resultados del proyecto “Adaptación de
Algoritmos Geométricos al uso de GPU Programable.
Aplicaciones”. A la vista de los mismos puede concluirse
que muchos de los algoritmos geométricos fundamentales
pueden ser resueltos de manera efectiva mediante el uso
del hardware gráfico. Además, la aparición de CUDA ha
facilitado el desarrollo de nuevas soluciones que aceleran
enormemente el rendimiento obtenido. Es de esperar que
la integración de nuevas funcionalidades como CUDA o
SLI mejoren aún más el rendimiento.
El proyecto se encuentra actualmente en la fase central, si
bien puede afirmarse que muchos de los objetivos
propuestos se han alcanzado ya. El principal esfuerzo
debe centrarse en la aplicación de las soluciones obtenidas
a problemas más concretos, especialmente en Sistemas de
Información Geográfica y Sistemas de Navegación.
Referencias.
[1] Kilgariff, E., Fernando, R., “The GeForce 6 Series GPU
Architecture”, in “GPU Gems 2”, Nvidia, Addisson Wesley,
2005.
[2] GPGPU, General-Purpose Computation using Graphics
Hardware, http://www.gpgpu.org.
[3] CUDA, Compute Unified Device Architecture,
http://www.nvidia.com/object/cuda_home.html
[4] AMD Stream Computing, http://ati.amd.com/technology/streamcomputing/index.html.
[5] C. Ogayar, R.J. Segura, F. R. Feito. “Point in Solid
Strategies”. Computers & Graphics, 29 (4), 2005.
[6] R. Segura, F.R. Feito, J. Ruiz de Miras, J.C. Torres, and C.
Ogayar. “An Efficient Point Classification Algorithm for
Triangle Meshes”. Journal of Graphics Tools, 10 (3), 2005.
[7] J. J. Jiménez, F. R. Feito, R.J. Segura, C. Ogayar, “Particle
Oriented Collision Detection using Simplicial Coverings and
Tetra-Tree”. Computer Graphics Forum, 26 (1), 2006.
[8] C. Ogáyar, A.J. Rueda, R.J. Segura, F. Feito. “Fast and
simple hardware accelerated voxelizations using simplicial
coverings”, The Visual Computer, 23 (8), 2007.
[9] J.M. Noguera, C. Ogáyar, A.J. Rueda, R.J. Segura.
“Voxelización de sólidos mediante instanciación de
geometría”, Actas del XVIII Congreso Español de
Informática Gráfica, CEIG 2008, Barcelona, 2008.
[10] J. Ruiz de Miras , F. Feito. “Inclusion test for curved-edge
polygons”. Computers & Graphics, 21, 1997.
[11] A.J. Rueda, J. Ruiz de Miras, F. Feito. “GPU-based
rendering of curved polygons using simplicial coverings”,
Computer & Graphics, 32 (5), 2008.
[12] A.J. Rueda, L. Ortega. “Geometric algorithms on CUDA”,
III International Conference on Computer Graphics Theory
and Applications, GRAPP'08, Madeira, Portugal, 2008.
[13] N. K. Govindaraju, I. Kabul, M. C. Lin, D. Manocha, “Fast
continuous collision detection among deformable models
using graphics processors”, Comput. Graph. 31 (1), 2007.
[14] N. K. Govindaraju, M. C. Lin, D. Manocha, “Quick-cullide:
fast inter- and intra-object collision culling using graphics
hardware, SIGGRAPH ’05: ACM SIGGRAPH 2005
Courses, 2005.
[15] Y. Choi, Y. J. Kim, M. Kim, “Rapid pairwise intersection
tests using programmable GPUs”, The Visual Computer, 22
(2), 2006.
[16] Khronos Group. OpenGL-ES - the standard for embedded
accelerated 3d graphics. http://www.khronos.org/, 2004.
[17] Java Community Process. Jsr 184: Mobile 3D graphics API
for J2me. http://www.jcp.org/en/jsr/detail?id=184, 2005.
Apéndice
Inicializar los conjuntos de vértices positivos (PosVert) y negativos
(NegVert) a vacío
acum=0;
foreach Ti=( Qi1Qi2Qi3) del recubrimiento {
if (P ∈ Ti) return (TRUE);
if (P∉ (OQi1Qi2Qi3)) continue;
if (P está en el interior de (OQi1Qi2Qi3)) acum+=2*sign([OQi1Qi2Qi3]);
else
if (P está en una cara de (OQi1Qi2Qi3)) acum+=sign([OQi1Qi2Qi3]);
else // P está en la arista OQij
if (sign([OQi1Qi2Qi3])>0) { Tetraedro positivo
if (Qij ∉ PosVert) {
insertar Qij en Posvert
acum+=2;
}
}
else { // El tetraedro tiene signo negativo
if (Qij ∉NegVert) {
insertar Qij en NegVert;
counter-=2;
}
}
}
return (acum == 2);
Algoritmo1. Inclusión de puntos en sólidos.
Sort ABC with respect to the y co-ordinate
y=Ay
Compute mAB, mAC, mBC, mOA, mOB, mOC
Ai=A; mB=mAB; mC=mAC
if By=y then Bi=B; mB=mOB
else mB=mAB; Bi=Ai+(B-A)·mB
if Cy=y then Ci=C; mC=mOC
else mC=mAC; Ci=Ai+(C-A)·mC
While (y>0)
Rasterize2D (Ai,Bi,Ci)
y--;
if (y<Bi) then mB=mOB
if (y<Ci) then mC=mOC
if (By>y>Cy) then
Di=B+(C-B)·mBC
Rasterize2D(Bi,Di,Ci)
Update Ai,Bi,Ci with the corresponding increment
Algoritmo2. Voxelización de tetraedros.
1. Crear la textura, que almacena los vértices ABCD de cada tetraedro, y
enviarla a la GPU.
2. Inicializar ys al tamaño del espacio de vóxeles.
3. Crear un array de vértices que almacene únicamente dos triángulos,
P0P1P2 y P3P2P1.
4. Limpiar el framebuffer y establecer la operación lógica por píxel a
GL_XOR.
5. Establecer como variables uniformes ys y el tamaño de la textura. Enviar el
array de vértices a la GPU con DrawArraysInstancedEXT, indicando que se
cree una instancia por cada tetraedro.
6. Copiar el resultado del framebuffer a memoria principal de la CPU.
7. Decrementar ys y volver al paso 4 hasta ys = 0
Algoritmo 3. Voxelización de sólidos mediante instaciación de
geometría.
#define UV gl_TexCoord[0]
varying vec4 coef1, coef2;
void main() {
vec4 ev1= vec4(pow(UV.x,3), pow(UV.x,2), UV.x, pow(UV.y,2));
vec4 ev2=vec4(pow(UV.y,3),ev1[1]*UV.y,UV.x*ev1[3],UV.x*UV.y);
if (dot(ev1, coef1) + dot(ev2,coef2) < 0.0f) discard;
}
Algoritmo 4. Fragment shader para el dibujado de una curva de
Bézier (código GLSL).
Descargar