Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

Proyecto Fin de Carrera PDF

Descargar como pdf o txt
Descargar como pdf o txt
Está en la página 1de 116

Proyecto Fin de Carrera

Generacin de paisajes procedurales


con Direct3D y GPU

Autor

D. Juan Gallego Molina

Director

Dr. D. Francisco Jos Sern Arbeloa

Escuela de Ingeniera y Arquitectura


2013/2014

Gracias a todos los compaeros que he tenido


durante estos aos, tanto en Zaragoza como
en mis aventuras en Cork y Donosti, donde
me he sentido como en casa.
A los profesores que me han ayudado durante
mi formacin, sobre todo a Paco por sus
consejos.
Y en especial a mi familia, sobre todo a mi
hermano, que ya me avis de los peligros
de querer ser ingeniero.

Generacin de paisajes procedurales con Direct3D y GPU

RESUMEN
Las modernas unidades de procesamiento grfico ofrecen capacidades operacionales de
clculo general. Este mbito est cobrando importancia ya que muchos clculos pueden
derivarse a la GPU, donde la existencia de numerosos ncleos trabajando en paralelo
permite obtener una mayor rapidez en la resolucin de algunos problemas, tanto de
ndole cientfico como para los videojuegos.
En este mbito es donde surge este Proyecto de Fin de Carrera. En concreto se ha
creado un paisaje procedural formado por varios elementos como montaas, playa,
agua, un planeta y nubes. Todos ellos se han creado utilizando el ruido de Perlin para
generar formas fractales. Dicho algoritmo est especialmente aconsejado para la
generacin de objetos naturales y adems es adecuado para aprovechar la capacidad de
clculo en paralelo de las unidades de procesamiento grfico, ya que cada vrtice puede
calcularse de manera individual.
Adems de los aspectos relacionados con la geometra de estos elementos se han tenido
en cuenta otros componentes de una pipeline grfica como son el modelo de
iluminacin y sombras, el texturizado de los objetos, el audio, el movimiento de la
cmara y la animacin de algunos elementos.
La aplicacin se ha desarrollado utilizando la API Direct3D 11 de Microsoft, ya que es
una de las ms usadas en el mundo de los grficos y nos permite aprovechar las
caractersticas de la GPU. Adems este API contiene varias herramientas que sirven
para controlar el estado de actividad de la unidad grfica, incluyendo el tiempo que est
trabajando, lo que nos ha permitido poner de manifiesto el beneficio de una ejecucin
en paralelo.
Finalmente, se ha integrado el algoritmo de ruido de Perlin en el entorno de desarrollo
de videojuegos UDK, Unreal Development Kit, donde se ha usado para crear un planeta
fractal. De esta manera se demuestra la capacidad tcnica para adaptar y aplicar los
conocimientos adquiridos en aplicaciones comerciales ya existentes.

NDICE DE CONTENIDOS
RESUMEN........................................................................................................................5
NDICE DE CONTENIDOS.............................................................................................7
NDICE DE TABLAS.......................................................................................................8
NDICE DE FIGURAS.....................................................................................................9
1. INTRODUCCIN.......................................................................................................13
1. 1. Contexto tecnolgico..........................................................................................13
1. 2. Objetivos.............................................................................................................15
1. 3. Estructura del documento...................................................................................16
2. TRABAJO REALIZADO...........................................................................................17
2. 1. Fractales y ruido..................................................................................................17
2. 2. Direct3D..............................................................................................................22
2. 3. Creacin de la escena..........................................................................................26
2. 4. Anlisis de rendimiento.......................................................................................36
2. 5. Integracin en UDK............................................................................................44
3. CONCLUSIONES.......................................................................................................47
3. 1. Resultados obtenidos..........................................................................................47
3. 2. Lneas futuras......................................................................................................47
3. 3. Valoracin personal.............................................................................................48
4. BIBLIOGRAFA.........................................................................................................49
ANEXOS
ANEXO A: GESTIN DEL PROYECTO......................................................................55
A. 1. Planificacin.......................................................................................................55
A. 2. Herramientas utilizadas......................................................................................56
ANEXO B: COMPARACIN DE MOTORES..............................................................57
B. 1. Herramientas disponibles...................................................................................57
B. 2. Imgenes comparativas......................................................................................64
ANEXO C: LA PIPELINE GRFICA...........................................................................71
C. 1. Etapas.................................................................................................................71
C. 2. HLSL..................................................................................................................72
ANEXO D: LA PIPELINE DE CLCULO....................................................................75
D. 1. Etapas.................................................................................................................75
D. 2. Caractersticas....................................................................................................75
ANEXO E: APLICACIN ESTUDIADA......................................................................79
E. 1. Contexto.............................................................................................................79
E. 2. Diseo.................................................................................................................80
E. 3. Aplicacin...........................................................................................................81
E. 4. Shader de clculo................................................................................................91
E. 5. Shaders de renderizado.......................................................................................94
E. 6. Resultados...........................................................................................................96
ANEXO F: RUIDO Y FRACTALES..............................................................................97
F. 1. Ruido...................................................................................................................97
F. 2. Tipos de ruido......................................................................................................97
F. 3. Fractales..............................................................................................................98
ANEXO G: DOCUMENTACIN DE LA APLICACIN...........................................101
G. 1. Lista de clases..................................................................................................101
G. 2. Documentacin de clases.................................................................................101
7

NDICE DE TABLAS
Tabla 1: Geometra de la escena......................................................................................34
Tabla 2: Llamada draw 1.................................................................................................36
Tabla 3: Llamada draw 2.................................................................................................37
Tabla 4: Llamadas draw 3 -12.........................................................................................37
Tabla 5: Llamada draw 13...............................................................................................37
Tabla 6: Equipos de prueba..............................................................................................38
Tabla 7: Dedicacin.........................................................................................................55
Tabla 8: Herramientas utilizadas.....................................................................................56
Tabla 9: Motores. Animacin..........................................................................................57
Tabla 10: Motores. Audio................................................................................................58
Tabla 11: Motores. Cinemticas......................................................................................58
Tabla 12: Motores. Networking.......................................................................................58
Tabla 13: Motores. Editor................................................................................................59
Tabla 14: Motores. Fsicas...............................................................................................59
Tabla 15: Motores. Iluminacin.......................................................................................60
Tabla 16: Motores. Inteligencia Artificial........................................................................60
Tabla 17: Motores. Programacin....................................................................................61
Tabla 18: Motores. Renderizado......................................................................................62
Tabla 19: Motores. Shaders y materiales.........................................................................63
Tabla 20: Motores. Terreno..............................................................................................63
Tabla 21: Motores. Otros.................................................................................................64

NDICE DE FIGURAS
Figura 1: Gradientes generados en 2 dimensiones..........................................................18
Figura 2: Malla en 2 dimensiones, n = 2.........................................................................19
Figura 3: Octavas de ruido...............................................................................................20
Figura 4: Ruido de Perlin, paso 1....................................................................................20
Figura 5: Ruido de Perlin, paso 2....................................................................................21
Figura 6: Ruido de Perlin, paso 3....................................................................................21
Figura 7: Arquitectura grfica..........................................................................................22
Figura 8: Pipeline grfica................................................................................................23
Figura 9: Pipeline computacional....................................................................................23
Figura 10: Threads en la GPU.........................................................................................24
Figura 11: Mip-mapping..................................................................................................25
Figura 12: Recursos en la pipeline grfica......................................................................25
Figura 13: Recursos en la pipeline computacional..........................................................26
Figura 14: Escena con un solo fractal..............................................................................27
Figura 15: Escena con 2 fractales....................................................................................27
Figura 16: Escena con los 3 fractales..............................................................................28
Figura 17: Escena completa.............................................................................................28
Figura 18: Clculo del fractal de la playa y las montaas...............................................29
Figura 19: Superficie del planeta fractal..........................................................................31
Figura 20: Planeta con nubes...........................................................................................31
Figura 21: Cielo...............................................................................................................32
Figura 22: Animacin de los pjaros...............................................................................32
Figura 23: Paisaje 100% - 649.800 vrtices....................................................................35
Figura 24: Paisaje 50% - 324.900 vrtices......................................................................35
Figura 25: Paisaje 25% - 162.450 vrtices......................................................................35
Figura 26: Paisaje 10% - 64.979 vrtices........................................................................36
Figura 27: Escena 1.........................................................................................................40
Figura 28: Escena 2.........................................................................................................40
Figura 29: Tiempo de inicio (s).......................................................................................41
Figura 30: Tiempos en la GPU (ms)................................................................................42
Figura 31: Tiempos en la CPU (ms)................................................................................43
Figura 32: Tiempos escena 1 GPU vs CPU (ms).............................................................44
Figura 33: Ruido de Perlin en UDK................................................................................45
Figura 34: Escena UDK...................................................................................................46
Figura 35: Muestra UDK 1..............................................................................................65
Figura 36: Muestra UDK 2..............................................................................................65
Figura 37: Muestra UDK 3..............................................................................................66
Figura 38: Muestra UDK 4..............................................................................................66
Figura 39: Muestra CryEngine 1.....................................................................................67
Figura 40: Muestra CryEngine 2.....................................................................................67
Figura 41: Muestra Cryengine 3......................................................................................68
Figura 42: Muestra CryEngine 4.....................................................................................68
Figura 43: Muestra Unity 1.............................................................................................69
Figura 44: Muestra Unity 2.............................................................................................69
Figura 45: Muestra Unity 3.............................................................................................70
Figura 46: Muestra Unity 4.............................................................................................70
Figura 47: Pipeline grfica..............................................................................................71
9

Figura 48: Organizacin de los threads de un compute shader.......................................76


Figura 49: Conexin de columnas de agua......................................................................80
Figura 50: Simulacin de agua con columnas.................................................................96
Figura 51: Montaas fractales.........................................................................................99
Figura 52: Lago fractal..................................................................................................100
Figura 53: Ocano fractal..............................................................................................100

10

1. INTRODUCCIN
El presente documento tiene como objetivo presentar toda la informacin relacionada
con la realizacin de este Proyecto de Fin de Carrera (PFC) titulado Generacin de
paisajes procedurales con Direct3D y GPU. En este apartado titulado Introduccin se
describe el contexto tecnolgico en el que se inserta este proyecto as como sus
objetivos y la estructura general de la memoria.

1. 1. Contexto tecnolgico
1. 1. 1. Unidades de procesamiento grfico
Las unidades de procesamiento grfico (GPU) han evolucionado enormemente a lo
largo de los aos, pasando de ofrecer una pipeline fija a otra mucho ms flexible que
puede ejecutar programas, denominados shaders, realizados por cualquier
desarrollador usando alguno de los lenguajes existentes: HLSL, de Microsoft; CG, de
nVidia; o GLSL, libre, aunque realmente hay pocas diferencias conceptuales adems de
las sintcticas.
Es aqu donde se basa el concepto de clculo general en la unidad grfica, o GPGPU por
su nombre en ingls, General Purpose computing on Graphics Processing Units.
Debido a que las GPU no son ms que coprocesadores especializados en operaciones
con nmeros reales es tericamente posible utilizar su gran nmero de ncleos
trabajando en paralelo para cualquier tipo de problema paralelizable del tipo SIMD,
Single Instruction Multiple Data.
Para la programacin de las unidades grficas se usan distintas API, siendo Direct3D,
propiedad de Microsoft, y OpenGL, libre, las ms utilizadas para el apartado grfico.
Por otra parte, DirectCompute, tambin de Microsoft; CUDA, de nVidia, y OpenCL son
las usadas para la parte computacional. Todas ellas se pueden integrar fcilmente en
cualquier aplicacin.

1. 1. 2. Videojuegos
Entre las aplicaciones comunes que ms utilizan la GPU estn los videojuegos. Por ello
se ha querido enmarcar este proyecto en este mbito.
El desarrollo de un videojuego es un proceso complejo que no se limita tan solo a la
programacin de la parte visual. Recordemos algunas de las fases por las que se pasa
durante su creacin:

Concepcin: definir la idea, el gnero del juego, cmo y dnde va a ser jugado,
la historia, los personajes o la ambientacin.

Diseo: definir las ideas obtenidas en el paso anterior, refinando la historia a


contar, la jugabilidad y comenzar con la parte artstica, realizando bocetos del
mundo y sus componentes. Tambin puede ser el momento de elegir las
herramientas y metodologas a usar durante el resto del desarrollo.

13

Planificacin: dividir el trabajo a realizar en sus distintas etapas, as como


marcar fechas lmites y los entregables de cada fase. Tambin habr que tener en
cuenta el presupuesto que se necesitar para acometer el trabajo y el personal
requerido.

Desarrollo: es el momento de crear todos los componentes del juego, que


podramos dividir en varios apartados:
Arte 2D 3D: los modelos 3D o los elementos 2D, como sprites o
texturas. Se pueden crear usando herramientas propias pero lo habitual es
usar algunas herramientas externas que estn muy extendidas por su
calidad, como Zbrush o Maya para los modelos en 3D y Photoshop o
Gimp para los 2D.
Motor del juego: el motor es el encargado de proporcionar la mayora de
funcionalidades necesarias como el renderizado de los grficos, la
animacin, deteccin de colisiones, IA, simulacin de fsicas,
networking, gameplay o audio. No obstante, programar un motor entero
desde cero es muy costoso, por lo que es habitual usar alguno ya
existente, como Unity o Unreal Engine, y modificar algunas partes para
adaptarlo a nuestras necesidades. Hay que tener en cuenta que las
licencias para usar un motor pueden ser muy caras y las gratuitas no
suelen ofrecer acceso a todo el cdigo de ste, por lo que la capacidad de
modificarlo es limitada.
Audio: hay que crear, bien desde cero o utilizando algunos elementos ya
grabados, todos los sonidos del juego, tanto los producidos por los
objetos como las voces y la msica. Tambin suelen usarse herramientas
externas como Wwise y FMOD.
Niveles: Una vez contamos con un motor y todos los elementos artsticos
es el momento de unirlos y crear los niveles jugables, lo que implica
colocar los objetos en sus sitios y programar los distintos eventos del
juego.

Pruebas: Como en cualquier proyecto hay que comprobar la calidad del


producto. Por esto se requiere un conjunto de tests completo que comprendan
todos los apartados del juego y un plan de soluciones para llevar a cabo en caso
de encontrar errores.

Es en la parte del motor grfico donde se ubica este proyecto, evidentemente no en su


creacin completa, pero s en la posibilidad de aplicar los conocimientos adquiridos
para la programacin de alguna de sus partes y su posterior integracin con el resto del
motor, en especial aquellos apartados relacionados con las unidades grficas. Para ello
se analizaron 3 opciones distintas donde poder integrar los resultados de este trabajo,
todas ellas para PC con dos requisitos, que fueran potentes y de uso gratuito:

Unity: es uno de los motores gratuitos ms usados por desarrolladores indies.


Soporta las plataformas ms importantes: PC, Linux, PS3, Xbox360, WiiU, iOS
y Android. Se caracteriza por su facilidad de uso, con la posibilidad de crear
prototipos de manera rpida, sencilla y flexible, ya que existen muchos
componentes creados previamente por la comunidad existente. Adems nos
permite programar nuestros propios shaders, ya sea usando Cg, GLSL o HLSL.

14

La versin gratis es, no obstante, incompleta y solo la de pago ofrece todas las
caractersticas [1].

CryEngine 3: es uno de los motores ms famosos en la industria ya que ofrece


grficos realistas y simulacin de fsicas para PC, PS3 y Xbox360. Permite usar
un conjunto de herramientas completas de manera gratuita, siendo el editor de
terrenos uno de sus puntos ms fuertes. Aunque el cdigo del motor no es
accesible directamente, se puede personalizar y programar en C++ gran parte de
los subsistemas de ste, que llamarn al cdigo fuente. No obstante, el apoyo de
la comunidad y la existencia de tutoriales es escaso, requiriendo conexin a
Internet para identificarse y usar las herramientas. Adems el sistema de shaders
es cerrado, por lo que no es factible programar los deseados [2].

Unreal Engine 3 / Unreal Development Kit: UDK es la versin gratuita del


motor Unreal Engine 3, uno de los motores ms potentes y usados en la
industria. Ofrece un completo conjunto de herramientas que permiten crear
juegos para PC y iOS, aunque la versin de pago soporta tambin MAC, Xbox
360, PS3, WiiU, PSVita y Android. No es posible acceder directamente al cdigo
fuente, pero si usar el lenguaje de programacin UnrealScript para retocar y
acceder a cualquier parte del motor a alto nivel. La comunidad existente es muy
amplia, con gran nmero de tutoriales, y adems es posible crear nuestros
propios shaders usando HLSL [3].

Puede verse una comparacin en detalle de las caractersticas que ofrece cada motor en
el ANEXO B: COMPARACIN DE MOTORES.
En este trabajo cabe mencionar que CryEngine deja de ser una opcin puesto que no
permite la programacin de shaders. En cuanto a Unity y UDK, es este ltimo el que
ofrece ms funcionalidades y por eso es el motor elegido.
El motor Unreal en PC utiliza Direct3D como API grfica, por lo que es obligatorio
elegir HLSL como lenguaje de programacin de shaders..
El motor puede usar tanto Direct3D 9 como 11, que son las dos ltimas versiones ms
extendidas de la API. La versin 10 es muy poco utilizada, ya que se cre para
funcionar en el sistema operativo Windows Vista, cuya penetracin en el mercado fue
escasa en comparacin con XP, que usa la versin 9. Direct3D 11 se desarroll para
funcionar con Windows 7 y es la elegida puesto que es la ms moderna y la que ms
funcionalidades incorpora, incluyendo el ltimo modelo de shaders que nos permite usar
compute shaders y utilizar la GPU para cmputo general [4].

1. 2. Objetivos
La idea de este proyecto es utilizar las unidades de procesamiento grfico y mostrar sus
capacidades en el mundo de los videojuegos.
Los objetivos concretos a alcanzar son:

15

Generacin de una escena formada por elementos naturales.


Comprender el funcionamiento de la API Direct3D, la pipeline grfica y
computacional.
Implementar la creacin de agua, montaas, nubes y planetas basados en
algoritmos procedurales fractales y ruido de Perlin.
Comparar el rendimiento de la implementacin entre CPU y GPU
Integrar parte de las funcionalidades implementadas dentro de un motor grfico
para videojuegos ya existente.

1. 3. Estructura del documento


La memoria del PFC se divide en los siguientes captulos:
I. Trabajo realizado. Se describen los algoritmos fractales que se han implementado.
Posteriormente se explica la estructura conceptual de Direct3D, que es la API elegida
para desarrollar el trabajo. Despus se pasa a describir el paisaje modelado y el
algoritmo en que se basa su apariencia. Se contina comparando el rendimiento
obtenido usando una CPU y una GPU y se finaliza comentando la integracin de parte
de las funcionalidades desarrolladas en un motor grfico para videojuegos ya existente.
II. Conclusiones. Se comentan los resultados obtenidos, las conclusiones alcanzadas y
posibles maneras de continuar en el futuro con el trabajo.
III. Bibliografa. Referencias de artculos y libros utilizados.
IV. Anexos. En ellos se profundiza en distintos aspectos del proyecto que, por brevedad,
no pueden comentarse en el cuerpo principal de la memoria.

16

2. TRABAJO REALIZADO
En esta seccin se detalla el trabajo realizado a lo largo del PFC. Se comienza
describiendo los fractales, seccin 2.1, y se sigue con el estudio de Direct3D, API
utilizada para crear nuestra aplicacin, en la seccin 2.2. Despus se explica la creacin
de la escena, seccin 2.3. A continuacin se compara el rendimiento obtenido usando
una CPU y una GPU, seccin 2.4. Por ltimo, se integra parte del trabajo realizado en el
motor Unreal Engine, seccin 2.5.

2. 1. Fractales y ruido
2. 1. 1. Fractales
Un fractal es un patrn que se repite a diferentes escalas para describir la forma de un
objeto irregular que no se podra obtener con los mtodos de la geometra clsica. stos
nos permiten, a travs de algoritmos, reproducir la complejidad de elementos tpicos de
la naturaleza como son las montaas, las nubes o incluso planetas enteros.
Aunque las ideas que existen tras estos mtodos se remontan al siglo 17 en esa poca los
matemticos estaban limitados a las imgenes que podan reproducir ellos mismos. Es
por eso que empiezan a cobrar importancia a partir de los aos 70, cuando aparecen los
primeros grficos por computador. Es en el ao 1979 cuando se crea la primera
animacin con elementos fractales, un corto de 2 minutos llamado Vol Libre de Loren
Carpenter [5].
No obstante, el primer trabajo formal en el que se define el concepto de los fractales tal
y como los conocemos ahora se debe a Benoit Mandelbrot en su libro The Fractal
Geometry of Nature, publicado en 1982 [6]. En ese ao tambin se crea el primer
planeta fractal mostrado en el cine en la pelcula Star Trek II, tambin por Carpenter y
su equipo de Pixar [7].
Desde entonces las imgenes creadas usando fractales han evolucionado junto con la
tecnologa, que cada vez permite alcanzar mayor realismo. Algunas de estas imgenes
pueden verse en el ANEXO F: RUIDO Y FRACTALES.
Es importante mencionar la aparicin en 1985 del Ruido de Perlin, ideado por Ken
Perlin [8]. Con l comenzaron los mtodos procedurales de generacin de fractales que
an hoy se siguen utilizando. En el mismo anexo citado se presenta una descripcin ms
detallada de las funciones usadas en estos mtodos.
Finalmente, comentar la existencia de la primera edicin del libro Texturing &
Modelling: A Procedural Approach en 1994 [9]. Es uno de los libros de referencia
sobre este tema y el que ha servido, en su tercera edicin, como gua e inspiracin para
el trabajo realizado en este PFC.
En ese mismo libro, adems de tratar los problemas tradicionales encontrados al trabajar
con fractales, tambin se presentan las tcnicas ms actuales y los nuevos retos
aparecidos al usar unidades grficas como herramienta de clculo.

17

2. 1. 2. Ruido de Perlin
El ruido de Perlin es una funcin matemtica que usa interpolacin entre varios
gradientes precalculados para obtener un valor entre -1 y 1 que vara pseudoaleatoriamente en el espacio o en el tiempo. Adems tiene la particularidad de ser
coherente, es decir, el ruido cambia suavemente y no existen discontinuidades [10].
La funcin puede definirse en cualquier espacio, sea cual sea su nmero de
dimensiones.
El espacio de n dimensiones que elijamos se divide en una malla definida para cada
punto con coordenadas enteras y a cada uno de ellos se le asigna uno de los gradientes
precalculados. Dichos gradientes se generaban inicialmente de manera aleatoria con
componentes entre -1.0 y 1.0, descartando aquellos cuya longitud sea superior a 1 y
normalizando el resto para evitar desviaciones alineadas con alguno de los ejes del
espacio.
En una revisin posterior Perlin decidi dejar de generar gradientes aleatorios ya que la
manera de asignarlos, comentada a continuacin, otorga suficiente aleatoriedad. Desde
entonces se utilizan gradientes que van desde el centro de un objeto de referencia de
dimensiones unidad, como un cuadrado en 2 dimensiones o un cubo en un espacio 3D, a
las aristas de dicho objeto y se normalizan, como vemos en la figura 1.

Figura 1: Gradientes generados


en 2 dimensiones
La asignacin de estos gradientes a cada punto de una malla de dimensin [t, t] se
realiza utilizando una permutacin aleatoria de nmeros enteros de tamao t y las
coordenadas del punto, como mostramos a continuacin para un espacio de dos
dimensiones:
Grad es una tabla de dimensin [4, 2] con los gradientes g0, g1, g2 y g3.
Perm es una tabla de dimensin t con una permutacin de enteros de tamao t.
P es un punto de la malla con coordenadas (x,y).
El gradiente asignado a dicho punto es:
Grad[modulo(4, Perm[modulo(t, y+Perm[x])])].
Para obtener el valor del ruido en cualquier punto de entrada p a la funcin debemos
usar los 2n puntos de la malla que lo rodean, como vemos en la figura 2.
18

Figura 2: Malla en 2 dimensiones, n = 2


Para cada uno de ellos tendremos un gradiente asignado, en este caso g 1 g4, y un
vector que va desde cada punto de la malla que rodea a p, tras lo cual obtendremos el
producto escalar de cada pareja de vectores asociados al mismo punto de la malla, como
se ve en el ejemplo de 2 dimensiones:
d1 = producto escalar (p1, g1)
d2 = producto escalar (p2, g2)
d2 = producto escalar (p3, g3)
d2 = producto escalar (p4, g4)
Finalmente interpolamos los 2n productos escalares usando la funcin 6p15 15p14 +
10p13 para obtener el valor del ruido. En el ejemplo dado primero interpolamos en x
entre d1 y d2 y entre d3 y d4. A continuacin interpolamos los 2 resultados obtenidos en y
para obtener el ruido final r. Elegimos esta funcin por ser una curva de forma S que
crece suavemente de 0 a 1 exagerando la cercana a ambos extremos. Adems tanto su
primera como su segunda derivada son 0 si las evaluamos en 0 o en 1, lo que evita que
se vean discontinuidades cuando tenemos una superficie desplazada usando el ruido de
Perlin y debemos calcular la normal.
Este procedimiento permite generar una funcin de ruido con frecuencia 1 y amplitud 1.
Para definir la funcin con frecuencia f y amplitud a debemos cambiar algunas cosas.
Lo primero que modificamos es que el espacio se dividir en una malla de dimensin
[f * t, f * t] y la asignacin de los gradientes ser como sigue:
Grad es una tabla de dimensin [4, 2] con los gradientes g0, g1, g2 y g3.
Perm es una tabla de dimensin t con una permutacin de enteros de tamao t.
P es un punto de la malla con coordenadas (x,y).
El gradiente asignado a dicho punto es
Grad[modulo(4, Perm[modulo(t, y+Perm[modulo(t, x)])])].
19

Adems usaremos como punto de entrada a la funcin f * p y el valor que se devolver


finalmente a * r.
La funcin de ruido es utilizada posteriormente para generar un fractal. Para ello se
suman distintas frecuencias de ruido a diferentes escalas, llamadas octavas si cada
frecuencia es mltiplo de 2, como se explica con ms detalle en el ANEXO F: RUIDO
Y FRACTALES y se muestra en la figura 3.

Figura 3: Octavas de ruido


Adems del ruido de Perlin hay otros tipos de ruido, cuya informacin se puede
consultar en el mismo anexo que acabamos de citar [11].

2. 1. 3. Ruido de Perlin en la GPU


A continuacin se explica cmo se ha implementado el ruido de Perlin en la GPU,
utilizando algunas figuras explicativas y pseudocdigo [12].
Aunque se han implementado versiones en 2 y 3 dimensiones aqu solo se explica la
primera ya que es sencillo aadir una o varias dimensiones adicionales.
Inicialmente creamos una permutacin de nmeros enteros de tamao 1024 y se generan
los 4 gradientes que van desde el centro de un cuadrado a sus aristas. Ambos datos se
guardarn en texturas, que adems de permitirnos hacer accesos rpidos se encargan de
hacer la operacin mdulo automticamente.
Cada punto p con coordenadas reales (x,y) cae dentro de una celda de la malla, la cual
podemos localizar a partir de la esquina (x0, y0). De esta misma manera se puede obtener
el vector que va desde dicha esquina al punto p, como se observa en la figura 4.

p es el punto en el que queremos calcular el


ruido de Perlin;
P = floor (p);
p1 = p P;

Figura 4: Ruido de Perlin, paso 1


20

Usando este vector p1 obtenemos el resto de vectores que van desde las esquinas de la
celda al punto p, como se muestra en la figura 5.

p2 = p1 + (-1, 0);
p3 = p1 + (0, -1);
p4 = p1 + (-1, -1);

Figura 5: Ruido de Perlin, paso 2


Ahora que tenemos los 4 vectores debemos obtener los gradientes asignados a cada
punto de la malla para obtener los productos escalares. Para ello necesitamos saber los
ndices correspondientes para indexar la tabla de gradientes, los cuales se obtienen
usando la permutacin de nmeros enteros, como se ve en la figura 6.

A = permutacin(P.x) + P.y;
B = permutacin(P.x + 1) + P.y;
g1 = gradiente(permutacin(A));
g2 = gradiente(permutacin(B));
g3 = gradiente(permutacin(A+1));
g4 = gradiente(permutacin(B+1));

Figura 6: Ruido de Perlin, paso 3


Finalmente, se obtiene el producto escalar de cada vector con el gradiente
correspondiente y se interpolan los resultados obtenidos, usando la curva 6t5 15t4 +
10t3 evaluada en p1, para hallar el valor final del ruido.
d1 = dot(p1, g1);
d2 = dot(p2, g2);
ix1 = interpolacin en x de d1 y d2;
ix2 = interpolacin en x de d3 y d4;

d3 = dot(p3, g3);

ruido final = interpolacin en y de ix1 y ix2;

21

d4 = dot(p4, g4);

2. 2. Direct3D
La API utilizada para interaccionar con la GPU en nuestra aplicacin es Direct3D 11, la
cual est diseada para poder ser accedida directamente mediante cdigo en C/C++ [4]
[13] [14] [15].

2. 2. 1. Arquitectura y pipeline
La arquitectura grfica seguida en Windows puede verse en la figura 7. La aplicacin
est en el nivel ms alto y es la que controla la escena: objetos 2D y 3D, animaciones,
texturas, etc. sta interacta principalmente con Direct3D, que convierte los datos de
alto nivel a un formato que pueda ser utilizado por el user mode driver, un driver de alto
nivel que no puede acceder directamente al kernel de la GPU para simplificar su
funcionamiento y reducir el nmero de errores.
Este driver se encarga de la traduccin a instrucciones que puedan ser ejecutadas por la
unidad de procesamiento grfico y sus resultados se pasan al siguiente nivel, DXGI, que
maneja los recursos de la GPU y se comunica directamente con la tarjeta grfica.
Este nivel est preparado para funcionar con prximas iteraciones de Direct3D, por lo
que tambin puede accederse directamente desde la aplicacin si necesitamos realizar
alguna operacin que an no est implementada en la API Direct3D 11.
Finalmente, el ltimo nivel es el propio hardware.
Ya que la aplicacin se comunica principalmente con Direct3D el programador puede
olvidarse del tipo de dispositivo grfico que est instalado, abstrayndose de la
complejidad del hardware disponible.

Figura 7: Arquitectura grfica


Adems es importante conocer la configuracin de la pipeline de Direct3D, cmo
fluyen los datos y se transforman en cada etapa.

22

La principal pipa es la grfica, mostrada en la figura 8, que se encarga de transformar


una escena 3D en una imagen en 2 dimensiones. Entre las etapas de la pipeline destacan
2, el vertex shader, que realiza operaciones sobre vrtices, y el pxel shader, que
hace operaciones sobre pxeles.

Figura 8: Pipeline grfica


Adems existe una pipeline de cmputo para otras aplicaciones, completamente
independiente de la pipa anterior y compuesta por una sola etapa llamada compute
shader, como se ve en la figura 9. En esta pipeline el hardware disponible permite
ejecutar operaciones con nmeros enteros y reales, vectores de hasta 4 componentes o
matrices de hasta 4x4, ya que disponemos de operadores para hacer sumas, restas,
multiplicaciones y divisiones escalar x escalar, escalar x vector, escalar x matriz, vector
x vector, vector x matriz y matriz x matriz. Adems se pueden hacer operaciones
lgicas, logaritmos en base 2 y races cuadradas.

Figura 9: Pipeline computacional


La pipeline computacional nos permite considerar la GPU como un conjunto de
procesadores trabajando en paralelo, cada uno de ellos ejecutando un hilo de
procesamiento o thread. La disposicin de estos hilos, que se unen formando grupos,
puede apreciarse en la figura 10, siendo los elementos rojos los grupos de threads y los
azules threads concretos.

23

Figura 10: Threads en la GPU


Ambas pipelines se explican con ms detalle en el ANEXO C: LA PIPELINE
GRFICA y el ANEXO D: LA PIPELINE DE CLCULO.

2. 2. 2. Interaccin con Direct 3D


Los datos en memoria que utiliza la GPU, ya sea en su comunicacin con la CPU o en
el intercambio de informacin interna entre etapas, se llaman recursos y Direct3D los
cataloga en 2 tipos: buffers y texturas.
Los buffers son conjuntos unidimensionales de datos y se usan para guardar
informacin sobre la geometra u otros datos necesarios en los shaders. Hay 3 tipos de
buffers:

Vertex Buffers: Contienen los vrtices que definen la geometra de la escena. El


formato de cada vrtice deber ser especificado por el desarrollador.
Index Buffers: Contienen punteros a los vrtices para no repetir informacin en
caso de que algn vrtice se utilice en varios polgonos.
Constant Buffers: Contienen cualquier otro tipo de datos. Los formatos de estos
datos pueden ser muy variados, existiendo tipos predefinidos, como reales o
enteros, y la posibilidad de especificar alguna estructura propia.

Las texturas representan conjuntos de datos estructurados en 1, 2 o 3 dimensiones. Cada


elemento de una textura se conoce como texel y contiene informacin en uno de los
muchos formatos predefinidos, siendo los que contienen informacin de colores los ms
habituales, como el formato RGBA de 128 bits. La mayora de unidades de
procesamiento grfico contienen hardware especializado para trabajar con texturas, por
lo que si nuestros datos encajan en alguno de los formatos disponibles deberamos
utilizarlas ya que su manejo ser mas eficiente que si usramos un buffer.

24

Con el uso de texturas tambin surge la idea de mip-map, distintas versiones de la


misma imagen usando diferentes resoluciones. stas se pueden intercambiar en funcin
del detalle que necesitemos en cada momento, usando ms o menos espacio en la
memoria de la GPU. Este concepto se muestra en la figura 11.

Figura 11: Mip-mapping


Adems las texturas van asociadas con un sampler state, un objeto que define como se
realiza el acceso a la textura desde un shader.
Con los tipos de recursos explicados debemos introducir el concepto de vista. Una vista
representa una instancia de un recurso, es decir, la asociacin de un recurso a una etapa
concreta de la pipeline. La idea surge porque un mismo recurso puede ser accedido
desde distintas partes de la pipa, las texturas, por ejemplo, siempre deben asociarse a la
pipeline mediante una vista. stas pueden ser de solo lectura o de lectura y escritura.
En las figuras 12 y 13 pueden verse los lugares en ambos tipos de pipeline donde
pueden asociarse los recursos, con fondo rojo.

Figura 12: Recursos en la pipeline grfica

25

Figura 13: Recursos en la


pipeline computacional
Todos los recursos, as como las vistas, se crean mediante la interfaz Device de
Direct3D 11. Esta misma interfaz tambin se utiliza para cargar y compilar los shaders y
para interrogar al hardware sobre la disponibilidad de ciertas caractersticas, ya que
estas varan en funcin de la versin de Direct3D implementada.
La asociacin de cada recurso a un lugar concreto de la pipeline se hace usando la
interfaz Device Context, que tambin es la encargada de configurar las etapas de la
pipeline y ordenar su ejecucin, con el comando draw para ejecutar la pipa grfica y
el comando dispatch para la computacional.
Al estado de la pipeline en un momento dado, es decir, su configuracin y recursos
asociados, se le llama contexto y puede ser de dos tipos: inmediato o diferido. El
inmediato es nico y es el que se usa durante la ejecucin de la pipeline mientras que el
diferido se guarda para una ejecucin posterior, momento en el que se pasar a ser el
inmediato. Puede haber varios contextos diferidos y son tiles cuando una CPU tiene
varios hilos de procesamiento distintos, de manera que podemos ahorrar tiempo creando
varios a la vez en paralelo.

2. 2. 3. Ejemplo de estudio
Para comprender el funcionamiento de Direct3D se ha desarrollado una simulacin de
agua que nos ha permitido observar las distintas caractersticas comentadas. Una
descripcin detallada de sta se encuentra en el ANEXO E: APLICACIN
ESTUDIADA.

2. 3. Creacin de la escena
Se ha creado un paisaje con varios elementos generados de manera procedural: unas
montaas, una playa, un mar y un planeta. Adems en la escena se presentan otros
objetos no procedurales como el cielo, unos pjaros y varias palmeras.
Los objetos procedurales se crean usando varias octavas de ruido de Perlin que se
suman para dar lugar a un fractal que calcule cierto valor: la altura de un vrtice para la
playa y la montaa, la posicin completa de un vrtice en el caso del agua y el color del
planeta. En todos ellos los datos de la funcin fractal se han ajustado para conseguir las

26

distintas formas naturales por ensayo y error, pues es la mejor manera para conseguirlos,
ya que con solo las funciones matemticas y sus factores no es fcil prever el resultado.
Los 3 primeros elementos parten originalmente de 3 planos distintos y a partir de ellos
se calculan los 3 fractales, que se superponen para crear el paisaje, como se ve en las
figuras 14, 15 y 16. Aunque es la manera ms costosa, es la nica forma de conseguir
intersecciones realistas entre las distintas partes.

Figura 14: Escena con un solo fractal

Figura 15: Escena con 2 fractales

27

Figura 16: Escena con los 3 fractales


A continuacin se describen todos los elementos que componen la escena final, que
puede verse en la figura 17:

Figura 17: Escena completa

2. 3. 1. Montaas y playa
Las montaas se calculan inicialmente a partir de un plano dividido en tringulos. Un
fractal bsico con 10 octavas de ruido de Perlin en 2 dimensiones se utiliza para calcular
la altura de cada vrtice, la cual se escala para obtener el tamao deseado [16]. Tras
haber obtenido las nuevas posiciones de cada vrtice debemos calcular las normales en
cada uno de ellos para que luego la visualizacin sea posible.

28

La playa se calcula de manera similar, con 8 octavas de ruido de Perlin que nos dan la
altura del vrtice.
Al hacer los clculos de la altura guardamos informacin de todos aquellos vrtices que
superen una altura lmite. Estos datos se utilizan durante el clculo del agua para reducir
operaciones, ya que en esos puntos el nivel del agua siempre estar por debajo de los
otros elementos y no se ver, por lo que no necesitamos hacer la simulacin.
Estos pasos se realizan en la GPU en dos compute shaders, uno para el clculo de la
altura y otro para el de las normales. Se ejecutan al inicio de la aplicacin ya que nos
basta con hacerlos una vez. Como ambos objetos son planos divididos en vrtices
aprovechamos esta disposicin y organizamos los threads de la GPU en 3 dimensiones
como dos planos de igual tamao, mostrados en la figura 18. Cada grupo se compone de
un nico thread ya que no necesitamos una organizacin ms compleja y a cada hilo se
le asigna un vrtice.
Gracias a esta disposicin podemos tener todos los ncleos de la unidad grfica
trabajando en paralelo, cada uno con un vrtice distinto, algo que en una CPU debera
hacerse de manera secuencial y tardara ms.

Figura 18: Clculo del fractal de la playa y las


montaas

2. 3. 2. Agua
De nuevo partimos de un plano de tringulos cuyos vrtices se van moviendo con el
tiempo. Ya que debemos actualizarla en cada momento el agua es el componente que
ms influye en el rendimiento de la aplicacin, por eso es importante no calcular zonas
que no se ven, para lo que utilizamos los datos guardados en el paso anterior, o no
aadir el mximo detalle en zonas muy alejadas de la cmara.
Para comenzar se utiliza una funcin sinusoidal para modificar la altura de cada vrtice,
lo que nos da un oleaje base. A continuacin, en funcin de la distancia a la cmara, se
utilizan una o dos octavas de ruido de Perlin en 3 dimensiones que modifican la
posicin del vrtice. Se aade una dimensin respecto a los casos anteriores para utilizar

29

el tiempo como factor dinmico. Adems en este caso no se utiliza directamente el valor
del ruido, sino que se usa la inversa de su valor absoluto para acentuar los bordes.
Para aadir algo ms de detalle se suma otro fractal que simula la influencia del viento.
En su clculo se utilizan 2 octavas de ruido de Perlin distorsionado, es decir,
desplazamos el punto inicial una distancia aleatoria en la direccin (1,1,1) antes de
calcular el valor del ruido. Como obtener esto cada instante incrementara el tiempo de
procesamiento lo calculamos una vez al inicio de la aplicacin y lo guardamos en una
textura. Esto nos obliga a tener un viento fijo en cada posicin, pero los cambios que el
fractal del agua sufre con el tiempo ya otorgan suficiente dinamismo a la superficie.
Tras haber actualizado la posicin de los vrtices debemos calcular la normal igual que
hacemos con la playa y las montaas.
Cuando hacemos los clculos de la posicin tambin guardamos 2 texturas de
informacin. Una de ellas sirve para marcar las zonas de la playa que estn, o han
estado alguna vez, por debajo del nivel de agua y as poder tratarlas como si estuvieran
mojadas. La otra sirve para guardar la distancia que hay entre el nivel de playa y el
agua, que se utilizar para la espuma.
Todos los clculos se hacen en compute shaders en la GPU, cuyos threads se organizan
de manera similar a la comentada en el apartado anterior. En este caso hay un compute
shader inicial para el viento y dos que se ejecutan cada frame para la posicin y las
normales del agua.

2. 3. 3. Planeta
El planeta est representado por una esfera de tringulos que va rotando sobre s misma
y su modelado consta de dos partes, el clculo de la superficie, que es esttica, y el de
las nubes, que son dinmicas.
Para obtener la superficie utilizaremos una tabla de colores que represente cada tipo de
terreno: agua, desiertos, praderas, montaas, etc. Se empieza por utilizar un fractal con 8
octavas de ruido de Perlin en 3 dimensiones que nos da la altura, la cual nos sirve para
separar los ocanos de los continentes. A continuacin se usa otro fractal de 6 octavas
que, junto con la altura previamente calculada y la latitud del punto, nos sirve para
obtener el color que representa nuestro tipo de terreno en funcin del clima. Finalmente,
para evitar que las zonas sean demasiado uniformes y queden poco realistas, utilizamos
un fractal de 5 octavas para motear y distorsionar ligeramente el color. El resultado
puede verse en la figura 19.
Esta parte se hace al inicio de la aplicacin, ya que no vara, en un compute shader.
Como la esfera est organizada en paralelos y meridianos, existiendo vrtices en los
puntos en los que se cortan, disponemos los threads de manera similar, usando la latitud
y la longitud para que cada vrtice sea tratado en un hilo distinto.

30

Figura 20: Planeta con nubes

Figura 19: Superficie del planeta


fractal

El clculo de las nubes se hace cada instante puesto que cambia con el tiempo. Se usa
un fractal de 6 octavas con ruido de Perlin en 3 dimensiones distorsionado, igual que el
viento que empuja el agua. Este valor se usa para interpolar entre el blanco de las nubes
y el color ya calculado en el paso anterior, obteniendo as cielos despejados o zonas
cubiertas, como se observa en la figura 20.
A diferencia de todos los clculos comentados hasta ahora este ltimo se hace
directamente en un pixel shader por dos motivos. El primero es que la esfera est muy
alejada, podramos decir que fuera del planeta que contiene nuestro paisaje, y por eso no
se ilumina de la misma forma, por lo que el color final del pixel es directamente el
calculado. La segunda razn es que en el pixel shader solo es visible una porcin del
planeta, por lo que el nmero total de operaciones para obtener el fractal es menor.

2. 3. 4. Objetos no procedurales
Para recrear el cielo de nuestra escena se usa una esfera, siempre centrada alrededor de
la cmara, a la cual se le aplica una textura que representa un fondo de cielo algo
nublado con una cordillera de montaas rodeando el paisaje [17]. Podemos verlo en la
figura 21. Este objeto tampoco interacciona con la luz de la manera habitual, por lo que
no necesitamos calcular las normales.
Tambin se han aadido varias palmeras para tener una referencia del tamao de la
escena [18]. Tanto los modelos como las texturas aplicadas han sido obtenidos de una
pgina externa1. Las texturas que se aplican a las hojas tienen partes que deben ser
transparentes, por lo que ha sido necesario configurar la pipeline para usar el canal
alpha [19].

http://www.loopix-project.com

31

Figura 21: Cielo


Adems hay unos pocos pjaros, diez, para completar el fondo. Son objetos muy
sencillos, apenas 16 vrtices en el mismo plano, y con posiciones distintas de las alas
que se van intercambiando en el tiempo para crear la animacin de vuelo, como se
muestra en la figura 22.

Figura 22: Animacin de los pjaros


Cada pjaro tiene informacin de 3 posiciones, incluida la inicial, obtenidas de manera
aleatoria y que marcan su camino. Sabiendo la posicin actual y la prxima podemos
hacer que se muevan por el paisaje en una linea recta que cambia cuando el pjaro
alcanza su meta. Debido a su sencillez tampoco es necesario calcular sus normales.

2. 3. 5. Resto de los elementos de la escena


Adems de los objetos que se ven hay otros elementos que componen la escena y que
pasamos a comentar en este apartado.

Cmara: por supuesto es necesaria una cmara para observar la escena. Es


posible usar el teclado para girarla y desplazarla. Tambin se han precalculado
dos trayectorias para observar la escena completa.

Iluminacin: la escena est iluminada por una luz direccional que simula la
procedente de un sol lejano, adems de existir una luz ambiental para evitar
zonas de total oscuridad. De la misma manera que con la cmara es posible
cambiar la direccin de la luz utilizando el teclado. Adems en el pixel shader se
usa el modelo de iluminacin de Phong, que usa las 3 componentes tpicas para
calcular la interaccin de la luz con un objeto: luz ambiental, luz difusa y luz
especular.

32

Materiales y texturas: las montaas, la playa, diferenciada en funcin de las


zonas secas y las mojadas, y el agua, con zonas de espuma, estn formadas por
materiales distintos que sirven para definir el color de cada objeto y algunos
factores que indican como interaccionan con la luz. Adems las montaas y la
playa tienen texturas, descargadas de pginas gratuitas2 3 4, que sirven para
definir el color de cada pxel y para aplicar bump mapping, modificando el valor
de la normal, y obtener mayor realismo [20].

Sombras: el sombreado de la escena se hace con un sencillo mapa de sombras


que se calcula cada vez que movemos la luz [21]. Posteriormente, cuando
estamos renderizando la escena y queremos ver si un pixel est iluminado o no
solo hay que acceder a dicho mapa. Para evitar que queden sombras muy
marcadas tambin se utiliza el valor en los pxeles vecinos, interpolando y
suavizando as los bordes [22].

Sonido: adems de los componentes visuales se han aadido un par de sonidos


que representan el mar y las gaviotas. Para esto se ha utilizado la API XAudio2
de Microsoft, usada para cargar los sonidos .wav, obtenidos de internet 5, y
reproducirlos en un bucle infinito mientras dure la aplicacin [23].

2. 3. 6. Detalles de la geometra
Salvo los pjaros todos los objetos mostrados por pantalla se definen usando listas de
tringulos. Estas constan de dos partes, una lista de vrtices, que se guarda en un vertex
buffer, y una lista de punteros a los vrtices, guardados en un index buffer. De esta
manera cada 3 ndices tenemos definido un nuevo tringulo y no es necesario repetir los
vrtices que formen parte de varios polgonos a la vez.
El caso de los pjaros es especial porque son objetos muy sencillos. En este caso solo
definimos los vrtices, guardados en un vertex buffer. Los 3 primeros vrtices sirven
para definir el primer tringulo y a partir de ese momento cada nuevo vrtice suma otro
tringulo, formado por este nuevo vrtice y los 2 inmediatamente anteriores.
A continuacin, en la tabla 1, vamos a detallar el nmero de vrtices, ndices y
tringulos de cada uno de los objetos que acabamos de mencionar.

2
3
4
5

http://www.texturex.com
http://www.blendswap.com
http://www.colorburned.com
http://www.soundjax.com

33

Elemento

Vrtices

ndices

Tringulos

Montaas

324.900

1.942.566

647.522

Playa

324.900

1.942.566

647.522

Agua

324.900

1.942.566

647.522

16

14

152.202

955.200

318.400

82

480

160

Palmera 1

1.008

1.008

336

Palmera 2

1.008

1.008

336

Palmera 3

1.008

1.008

336

Palmera 4

1.008

1.008

336

Palmera 5

276

276

92

1.131.452

6.787.686

2.262.702

Pjaro (x10)
Planeta
Cielo

Total:

Tabla 1: Geometra de la escena


En esta tabla podemos observar que la mayora de polgonos se encuentran en los planos
que se utilizan para crear los fractales. Esto es as porque necesitamos suficientes
tringulos para aadir el detalle, ya que no subdividimos la geometra como se hace en
otras aproximaciones para generar objetos procedurales [24]. Como en este proyecto se
pretende simplemente usar la GPU y comprobar sus capacidades el elevado nmero de
polgonos no importa, pero en caso de que necesitramos obtener un framerate estable
suficientemente alto, como en un videojuego, podra ser importante reducir el nmero
de tringulos [25].
Creando un fichero .obj desde la aplicacin y usando un software externo podemos
reducir el nmero de vrtices y comprobar los resultados visualmente, algo que se
muestra en las figuras 23 - 26 con los planos de la montaa y la playa.
En estas figuras se aprecia que es posible reducir el nmero de vrtices y polgonos sin
que se aprecien diferencias a primera vista. Solo cuando bajamos del 25% de datos
originales se empiezan a hacer visibles los tringulos de la malla, aunque en funcin del
detalle que queramos y mediante la aplicacin de texturas y materiales, algo que en el
ejemplo se ha evitado por sencillez, podramos reducir ms el nmero de polgonos y
seguir teniendo un buen resultado visual.

34

Figura 23: Paisaje 100% - 649.800 vrtices

Figura 24: Paisaje 50% - 324.900 vrtices

Figura 25: Paisaje 25% - 162.450 vrtices

35

Figura 26: Paisaje 10% - 64.979 vrtices

2. 4. Anlisis de rendimiento
Una vez finalizada la aplicacin se van a tomar varias medidas de tiempos que nos
permitan ver el comportamiento de la CPU y la GPU en varios equipos distintos.

2. 4. 1. Definicin de la escena
La escena est compuesta por los elementos mencionados en el apartado anterior y,
como a la hora de renderizar la geometra se usan varias llamadas draw distintas para
ejecutar la pipeline grfica, vamos a mostrar la siguiente informacin agrupada de esta
manera. Para cada llamada se indicarn los polgonos dibujados y el espacio en
memoria de la GPU, en bytes, que ocupan todos los datos de entrada necesarios: buffers
de vrtices e ndices, programas shaders, resto de buffers y texturas.
Las tablas 2 - 5 muestran cada llamada en el orden en que se ejecutan.

Cielo: tabla 2

Tringulos dibujados

160

Tamao del Vertex Buffer

5.576 B

Tamao del Index Buffer

1.920 B

Tamao del Vertex Shader

15.256 B

Tamao del Pixel Shader

14.512 B

Tamao de los buffers constantes

192 B

Tamao de las texturas

66.354.240 B

Total de memoria de video usada

66.391.696 B

Tabla 2: Llamada draw 1

36

Planeta: tabla 3

Tringulos dibujados

318.400

Tamao del Vertex Buffer

10.825.736 B

Tamao del Index Buffer

3.820.800 B

Tamao del Vertex Shader

19.660 B

Tamao del Pixel Shader

46.536 B

Tamao de los buffers constantes

208 B

Tamao de las texturas

4.288 B

Total de memoria de video usada

14.717.228 B

Tabla 3: Llamada draw 2

Pjaro: tabla 4

Tringulos dibujados

14

Tamao del Vertex Buffer

1088 B

Tamao del Index Buffer

0B

Tamao del Vertex Shader

15.108 B

Tamao del Pixel Shader

14.336 B

Tamao de los buffers constantes

192 B

Tamao de las texturas

0B

Total de memoria de video usada

30.724 B

Tabla 4: Llamadas draw 3 -12

Montaas, playa, agua y palmeras: tabla 5

Tringulos dibujados

1.944.002

Tamao del Vertex Buffer

66.572.544 B

Tamao del Index Buffer

23.328.024 B

Tamao del Vertex Shader

23.720 B

Tamao del Pixel Shader

33.992 B

Tamao de los buffers constantes

464 B

Tamao de las texturas

335.229.192 B

Total de memoria de video usada

425.187.936 B

Tabla 5: Llamada draw 13

37

Podemos ver que la ltima llamada es la que ms memoria consume y, por tanto, en la
que nos deberamos fijar si queremos disminuir el espacio a ocupar, no solo en
polgonos, como ya hemos mencionado anteriormente, sino tambin en el nmero de
texturas y su resolucin. En este caso los datos de entrada ocupan unos 400 MB, por lo
que en GPUs con poca memoria podra aparecer la necesidad de mover datos entre la
memoria grfica y la principal del sistema, con el consecuente tiempo adicional.
Otra posible opcin sera dividir la ltima en varias llamadas distintas, cada una ms
pequea que la original, puesto que hay objetos distintos. La pega de esta solucin es
que aade ms operaciones en la CPU, ya que hay cambiar ms veces de contexto, y
esto puede ser el cuello de botella de la aplicacin.

2. 4. 2. Equipos
Se han utilizado 4 equipos distintos para realizar las pruebas, los tres primeros de
sobremesa y uno ltimo porttil, que vamos a definir en funcin de su CPU, GPU y
memoria RAM, ya que son los componentes que ms pueden influir en los resultados.
En la tabla 6 tenemos las especificaciones de todos ellos.
Equipo 1

Equipo 2

Equipo 3

Equipo 4

Intel Core
i7-4770

Intel Core
i7-2600

AMD Phenom
II X4 955

Intel Core
i5-430M

Ncleos

Threads

Frecuencia

3,40 GHz

3,40 GHz

3,20 GHz

2,27 GHz

Cach L1

4 x 64 KB

4 x 64 KB

4 x 128 KB

2 x 64 KB

Cach L2

4x 256 KB

4x 256 KB

4 x 512 KB

2 x 256 KB

Cach L3

8 MB

8 MB

6 MB

3 MB

NVIDIA
GeForce GTX
660

NVIDIA
GeForce GTX
570

AMD
Radeon HD
6850

ATI Mobility
Radeon HD
5470

960

480

960

80

980 MHz

732-1464 MHz
grficos-shaders

775 MHz

750 MHz

Tamao VRAM

2 GB DDR5

1,25 GB DDR5

1 GB DDR5

512 MB DDR5

Ancho de banda

144,2 GB/s

152 GB/s

128 GB/s

24,6 GB/s

RAM

8 GB DDR3

6 GB DDR3

8 GB DDR3

4 GB DDR3

Ancho de banda

12.800 MB/s

12.800 MB/s

12.800 MB/s

8.500 MB/s

CPU

GPU

Ncleos
Frecuencia

Tabla 6: Equipos de prueba


Debemos comentar la particularidad de la GPU del equipo 2, ya que en ella los
procesadores de shaders funcionan a una frecuencia distinta que el resto de la unidad, en
este caso el doble.

38

2. 4. 3. Pruebas
Para realizar las pruebas van a recolectarse datos sobre el tiempo de inicio de la
aplicacin, con operaciones ejecutadas en la CPU, y de varios tiempos obtenidos de dos
vistas distintas de la escena, calculadas en la GPU. Para obtener los datos de la unidad
grfica usamos la interfaz Query de Direct3D 11, que permite obtener informacin
sobre el estado de la ejecucin de la tarjeta grfica [26].
Estos son los datos recogidos:

Tiempo de inicio de la aplicacin en segundos (CPU).


Tiempo total de un frame en milisegundos (GPU).
Tiempo de clculo del agua de un frame milisegundos (GPU).
Tiempo de renderizado de un frame en milisegundos (GPU).

En todos los equipos se harn pruebas usando la CPU y la GPU en conjunto as como
con la CPU en solitario, ya que Direct3D permite que un procesador normal simule el
funcionamiento de una unidad grfica. Aunque es posible implementar nuestro propio
software de virtualizacin Microsoft ofrece uno en el propio SDK de DirectX, conocido
como Windows Advanced Rasterization Platform (WARP), que es el que usaremos [27].
En cuanto a las imgenes escogidas, se ha elegido una vista area del paisaje, que podra
encajar en una escena de una pelcula o un videojuego, y otra ms alejada donde se ven
todos los elementos pero donde tambin se observan los lmites del propio paisaje.
Cada vista est definida por los siguientes factores, que tambin se obtienen usando la
interfaz Query :

Vrtices de entrada a la pipeline


Tringulos de entrada a la pipeline
Invocaciones de Vertex Shaders
Invocaciones de Pxel Shaders
Tringulos dibujados

A continuacin, en las figuras 27 y 28, se muestran y especifican ambas escenas:

39

Figura 27: Escena 1


Vrtices de entrada: 6.787.846
Tringulos de entrada: 2.262.702
Ejecuciones de Vertex Shaders: 2.269.388
Ejecuciones de Pixel Shaders: 3.245.677
Tringulos dibujados: 1.886.400

Figura 28: Escena 2


Vrtices de entrada: 6.787.846
Tringulos de entrada: 2.262.702
Ejecuciones de Vertex Shaders: 2.269.388
Ejecuciones de Pixel Shaders: 1.915.028
Tringulos dibujados: 2.262.568
40

El primer factor puede llevar a confusin ya que al detallar la geometra de la escena


hemos dicho que sta se haca con 1.131.452 vrtices, mientras que aqu tenemos 6
veces esa cantidad. Esto se debe a que la pipeline cuenta cada vrtice que entra, aunque
estn repetidos. De hecho el nmero de vrtices coincide exactamente con el nmero de
vrtices de los pjaros ms el nmero de ndices del resto de objetos, ya que cada uno de
ellos hace referencia a un vrtice.
Ambas imgenes tienen una resolucin de 1280 x 720, por lo que en total hay 921.600
pxeles. No obstante en las dos vistas se hacen ms invocaciones a pixel shaders de las
estrictamente necesarias ya que distintos objetos pueden situarse sobre el mismo pixel,
aunque finalmente solo uno se muestre.
La segunda escena contiene ms tringulos pero estos ocupan menos pxeles de la
imagen ya que los objetos se ven ms pequeos, por lo que sern necesarias menos
invocaciones de pxel shaders. Por eso esperamos que los tiempos obtenidos sean
menores, poniendo de manifiesto el tiempo que consume el clculo del color de un
pxel.

2. 4. 4. Tiempos de inicio
En la figura 29 puede verse el tiempo en segundos necesario para iniciar la aplicacin, o
lo que es lo mismo, crear todos los objetos necesarios durante la ejecucin de la
pipeline. Se presentan los resultados cuando el dispositivo a ejecutar los comandos
Direct3D es la GPU y cuando es la CPU.

Figura 29: Tiempo de inicio (s)


Observamos que iniciar el dispositivo cuando ste es el procesador principal cuesta algo
ms por el hecho de tener que cargar el software de virtualizacin WARP, que ya hemos
mencionado.

2. 4. 5. Clculo y renderizado en la GPU


Podemos ver en la figura 30 los tiempos obtenidos en ambas escenas usando la GPU. Se
observa como el clculo del agua se lleva la mayor parte del tiempo del clculo del
frame, siendo algo menos en la segunda escena gracias a las medidas comentadas en el
apartado 2.3.2: no es necesario aadir el mximo detalle en zonas muy alejadas de la

41

cmara. Tambin podemos comprobar como el menor nmero de ejecuciones de pixel


shaders reduce el tiempo de renderizado.

Figura 30: Tiempos en la GPU (ms)

2. 4. 6. Clculo y renderizado en la CPU


En la figura 31 se presentan los tiempos necesitados por la CPU para realizar las
mismas operaciones. Ahora es la etapa de renderizado, con gran diferencia, la que ms
tiempo consume. Esto es as porque en ella se realizan los clculos ms especializados
mientras que el clculo del agua, de tipo ms general, encaja mejor con un procesador
corriente.

42

Figura 31: Tiempos en la CPU (ms)

2. 4. 7. Clculo y renderizado GPU vs CPU


La figura 32 muestra una comparacin de los tiempos obtenidos para la escena 1 en la
GPU y la CPU. Podemos observar como los tiempos son mucho menores cuando
usamos la unidad grfica gracias a que todos sus ncleos pueden trabajar en paralelo.
No obstante, y como ya hemos mencionado, la mejora es menos patente en los shaders
de clculo, 1,5 3 veces ms rpido, puesto que no es el objetivo con el que las tarjetas
grficas se disean, aunque tambin es algo que empieza a considerarse por los
fabricantes. Es en la pipeline grfica donde se observa un mayor impacto, consiguiendo
un ratio de mejora comprendido entre 50 y 200.
La GPU nos permite obtener un framerate adecuado en los dos primeros equipos, 40 en
el ms potente y 30 en el segundo, aunque el equipo 3 se queda en solo 20 y el cuarto, el
porttil, apenas llega a 4 fps.
Sin embargo la CPU no permite en ningn caso alcanzar un ratio de refresco
suficientemente alto como para que no sea evidente al ojo.

43

Figura 32: Tiempos escena 1 GPU vs CPU (ms)


Si comparamos entre equipos se ve como las tarjetas grficas se comportan segn lo
esperado, siendo la GTX 660 la ms potente y la que mejores resultados obtiene. Cabe
mencionar que no podemos medir la potencia solo por el nmero de ncleos y su
frecuencia, dados en este mismo apartado, ya que el diseo de cada ncleo vara entre
fabricantes y arquitecturas. Es por eso que la GTX 570, con la mitad de ncleos que la
HD 6850, aunque al doble de frecuencia, se comporta significativamente mejor en la
etapa de clculo. La tarjeta grfica del porttil es la que peores resultados da debido a su
bajo nmero de ncleos y su menor frecuencia. Incluso el tamao de la memoria
influye, ya que sus escasos 512 megas obligan a que aumente el flujo de datos entre
CPU y GPU.
En cuanto a la CPU, podramos hacer una lectura similar de los resultados.

2. 5. Integracin en UDK
Con objeto de demostrar que el uso de shaders es de inmediata aplicacin al mundo de
los videojuegos, parte del trabajo realizado se ha integrado en una escena creada con el
entorno de desarrollo del motor Unreal.

2. 5. 1. Ruido y materiales
Para usar nuestro ruido de Perlin debemos utilizar el editor de materiales, que usa una
red de nodos para crear cada material [28]. Este editor ofrece varios tipos de nodos,
cada uno con un cdigo HLSL asociado y que se van uniendo hasta formar el cdigo
final de los shaders [29]. Entre estos tipos de nodos existe uno que nos permite escribir
nuestras propias instrucciones en HLSL y que se combina con el resto de la misma
manera. Hay que tener en cuenta que este editor tiene sus particularidades y no es tan

44

simple como copiar y pegar desde nuestra aplicacin. Para empezar solo pueden
construirse vertex y pixel shaders, no es posible utilizar compute shaders. Esto nos
impide precalcular y guardar algunos datos, de manera que los clculos se repiten cada
pasada. Adems cada nodo personalizado solo puede contener una funcin, por lo que
las llamadas a otras funciones deben sustituirse por el cdigo entero o hacerlas en otros
nodos anteriores y propagar los resultados hacia delante. Tambin debemos mencionar
que el editor solo acepta texturas con tamaos que sean potencia de dos y que sigan el
formato clsico RGBA, por lo que cualquier otro tipo de textura debe ser adaptado.
Tras estas consideraciones pasamos a mostrar nuestra implementacin del ruido de
Perlin en 3 dimensiones. Aprovechando que el editor ofrece un recuento de las
instrucciones de cada material se ha hecho una versin que tiene los datos necesarios
para el clculo, permutacin y gradientes, como variables dentro del propio cdigo y
otra con ellos guardados en texturas. En la figura 33 se observan los resultados
obtenidos.

Figura 33: Ruido de Perlin en UDK


Podemos comprobar como el uso de texturas agiliza la ejecucin de nuestro cdigo, en
este caso se reduce en 263 instrucciones, menos de la mitad que en el original. Aunque
tambin habra que tener en cuenta el tiempo necesario para procesar cada una, es un
buen indicador de la complejidad y el tiempo total que se necesitar. Esta mejora se
consigue gracias al hardware especializado para el manejo de texturas que las GPU
actuales tienen debido a que se usan muy a menudo.

2. 5. 2. Escena
Tras la implementacin, para obtener cualquier fractal que queramos integrar en nuestra
escena solo hay que crear un material que sume varias octavas de ruido y aplicarlo a un
objeto. Como ejemplo se ha decidido usar el fractal del planeta aplicado a una bola del
mundo que va rotando y cuyo modelo se ha conseguido en internet 6, que se ha integrado
6

http://www.3delicious.net/

45

en un mapa ya existente y que viene con el motor: Epic Citadel, usado por Epic como
demo tcnica. El resultado final puede verse en la figura 34.

Figura 34: Escena UDK

46

3. CONCLUSIONES
En este ltimo apartado de la memoria se analizan los resultados obtenidos y si se han
cumplido los objetivos, se indican posibles lneas de trabajo a seguir en el futuro y se
realiza una valoracin personal del PFC.

3. 1. Resultados obtenidos
Los objetivos marcados al inicio del proyecto se han conseguido. Hemos podido crear
un paisaje completo usando algoritmos fractales que utilizan ruido de Perlin. Esto nos
ha permitido comprender como se implementan y utilizan distintos tipos de ruido y el
potencial de algoritmos fractales para la generacin de elementos naturales.
Adems se han estudiado las caractersticas de Direct3D, tanto a nivel de grficos como
de clculo general, viendo as como se organiza la API, su flexibilidad y su relacin con
los elementos del hardware.
Los resultados obtenidos en el anlisis de rendimiento nos han ofrecido una visin de la
potencia de las unidades grficas y nos han permitido comprobar de primera mano por
qu su uso para clculo general ha cobrado fuerza y as lo sigue haciendo cada da que
pasa.
Tambin hemos conseguido implementar nuestro algoritmo de ruido dentro del entorno
de desarrollo del motor Unreal, demostrando que los conocimientos adquiridos pueden
adaptarse y aprovecharse en casi cualquier otro tipo de aplicacin, en este caso del
mundo de los videojuegos.

3. 2. Lneas futuras
Tras finalizar el proyecto surgen ideas sobre como se podra continuar trabajando en el
mismo mbito en el futuro.
Una de estas ideas es el uso de la pipeline de teselado, caracterstica nueva en Direct3D
11, en la generacin del paisaje. Ya que las tarjetas grficas modernas implementan la
divisin de polgonos por hardware podra ser interesante reducir la resolucin de la
malla a la hora de calcular los fractales, disminuyendo as el tiempo necesario, algo que
se notara especialmente en los objetos dinmicos como el agua, que deben calcularse
constantemente. Con la malla subdividida podramos aadir ms detalle usando algn
mapa de desplazamiento, que variara en funcin de la distancia y as poder ahorrar
espacio en la memoria de la GPU.
Tambin sera posible mejorar el rendimiento de los compute shader. En el caso del
clculo de las posiciones cada vrtice se trata de manera aislada y no hay posibilidad de
mejorar la comunicacin con los vecinos, ya que es inexistente, pero cuando calculamos
las normales podramos utilizar grupos de threads, que comparten un espacio en
memoria. Esto nos permitira calcular las normales de un tringulo y guardar la

47

informacin en la memoria compartida, reduciendo el nmero de clculos repetidos y el


tiempo de acceso a los datos necesarios.
Adems sera interesante traducir la implementacin de nuestro ruido y los fractales al
sistema de materiales de UDK, usando siempre nodos predefinidos en vez de escribir
nuestro propio cdigo. Aunque la red de nodos final sera ms compleja el editor est
desarrollado para trabajar con estos y genera cdigo HLSL optimizado, a diferencia del
que indiquemos directamente nosotros, que se traduce tal cual a los shaders finales.

3. 3. Valoracin personal
La realizacin de este proyecto me ha permitido aplicar muchos de los conocimientos
adquiridos a lo largo de estos 5 aos de carrera, suponiendo la culminacin de un largo e
importante periodo de mi vida, el cual me marcar durante los aos que estn por llegar.
Adems me ha otorgado la oportunidad de estudiar, comprender y trabajar con
herramientas que se usan en el mundo actual, concretamente con tecnologas que se
usan en el mundo de los videojuegos, donde espero poder trabajar. De especial utilidad
creo que van a ser los conocimientos adquiridos sobre Direct3D y, sobretodo, las
pipelines grfica y computacional, ya que es algo ms reciente y que cada vez se usa
ms, por lo que acabar la carrera habiendo usado stas puede suponer una diferenciacin
positiva de cara al futuro.
No obstante el hecho de que sean tecnologas propietarias tiene sus pegas. Aunque sean
las dominantes en la situacin actual del mercado y por eso es importante conocerlas y
saber usarlas, la comunidad de software libre, y en concreto la de OpenGL, suele ser
mucho ms participativa, por lo que es ms fcil encontrar documentacin y ayuda ante
los problemas. La parte positiva de esto es que hemos aprendido a manejarnos con la
documentacin de Microsoft, que, aunque sea ms escueta y en ocasiones parezca
escasa, es la oficial y por tanto la que se debera usar como referencia.
Finalmente, ha sido interesante ver el funcionamiento de un motor de videojuegos y
como sus componentes trabajan en conjunto para crear el producto final. Es una pena
que los kits de desarrollo de motores conocidos y potentes que se ofrecen de manera
gratuita no permitan acceder al cdigo del motor. Aunque es algo comprensible ya que
las compaas ponen muchos recursos en su desarrollo me hubiera gustado estudiar sus
partes internas con ms detalle.

48

4. BIBLIOGRAFA
[1] Unity License Comparisons
http://unity3d.com/unity/licenses
[2] CryEngine Overview
http://mycryengine.com/?conid=2
[3] Unreal Engine Features
http://www.unrealengine.com/en/features/
[4]: Jason Zink, Matt Petineo, Jack Hoxley (2011). Practical Rendering & Computation
with Direct3D 11. CRC Press
[5] The World's First Fractal Movie - "Vol Libre" 1979 - Loren Carpenter
http://www.liveleak.com/view?i=b75_1371314878
[6]: Benoit B. Mandelbrot (1982). The Fractal Geometry of Nature. W. H. Freeman and
Company
[7] The First Completely Computer-Generated (CGI) Cinematic Image Sequence in a
Feature Film
http://www.historyofinformation.com/expanded.php?id=3584
[8] Making Noise
http://www.noisemachine.com/talk1/
[9]: David S. Ebert, F. Kenton Musgrave, Darwyn Peachey, Ken Perlin, Steven Worley
(2002). Texturing & Modelling: A Procedural Approach. Third edition. Morgan
Kaufman Publishers
[10] The Perlin noise math FAQ
http://webstaff.itn.liu.se/~stegu/TNM022-2005/perlinnoiselinks/perlin-noise-mathfaq.html
[11] Procedural Noise Categories
http://physbam.stanford.edu/cs448x/old/Procedural_Noise%282f%29Categories.html
[12]: Matt Pharr, Randima Fernando, Tim Sweeney (2005). GPU Gems 2:
Programming Techniques for High-Performance Graphics and General-Purpose
Computation. Addison-Wesley Professional
[13] MSDN: Direct3D 11 Graphics
http://msdn.microsoft.com/en-us/library/windows/desktop/ff476080(v=vs.85).aspx
[14] MDSN: HLSL
http://msdn.microsoft.com/en-us/library/windows/desktop/bb509561(v=vs.85).aspx

49

[15] Dark Secrets of Shader Development or What Your Mother Never Told You About
Shaders
http://developer.amd.com/wordpress/media/2012/10/Dark_Secrets_of_shader_DevMojo.pdf
[16] Scape 2: Procedural Basics
http://www.decarpentier.nl/scape-procedural-basics
[17] DirectX 11 Skybox
http://www.braynzarsoft.net/index.php?p=D3D11CUBEMAP
[18] Direct3D 11: Loading Static 3D models
http://www.braynzarsoft.net/index.php?p=D3D11OBJMODEL
[19] DirectX 10: Blending and Alpha Blending
http://takinginitiative.wordpress.com/2010/04/09/directx-10-tutorial-6-transparencyand-alpha-blending/
[20] Direct3D 11 Normal (Bump) Maps
http://www.braynzarsoft.net/index.php?p=D3D11NORMMAP
[21] DirectX10: Shadow Mapping
http://takinginitiative.wordpress.com/2011/05/15/directx10-tutorial-10-shadowmapping/
[22]: Randima Fernando, David Kirk (2004). GPU Gems: Programming Techniques,
Tips and Tricks for Real-Time Graphics. Addison-Wesley Professional
[23] MSDN: XAudio2 APIs
http://msdn.microsoft.com/en-us/library/hh405049(v=vs.85).aspx
[24] Procedural Shape Synthesis on Subdivision Surfaces
http://lvelho.impa.br/spd/spd.pdf
[25] Beautiful, Yet Friendly Part 1: Stop Hitting the Bottleneck
http://www.ericchadwick.com/examples/provost/byf1.html
[26] MSDN: ID3DQuery interface
http://msdn.microsoft.com/en-us/library/windows/desktop/ff476578(v=vs.85).aspx
[27] MSDN: Windows Advanced Rasterization Platform (WARP) Guide
http://msdn.microsoft.com/en-us/library/windows/desktop/gg615082(v=vs.85).aspx
[28] Material Editor User Guide
http://udn.epicgames.com/Three/MaterialEditorUserGuide.html
[29] Materials Compendium
http://udn.epicgames.com/Three/MaterialsCompendium.html

50

II ANEXOS

ANEXO A: GESTIN DEL PROYECTO


En este anexo se explican la metodologa y planificacin seguidas para el desarrollo del
proyecto y las herramientas utilizadas.

A. 1. Planificacin
El desarrollo se ha dividido en 5 fases distintas. La primera ha sido el estudio de las
herramientas y tcnicas que bamos a usar.
El siguiente paso ha sido implementar la creacin del paisaje fractal usando C++ y el
entorno de desarrollo Visual Studio 2013. Se ha seguido un desarrollo iterativo e
incremental que ha permitido partir de una idea bsica de lo que queramos hacer, el
paisaje, para ir refinando el objetivo conforme avanzbamos y aadamos
caractersticas. Adems de esta manera podemos modificar los elementos ya existentes
conforme agregamos nuevos. El lmite de los detalles adicionales implementados viene
marcado por el tiempo disponible, ya que tambin debamos finalizar el resto del
proyecto antes de la fecha lmite marcada y podramos haber seguido aadiendo ms
elementos a la escena.
Posteriormente se ha estudiado el desempeo de la aplicacin en la CPU y la GPU,
analizando el rendimiento en ambos casos.
A continuacin se ha implementado el ruido de Perlin en el entorno UDK para poder
crear un fractal. Tambin hemos seguido un desarrollo iterativo e incremental, aunque
con pocas iteraciones y ms cortas que en la creacin de la escena principal.
Por ltimo se ha escrito la memoria y preparado la presentacin del proyecto.
En la tabla 7 pueden verse las distintas tareas planificadas, su duracin y el tiempo en
horas dedicado para su finalizacin.
Descripcin

Fecha inicio

Fecha fin

Dedicacin (h)

Estudio de tcnicas y
herramientas

1/09/2013

8/10/2013

100

Creacin de la escena

9/10/2013

16/02/2014

195

Anlisis de rendimiento

3/02/2014

10/02/2014

35

Integracin en UDK

24/01/2014

5/02/2014

30

Escribir memoria y anexos

1/10/2013

19/02/2014

90

Preparar presentacin

21/02/2014

10/03/2014

30

Total

1/09/2013

10/03/2014

480

Tabla 7: Dedicacin

55

A. 2. Herramientas utilizadas
A continuacin, en la tabla 8, se indican las herramientas utilizadas en el desarrollo del
proyecto junto con una breve descripcin.
Herramienta

Descripcin
Sistema Operativo

Windows 7

Sistema operativo utilizado en 3 de los equipos


de prueba.

Windows 8

Sistema operativo de un equipo de prueba.


Desarrollo

Visual Studio 2013

IDE para escribir el cdigo de la aplicacin


principal, los shaders y su depuracin.

Unreal Development Kit (Julio 2013) Entorno de desarrollo del motor Unreal para
integrar el ruido en una escena.
DirectX SDK (Junio 2010)

Bibliotecas para trabajar con DirectX.


Grficos

CrazyBump 1.2

Herramienta para generar normal maps a partir


de una imagen.

3DS Max 2014

Software de creacin de grficos, usado para


leer la malla del paisaje y modificar su
resolucin.

Vue xStream 9.5

Aplicacin para generar las texturas del cubo


del cielo.

Microsoft DirectX Texture Tool

Herramienta para agrupar las texturas del cielo


en un solo archivo.

Paint

Edicin de imgenes.
Gestin

Google Drive

Copias de seguridad, control de cambios y


sincronizacin entre ordenadores.
Documentacin

LibreOffice 4.2.0 Writer

Memoria del proyecto y anexos.

LibreOffice 4.2.0 Calc

Anlisis de rendimiento.

LibreOffice 4.2.0 Impress

Presentacin del PFC.

LibreOffice 4.2.0 Draw

Creacin de imgenes

DoxyGen 1.8.6

Documentacin de la aplicacin.
Otros

FRAPS 3.5.99

Captura de imgenes y video. Control de


framerate.

Tabla 8: Herramientas utilizadas


56

ANEXO B: COMPARACIN DE MOTORES


En este anexo se realiza una comparacin entre varios motores grficos de videojuegos,
potentes y disponibles para PC de manera gratuita. Aunque existen muchas opciones
diferentes solo nos vamos a centrar en 3 de los motores ms famosos y utilizados:
Unreal Development Kit, CryEngine 3 y la versin gratuita de Unity.

B. 1. Herramientas disponibles
En este apartado se van a comparar las distintas herramientas que ofrecen los motores y
sus diferentes caractersticas. Para ello stas sern listadas y se presentar una tabla que
permite hacer la comparacin de manera rpida y sencilla.

B. 1. 1. Animacin
1.
2.
3.
4.
5.
6.
7.
8.

Animacin basada en esqueletos.


Huesos que pueden influenciar cada vrtice.
Asociacin de objetos externos con alguna parte del esqueleto.
Transicin entre animaciones distintas.
Cinemtica inversa.
Animaciones grupales.
Animacin morph-target.
Animacin facial.

Caracterstica

UDK

CryEngine 3

Unity

Tabla 9: Motores. Animacin

57

B. 1 . 2. Audio
1.
2.
3.
4.
5.
6.

Control de volumen, atenuacin o tono.


Algoritmos de compresin y descompresin.
Audio 3D.
Multi-canal.
Control de uso de recursos.
Filtros.

Caracterstica

UDK

CryEngine 3

Unity

Hasta 5.1

Hasta 7.1

Hasta 7.1

Tabla 10: Motores. Audio

B. 1. 3. Cinemticas
1.
2.
3.
4.

Key-frames para actores y objetos.


Manejo de cmaras y otros objetos.
Control de bucles, velocidad, audio y partculas.
Efectos de post-procesado.

Caracterstica

UDK

CryEngine 3

Unity

Tabla 11: Motores. Cinemticas

B. 1 . 4. Networking
1. Soporte para conexin LAN e Internet.
2. Modelo cliente-servidor.
3. Descarga y cach de contenidos automticas.
Caracterstica

UDK

CryEngine 3

Unity

Tabla 12: Motores. Networking

58

B. 1. 5. Editor
1.
2.
3.
4.

Integracin del resto de herramientas.


Gestor de contenidos.
Renderizado completo para ver el aspecto final del juego.
Posibilidad de jugar desde el editor para comprobaciones rpidas.

Caracterstica

UDK

CryEngine 3

Unity

Tabla 13: Motores. Editor

B. 1. 6. Fsicas
1.
2.
3.
4.
5.
6.
7.
8.

Rigid bodies, soft bodies y ragdoll.


Combinacin de fsicas con animaciones.
Simulacin de multitudes.
Destruccin de escenarios y objetos.
Simulacin de ropas.
Simulacin de fluidos.
Campos de fuerza.
Sistema de partculas.

Caracterstica

UDK

CryEngine 3

Unity

Tabla 14: Motores. Fsicas

59

B. 1. 7. Iluminacin
1.
2.
3.
4.
5.
6.
7.
8.
9.

Iluminacin global.
Ambient occlusion.
Iluminacin per-pixel.
Luces dinmicas.
Luces precalculadas.
Reflejos en tiempo real.
Sombras dinmicas.
Sombras precalculadas.
Deferred Lighting.

Caracterstica

UDK

CryEngine 3

Unity

Tabla 15: Motores. Iluminacin

B. 1. 8. Inteligencia artificial
1.
2.
3.
4.

Grafos de navegacin.
Generacin automtica de caminos.
Bsqueda de caminos.
Obstculos y restricciones.

Caracterstica

UDK

CryEngine 3

Unity

Tabla 16: Motores. Inteligencia Artificial

60

B. 1. 9. Programacin
1. Lenguaje de programacin usado.
2. Paradigma.
3. Acceso al cdigo del motor.
4. Atributos especficos de las clases para juegos.
5. Sensible a maysculas.
6. Herencia.
7. Manejo de excepciones.
8. Sobrecarga de funciones.
9. Sobrescritura de funciones.
10. Sobrecarga de operadores.
11. Sobrescritura de operadores.
12. Recolector de basura y creacin/destruccin de objetos de manera automtica
13. Comprobacin de tipos.
Caracterstica

UDK

CryEngine 3

Unity

UnrealScript

C++ ( y Lua)

C # (Javascript y
Boo)

Orientado a objetos

Orientado a objetos

Orientado a objetos

Indirecto

Indirecto

Indirecto

Estados, tiempo y
red

Simple

Simple y mltiple

Simple

10

11

12

13

Tabla 17: Motores. Programacin

61

B. 1. 10. Renderizado
1. Direct3D.
2. OpenGL.
3. HDR de 64-bit.
4. Modelo de iluminacin.
5. Teselado.
6. Correccin gamma.
7. Normal mapping.
8. Depth of field.
9. Filtros anisotrpicos.
10. Desplazamientos.
11. Atenuacin.
12. Niebla.
13. Texturas.
14. Efectos de post-procesado.
15. Distintos niveles de detalle.
Caracterstica

UDK

CryEngine 3

Unity

9 y 11

9, 10 y 11

9 y 11

Solo la versin IOs

Phong

Phong

Phong / Gouraud

10

11

12

13

14

15

Tabla 18: Motores. Renderizado

62

B. 1. 11. Shaders y materiales


1.
2.
3.
4.
5.
6.
7.
8.

Editor de materiales.
Factores bsicos.
Funciones para combinar shaders.
Texturas.
Subsurface Scattering.
Creacin automtica de shaders en funcin de la plataforma.
Custom shaders.
Anti-aliasing.

Caracterstica

UDK

CryEngine 3

Unity

Grfico (nodos)

Grfico (rbol)

Cdigo

Difuso, especular,
emisor y opacidad

Difuso, especular,
brillo, emisor y
opacidad

Difuso, especular,
emisor, brillo y
transparencia

Suma

HLSL

HLSL, GLSL y CG

Tabla 19: Motores. Shaders y materiales

B. 1. 12. Terreno
1.
2.
3.
4.
5.
6.

Herramientas para creacin de terrenos exteriores.


Creacin de vegetacin.
Simulacin de erosin y efectos climticos.
Creacin de ros.
Creacin de carreteras y caminos.
Distintos niveles de detalle.

Caracterstica

UDK

CryEngine 3

Unity

Tabla 20: Motores. Terreno

63

B. 1. 13. Otros
1.
2.
3.
4.
5.
6.
7.

Distribucin de tareas entre mltiples ncleos.


Visual scripting.
Creacin de mens e interfaces.
Documentacin disponible.
Plataformas soportadas.
Editor de vehculos.
3D estereoscpico.

Caracterstica

UDK

CryEngine 3

Unity

Windows y IOs

Windows, Xbox 360


y PS3

Windows, Linux,
Mac, Web player,
Xbox 360, PS3,
WiiU, IOs y Android

Tabla 21: Motores. Otros

B. 2. Imgenes comparativas
A continuacin, en las figuras 35 - 46, se presentan algunas imgenes de juegos
comerciales o demostraciones tcnicas creadas con los motores comparados para as
poder comprobar la calidad grfica que se puede obtener con ellos y ver en
funcionamiento las caractersticas comentadas.

64

B. 2. 1. Unreal Development Kit

Figura 35: Muestra UDK 1

Figura 36: Muestra UDK 2

65

Figura 37: Muestra UDK 3

Figura 38: Muestra UDK 4

66

B. 2. 2. CryEngine 3

Figura 39: Muestra CryEngine 1

Figura 40: Muestra CryEngine 2

67

Figura 41: Muestra Cryengine 3

Figura 42: Muestra CryEngine 4

68

B. 2. 3. Unity

Figura 43: Muestra Unity 1

Figura 44: Muestra Unity 2

69

Figura 45: Muestra Unity 3

Figura 46: Muestra Unity 4

70

ANEXO C: LA PIPELINE GRFICA


En este apartado se explica el funcionamiento de la pipeline grfica de Directc3D 11 y
las caractersticas del lenguaje que se usa para la programacin de sus etapas: HLSL.

C. 1. Etapas
En la figura 47 podemos observar la pipeline grfica de Direct3D 11, siendo las etapas
enmarcadas en rectngulos las programables y donde, por tanto, podemos ejecutar
nuestro propio cdigo. Las otras, aunque ms o menos configurables, harn siempre las
mismas operaciones y por ello ofrecen una flexibilidad ms limitada.

Figura 47: Pipeline grfica


Adems hay que considerar que las etapas de teselado, hull shader, tesselator y domain
shader, siempre las 3 juntas, son opcionales y pueden utilizarse segn nos convenga en
la aplicacin. Lo mismo ocurre con el geometry shader y el stream output.
A continuacin se realiza un pequeo resumen de las etapas de la pipeline, haciendo
hincapi en las programables, mostrando sobre qu trabajan y algunos ejemplos de para
qu pueden utilizarse.

C. 1. 1. Input Assembler
La primera etapa es la encargada de construir los vrtices que se utilizarn en el resto de
la pipeline, as como de las uniones entre ellos.

C. 1. 2. Vertex Shader (programable)


Se ejecuta una vez por cada vrtice de la escena y trabaja sobre cada uno de ellos de
manera aislada. Entre las operaciones ms tpicas que realiza est el transformar el
sistema de coordenadas del vrtice o calcular alguna iluminacin sencilla.

C. 1. 3. Hull Shader (programable)


sta es la primera de las etapas de teselado que a partir de los vrtices iniciales,
considerados puntos de control, consigue generar otros nuevos. Se divide en dos
funciones distintas, la primera es la encargada de configurar la siguiente etapa y la otra
se encarga de hacer cualquier modificacin que queramos a dichos puntos.

71

C. 1. 4. Tesselator
Crea una serie de coordenadas en funcin de la configuracin que hayamos indicado en
el paso previo, independientemente de la posicin o cualquier otro atributo de los puntos
de control.

C. 1. 5. Domain Shader (programable)


Utilizando los puntos de control y las coordenadas generadas en la anterior etapa y con
el algoritmo que el programador implemente se crearn los nuevos vrtices para ser
pasados al resto de la pipeline.

C. 1. 6. Geometry Shader (programable)


En este shader podemos modificar la geometra, vrtices y sus conexiones, cambiando
sus atributos o incluso aadiendo nuevos puntos. Adems tiene otros usos como
seleccionar qu parte de la escena no queremos que contine a las siguientes etapas y
as reducir el nmero de operaciones.

C. 1. 7. Stream Output
El nico objetivo de esta etapa es guardar el resultado obtenido hasta ahora en un buffer
externo para su futuro uso o inspeccin. Realmente la etapa no realiza ningn tipo de
operacin puesto que la copia se hace durante la anterior, el geometry shader o el vertex
shader si el primero est desactivado.

C. 1. 8. Rasterizer
En esta etapa la geometra se convierte a un formato adecuado para poder ser presentado
en pantalla, es decir, los tringulos se convierten en pxeles. Aqu tambin se elimina la
parte de la escena que no debe ser mostrada en pantalla en funcin del tamao de la
cmara, su posicin o qu parte de los objetos no se vern por no mirar a sta.

C. 1. 9. Pixel Shader (programable)


El ltimo shader programable es invocado una vez por cada pixel y se encarga de
calcular su color final. Por ello es en esta etapa donde se realizan operaciones como
aplicar materiales o texturas. Tambin guarda informacin de la profundidad de los
pxeles para poder comprobar a continuacin cuales se corresponden con los objetos que
estn ocultos y cuales deben ser presentados.

C. 1. 10. Output Merger


Finalmente se combina la informacin de color y profundidad y se calcula el color final
que tendr cada pxel. Estos colores sern los que se guarden y los que se obtengan
como salida final de la pipeline.

C. 2. HLSL
High Level Shading Language, HLSL, es un lenguaje derivado de C++ pero con una
serie de caractersticas particulares para la programacin de tarjetas grficas, como el
soporte para vectores o matrices y la inclusin de operaciones tpicas con ellos, aunque
carece de otras como el uso de punteros o la reserva dinmica de memoria.

72

Es utilizado en todas las etapas programables de la pipeline, permitiendo la abstraccin


del hardware que haya debajo. El cdigo escrito, que implementar el algoritmo
deseado, ser compilado y asociado a la parte de la pipeline correspondiente.
Un shader puede utilizar variables de tipo entero, real y booleano, que tambin pueden
ser usados en vectores de hasta 4 variables, matrices de hasta 4x4 y estructuras definidas
por el usuario. Adems es capaz de acceder a variables de sistema, muchas generadas
automticamente, como la posicin de un pxel, y que pueden ser usadas para compartir
informacin entre etapas o simplemente para calcular algo en nuestro algoritmo.
Tambin es posible acceder a distintos buffers que contienen informacin intercambiada
con la CPU o con otras partes de la pipeline, como podra ser una textura o un mapa de
alturas.

73

ANEXO D: LA PIPELINE DE CLCULO


La potencia de clculo que ofrecen las tarjetas grficas actuales puede ser aprovechada
para realizar operaciones de clculo general, en especial aquellas que se beneficien de
una ejecucin en paralelo. En este anexo se explica como Direct3D 11, que incorpora la
API DirectCompute para GPGPU, permite explotar estas caractersticas a travs de la
pipeline de clculo.

D. 1. Etapas
La pipeline de clculo consta de una sola etapa, el Compute Shader, que se ejecuta de
manera totalmente separada de la pipeline grfica tradicional. Este shader debe
escribirse en HLSL, como cualquier otro, y ser el encargado de ejecutar el algoritmo
que queramos implementar en la GPU.

D. 2. Caractersticas
Para comprender como podemos utilizar la GPU para la ejecucin de un algoritmo de
tipo general y aprovechar su potencia es necesario comentar algunas de sus
particularidades.

D. 2. 1. Modelo de threading
El trabajo a ejecutar en la GPU se divide en grupos de threads. stos se distribuyen en
un array de 3 dimensiones comprendidas entre 1 y 64K, teniendo cada uno un ndice
para ser identificado. A su vez cada grupo est formado por varios threads, con su
propio identificador, distribuidos en otro array de 3 dimensiones comprendidas entre 1
y 64, siendo 1024 el nmero mximo de threads a ejecutar en cada grupo. Esta
disposicin se puede observar en la figura 48.
Ya que cada thread ejecutar el mismo shader es necesario que cada uno acte sobre
unos datos distintos. Tambin en la figura 48 es fcil ver la importancia de organizar
nuestros threads para aprovechar las caractersticas del algoritmo y como se van a
dividir los datos.
Para ello disponemos de los ndices mencionados anteriormente, tanto el de grupo como
el de thread dentro de grupo, as como la posicin global del thread y la posibilidad de
identificar a qu grupo pertenece. Estos ndices contendrn la posicin del grupo o el
thread en los 3 ejes, as que con toda esta informacin podemos acceder sin problemas a
la porcin de los datos que necesitemos.
Por supuesto el nmero de shaders que se ejecutarn realmente en paralelo depender
del hardware empleado, pero siempre hay que tratar de ajustar al mximo las
propiedades del problema a la organizacin de los threads.

75

Figura 48: Organizacin de los threads de un compute shader

D. 2. 2. Memoria
Como en cualquier otro shader es posible acceder a los recursos guardados en distintos
buffers y texturas, que estarn dentro la memoria de la GPU, si es posible, o en memoria
externa si no caben. Todos los threads tendrn acceso a los mismos recursos, ya sean
lecturas o escrituras, por ello habr que sincronizarlos, como se comenta en el siguiente
apartado.
Adems todos los threads del mismo grupo pueden compartir hasta 32 KB de memoria
dentro de la disponible en la GPU. Esta memoria, llamada Group Shared Memory
(GSM), tambin debe ser sincronizada para evitar conflictos y es la manera ms rpida
de compartir informacin entre threads.

D. 2. 3. Sincronizacin
Podemos evitar los problemas de sincronizacin en ambos tipos de memoria de varias
maneras, siendo la ms sencilla la que ya hemos comentado, que cada thread trabaje con
una parte distinta de los datos.
Tambin podemos utilizar barreras para sincronizar los accesos a memoria de un mismo
grupo. Es posible sincronizar la memoria de grupo, la externa o ambas a la vez. Adems
en los 3 casos se pueden utilizar 2 tipos de barreras distintos. El primero espera a que
todas las escrituras pendientes en ese momento acaben antes de seguir, puesto que hay
un lapso de tiempo desde que la instruccin se ejecuta en el shader y ste es realmente
realizado a nivel hardware. El segundo tipo, adems de garantizar lo anterior, espera a
que todos los threads del grupo lleguen a la llamada a la funcin de barrera.

76

Finalmente, es posible utilizar varias funciones atmicas disponibles que garantizan que
su ejecucin se completa antes de que cualquier otra operacin se vaya a realizar sobre
los mismos datos.
Tambin debemos comentar que aunque todas estas maneras de sincronizacin son
tiles solo la primera es deseable, ya que es la nica que nos evita tener tiempos ociosos
en la GPU y por tanto aprovecha al mximo sus capacidades.

77

ANEXO E: APLICACIN ESTUDIADA


En el presente anexo se trata la implementacin de una aplicacin para simular fluidos
sacada del libro Practical Rendering and Computation with Direct3D 11. Gracias a
ella se han estudiado las caractersticas de Direct3D 11 y el uso y configuracin de las
distintas etapas de la pipeline, tanto de clculo como de renderizado.

E. 1. Contexto
E. 1. 1. Contexto tecnolgico
La simulacin y renderizado en tiempo real de fluidos, en este caso agua, suele ser uno
de los aspectos ms costosos de una escena. Es debido a esta complejidad que puede ser
beneficioso usar la potencia de una GPU para realizar los clculos.
Hacer una representacin fsicamente perfecta es algo imposible para el hardware
actual, pero no es necesaria para conseguir una aproximacin que sea eficiente y
visualmente capaz de dar la impresin adecuada. En nuestro caso el agua est formada
por millones de molculas pero solo nos interesa ver el comportamiento de la superficie
para poder renderizarla. Tambin podemos acotar el nmero de partculas reduciendo
todo a una red cuadriculada de columnas de agua, cuya altura ser la de la superficie.

E. 1. 2. Base matemtica
Usando estas columnas es posible que el agua fluya de unas a otras si consideramos que
las vecinas estn conectadas por tuberas virtuales situadas al pie de cada columna. Para
calcular este flujo necesitamos saber la presin Pij ejercida en el fondo de cada
columna, la cual podemos hallar con la altura Hij de sta, la densidad del agua d, la
gravedad g y la presin atmosfrica p.
Pij=Hijdg+ p

La diferencia existente entre presiones de columnas vecinas ser la que genere la


aceleracin a del flujo de cada tubera, que podemos calcular puesto que tambin
conocemos el rea c de sta y la masa de agua m que ya hay en la columna.
a ij kl =

c( H ij H kl )
m

Conociendo la aceleracin y suponiendo que el flujo es constante durante un intervalo


de tiempo t es posible calcular el flujo de agua Q.
t + t

Qij kl =Qij kl + t(caij kl )


Tras calcular los flujos a travs de todas las tuberas virtuales es fcil calcular el cambio
en el volumen de agua de una tubera V.

79

V ij = t (
kl nij

t + t

Qij kl +Qij kl
)
2

Finalmente, calcular el cambio de altura usando el rea A de la columna de agua es


trivial ya que
H ij =

V ij
Aij

E. 2. Diseo
E. 2. 1. Datos
Viendo las consideraciones anteriores llegamos a la conclusin de que para cada
columna debemos mantener dos tipos de informacin: su altura y el flujo de las tuberas.
Como cada columna tiene 8 conexiones pero hay informacin compartida nos basta con
utilizar 4 datos, la tubera de la derecha y las de abajo, como se muestra en la figura 49.

Figura 49: Conexin de columnas de agua


Tenemos en total 5 datos de tipo real por columna que sern guardados en un buffer
constante estructurado y que contendr el estado de la simulacin. No obstante no nos
basta con usar uno puesto que el estado actual debe ser mantenido hasta haber
completado el clculo del nuevo, as que usaremos 2 que irn intercambiando su papel.

E. 2. 2. Threading
Observando la figura 49 es fcil pensar que cada columna puede asociarse con un
thread, que a su vez sern organizados en grupos cuadrados, en este caso de dimensin
16x16. Puesto que los threads vecinos comparten informacin es posible usar la
memoria compartida de grupo para almacenar estos datos y mejorar el acceso a ellos. El
problema aparece en los threads del borde del grupo, que deben comunicarse con otros
que estn fuera del grupo y, por tanto, fuera de la memoria compartida.
Para evitar tener que escribir y leer todos los datos en la memoria de la GPU en cada
pasada aadimos una fila al permetro del grupo, quedando 18x18, que se solapa con los
grupos adyacentes. Estos threads cargarn las alturas correspondientes y realizarn los
clculos de flujo, que si podrn ser guardados en memoria de grupo, pero no
actualizarn el estado de la simulacin, ya que de eso se encargarn los threads
correspondientes de los grupos vecinos. En resumen, para evitar tener que hacer ms
accesos a memoria lenta repetimos algunos clculos en distintos grupos, que suponen
una penalizacin menor.
80

E. 3. Aplicacin
Con la teora y el diseo en mente solo queda la implementacin. Para empezar,
analizaremos la aplicacin. La original utilizada en el ejemplo del libro usa una serie de
libreras creadas por los autores que no permiten ver las llamadas a Direct3D
claramente, por ello se ha escrito una nueva donde se pueden apreciar.
// Incluimos los archivos necesarios
#include <windows.h>
#include <d3d11.h>
#include <d3dcompiler.h>
#include <directxmath.h>
// Incluimos las librerias necesarias
#pragma comment (lib, "d3d11.lib")
#pragma comment (lib, "d3dcompiler.lib")
using namespace DirectX;
// Variables globales
HWND hWnd;
//
D3D11_VIEWPORT viewport;
//
IDXGISwapChain *swapchain = NULL;
//
ID3D11Device *dev = NULL;
//
ID3D11DeviceContext *devcon = NULL;
//
ID3D11RenderTargetView *rtv = NULL;
//
ID3D11VertexShader *pVS = NULL;
//
ID3D11PixelShader *pPS = NULL;
//
ID3D11ComputeShader *pCS = NULL;
//
ID3D11Buffer *pVBuffer = NULL;
//
ID3D11Buffer *pIBuffer = NULL;
//
ID3D11InputLayout *pLayout = NULL;
//
ID3D11RasterizerState *pRState=NULL;
//
rasterizado
ID3D11Buffer *pCBufferMat = NULL;
//
transformacion
ID3D11Buffer *pCBufferDis = NULL;
//
utilizados
ID3D11Buffer *pCBufferDisTime = NULL;
//
tiempo
ID3D11Buffer *pWaterSim1 = NULL;
//
actual de la simulacin
ID3D11Buffer *pWaterSim2 = NULL;
//
estado de la simulacin
ID3D11ShaderResourceView *pSRVWater= NULL; //
la simulacin
ID3D11UnorderedAccessView *pUAVWater= NULL;//
informacin de la simulacin
int numVertices = 0;
//
int numIndices = 0;
//
XMMATRIX myWorld;
//
XMMATRIX myView;
//
XMMATRIX myProjection;
//
int ThreadGroupsX = 16;
//
int ThreadGroupsY = 16;
//
const int DispatchSizeX = 16;
//
const int DispatchSizeZ = 16;
//
int SizeX= ThreadGroupsX*DispatchSizeX;
//

81

Controlador de la ventana
Vista
Swap chain
Direct3D device interface
Direct3D device context
Render Target View
Vertex Shader
Pixel Shader
Compute Shader
Buffer de los vrtices
Buffer de ndices
Formato de entrada a la pipeline
Configuracin de la etapa de
Constant buffer de las matrices de
Buffer con la info de threads
Buffer con la info de threads y de
Buffer para guardar el estado
Buffer para guardar el prximo
Vista para leer la informacin de
Vista para leer/escribir la
Nmero de vertices a dibujar
Nmero de indices
Matriz del mundo
Matriz de la vista
Matriz de proyeccin
Nmero de thread groups, x
Nmero de thread groups, y
Nmero de threads por grupo, x
Numeo de threads por grupo, Z
Nmero de vrtices en X

int SizeZ= ThreadGroupsY*DispatchSizeZ;


LARGE_INTEGER tiempo;
actualizacin de la simulacion
LARGE_INTEGER freq;
calcular el tiempo

// Nmero de vrtices en Z
// Tiempo transcurrido desde la ltima
// Frecuencia de la CPU, usada para

// Estructuras a usar
// Vrtice
struct VERTEX {
float x, y, z; // Posicin
};
// Informacin de un punto de la simulacin
struct GridPoint
{
float height;
float flow[4];
};
// Buffer constante de las matrices de transformacin
struct ConstantBufferMatrix
{
XMMATRIX World;
XMMATRIX View;
XMMATRIX Projection;
};
// Buffer constante con la informacin de threads
struct ConstantBufferDis
{
float DispatchSize[4];
};
// Buffer constante con al informacin de threads y tiempo
struct ConstantBufferDisTime
{
float TimeFactor;
float padding[3]; // Los buffers constantes deben estar alineados a 16bytes,
as que rellenamos
float DispatchSize[4];
};
// Declaracin de las funciones a usar
HRESULT InitWindow(HINSTANCE hInstance, int nCmdShow );
HRESULT InitDevice();
void InitPipeline();
void InitScene();
void InitSim();
void InitCamera();
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM
lParam);
void Calculate();
void Render();
void CleanD3D();
// Punto de entrada a la aplicacin
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
int nCmdShow)
{

82

// Creacin de la ventana
if( FAILED (InitWindow(hInstance,nCmdShow)) )
return 0;
// Creacin del dispositivo y swap chain
if( FAILED (InitDevice()) )
return 0;
// Inicializar la pipeline
InitPipeline();
// Inicializar la escena
InitScene();
// Iniciar la simulacin
InitSim();
// Inicializar la cmara
InitCamera();
// Inicio de la informacin del timer
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&tiempo);
// Bucle principal
MSG msg; // Mensaje de los eventos de Windows
while(TRUE)
{
// Comprobar si hay mensajes esperando
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
// Traducir al formato de Windows
TranslateMessage(&msg);
// Mandar mensaje a WindowProc para procesarlo
DispatchMessage(&msg);

// Comprobar si hay que salir de la aplicacin


if(msg.message == WM_QUIT)
break;

// Calcular un paso de la simulacion


Calculate();
// Renderizar la escena
Render();
}
// Liberar recursos
CleanD3D();

// Devolver a Windows la siguiente info


return msg.wParam;

// Funcin para iniciar la ventana


HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow )
{
WNDCLASSEX ventana; // Clase de la ventana
ZeroMemory(&ventana, sizeof(WNDCLASSEX)); // Limpiamos la variable ventana

83

// Llenamos la clase con la info correspondiente


ventana.cbSize = sizeof(WNDCLASSEX);
//
ventana.style = CS_HREDRAW | CS_VREDRAW;
//
ventana.lpfnWndProc = WindowProc;
//
eventos
ventana.hInstance = hInstance;
//
con la ventana
ventana.hCursor = LoadCursor(NULL, IDC_ARROW); //
ventana.hbrBackground = (HBRUSH)COLOR_WINDOW;
//
ventana.lpszClassName = L"ClaseVentana";
//

Tamao de la clase
Estilo
Puntero al controlador de
Instancia de la aplicacin
Cursor
Color del fondo
Nombre de la clase

// Registramos la clase
if (! RegisterClassEx(&ventana))
return E_FAIL;
// Creamos una ventana y obtenemos el controlador
RECT wr = {0, 0, 800, 600}; // Indicamos el tamao de la zona de la ventana
disponible para nuestra aplicacin
AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE); // Obtenemos el tamao
completo de la ventana
hWnd = CreateWindowEx(NULL, // Estilo
L"ClaseVentana",
L"Agua-Columnas",
WS_OVERLAPPEDWINDOW,
100,
100,
wr.right - wr.left,
wr.bottom- wr.top,
NULL,
NULL,
hInstance,
con la ventana
NULL);

//
//
//
//
//
//
//
//
//
//

Nombre de la clase ventana


Titulo a mostrar
Estilo
Posicion x de la ventana
Posicion y de la ventana
Ancho
Altura
Ventana padre, NULL
Uso de menus, NULL
Instancia de la aplicacin

// Multiples ventanas, NULL

if (!hWnd)
return E_FAIL;
// Mostrar ventana por pantalla
ShowWindow(hWnd, nCmdShow);
return S_OK;
}
// Funcin para crear el dispositivo y la swapchain
HRESULT InitDevice()
{
// Informacin de la swap chain
DXGI_SWAP_CHAIN_DESC scd;
ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));
scd.BufferCount = 1;
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
la pipeline
scd.OutputWindow = hWnd;
scd.SampleDesc.Count = 1;
scd.Windowed = TRUE;
completa

84

// 1 back buffer
// Usar colores de 32 bit
// Modo de uso: salida de
// Ventana a usar
// Multisamples
// Modo ventana/!pantalla

// Crear device, device context y swap chain


HRESULT hr = D3D11CreateDeviceAndSwapChain(NULL,
//
usar (GPU). Se elige automticamente
D3D_DRIVER_TYPE_HARDWARE,//
(software-hardware)
NULL,
//
driver si este es software
NULL,
//
configuracin
NULL,
//
Distintas aractersticas que pueden estar disponibles en el
NULL,
//
levels
D3D11_SDK_VERSION,
//
con la que vamos a desarrollar la aplicacin
&scd,
//
&swapchain,
//
&dev,
//
NULL,
//
disponible en el equipo actual
&devcon);
//
if( FAILED(hr))
return hr;

Adaptador grfico a
Tipo de driver a usar
Puntero al cdigo del
Flags de
Feature levels.
hardware
Nmero de feature
Versin de DirectX
Info de la swap chain
Swap chain
Device
Mximo feature level
Device context

// Crear render target view


// Necesitamos la direccin del back buffer
ID3D11Texture2D *pBackBuffer;
swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
// Usamos esta direccin para crear el render target
dev->CreateRenderTargetView(pBackBuffer, NULL, &rtv);
pBackBuffer->Release(); // Ya no necesitamos la textura
// Configuramos la vista
ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.Width = 800;
viewport.Height = 600;
return S_OK;
}
// Funcion para inicializar la pipeline
void InitPipeline()
{
// Compilar y cargar los shaders
ID3DBlob *VS, *PS, *CS;
D3DCompileFromFile(L"Visualizacion.hlsl", NULL, NULL, "VSMAIN", "vs_5_0",
D3DCOMPILE_DEBUG, 0, &VS, NULL);
D3DCompileFromFile(L"Visualizacion.hlsl", NULL, NULL, "PSMAIN", "ps_5_0",
D3DCOMPILE_DEBUG, 0, &PS, NULL);
D3DCompileFromFile(L"AguaColumnas.hlsl", NULL, NULL, "CSMAIN", "cs_5_0",
D3DCOMPILE_DEBUG, 0, &CS, NULL);
// Encapsular los objetos shaders
dev->CreateVertexShader(VS->GetBufferPointer(), VS->GetBufferSize(), NULL,
&pVS);
dev->CreatePixelShader(PS->GetBufferPointer(), PS->GetBufferSize(), NULL,
&pPS);

85

dev->CreateComputeShader(CS->GetBufferPointer(), CS->GetBufferSize(), NULL,


&pCS);
// Definir la estructura del input layout
D3D11_INPUT_ELEMENT_DESC ied[] =
{
{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0,
D3D11_INPUT_PER_VERTEX_DATA, 0},
};
// Crear el objeto input layout
dev->CreateInputLayout(ied, ARRAYSIZE(ied), VS->GetBufferPointer(), VS>GetBufferSize(), &pLayout);

// Configuramos el rasterizado
D3D11_RASTERIZER_DESC rs;
ZeroMemory(&rs, sizeof(rs));
rs.FillMode = D3D11_FILL_WIREFRAME; // Modo malla
rs.CullMode = D3D11_CULL_BACK; // No mostrar las caras traseras
dev->CreateRasterizerState( &rs, &pRState);

// Funcin para inicializar los objetos de la escena


void InitScene()
{
numVertices=SizeX*SizeZ; // Nmero de vrtices
numIndices=6*(SizeX-1)*(SizeZ-1); // Nmero de ndices
// Creamos un plano de tringulos
VERTEX *OurVertices;
OurVertices= new VERTEX[numVertices];
WORD *indices;
indices = new WORD[numIndices];
// Generar vrtices
for ( int y = 0; y < SizeZ; y++ )
{
for ( int x = 0; x < SizeZ; x++ )
{
OurVertices[y*SizeX+x].x = (float)x;
OurVertices[y*SizeX+x].y = 0.0f;
OurVertices[y*SizeX+x].z = (float)y;
}
}
// Creamos el buffer de vrtices
D3D11_BUFFER_DESC bd;
ZeroMemory(&bd, sizeof(bd));
bd.Usage = D3D11_USAGE_DEFAULT; // Modo de uso. CPU -/- y GPU Read/Write
bd.ByteWidth = sizeof(VERTEX) *numVertices; // Tamao
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER; // Donde puede asociarse en la
pipeline
bd.CPUAccessFlags = 0; // Permiso de escritura de la CPU
D3D11_SUBRESOURCE_DATA InitData; // Datos iniciales
ZeroMemory( &InitData, sizeof(InitData) );
InitData.pSysMem = OurVertices;
dev->CreateBuffer( &bd, &InitData, &pVBuffer); // Crear el buffer

86

// Generar ndices
for ( int j = 0; j < SizeZ-1; j++ )
{
for ( int i = 0; i < SizeX-1; i++ )
{
indices[j*6*(SizeX-1)+i*6] = j*SizeX + i;
indices[j*6*(SizeX-1)+i*6+1] = (j*SizeX + i) + SizeX;
indices[j*6*(SizeX-1)+i*6+2] = (j*SizeX + i) + 1;

indices[j*6*(SizeX-1)+i*6+3] = (j*SizeX + i) + 1;
indices[j*6*(SizeX-1)+i*6+4] = (j*SizeX + i) + SizeX;
indices[j*6*(SizeX-1)+i*6+5] = (j*SizeX + i) + SizeX + 1;

}
// Crear el index buffer
ZeroMemory(&bd, sizeof(bd));
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof( WORD ) * numIndices; // Tamao
bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
bd.CPUAccessFlags = 0;
InitData.pSysMem = indices; // Datos iniciales
dev->CreateBuffer( &bd, &InitData, &pIBuffer ); // Crear el buffer
}
// Funcin para inicializar la simulacin
void InitSim()
{
// Creamos datos iniciales para la simulacin
GridPoint* pData;
pData = new GridPoint[numVertices];
for (int j = 0; j <
{
for (int i = 0;
{
int x = i int y = j -

SizeZ; j++)
i < SizeX; i++)
32;
96;

const float fFrequency = 0.1f;


if (x*x + y*y != 0.0f)
{
pData[SizeX*j + i].height = 40.0f * sinf(sqrt((float)(x*x + y*y))
* fFrequency) / (sqrt((float)(x*x + y*y)) * fFrequency);
pData[SizeX*j + i].flow[0] = 0.0f;
pData[SizeX*j + i].flow[1] = 0.0f;
pData[SizeX*j + i].flow[2] = 0.0f;
pData[SizeX*j + i].flow[3] = 0.0f;
}
else
{
pData[SizeX*j + i].height = 40.0f;
pData[SizeX*j + i].flow[0] = 0.0f;
pData[SizeX*j + i].flow[1] = 0.0f;
pData[SizeX*j + i].flow[2] = 0.0f;
pData[SizeX*j + i].flow[3] = 0.0f;
}
}

87

}
// Datos iniciales
D3D11_SUBRESOURCE_DATA InitialData;
InitialData.pSysMem = pData;
// Creamos los buffer que contendrn el estado de la simulacin
D3D11_BUFFER_DESC bd;
ZeroMemory(&bd, sizeof(bd));
bd.ByteWidth = numVertices*sizeof(GridPoint);
bd.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS;
bd.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
bd.StructureByteStride = sizeof(GridPoint);
bd.Usage = D3D11_USAGE_DEFAULT;
bd.CPUAccessFlags = 0;
dev->CreateBuffer(&bd, &InitialData, &pWaterSim1);
dev->CreateBuffer(&bd, &InitialData, &pWaterSim2);
// Ya no necesitamos la memoria de la CPU, pues la simulacin es manejada por
la GPU
delete[] pData;
// Crear el constant buffer con la info de los threads usados
ZeroMemory(&bd, sizeof(bd));
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof(ConstantBufferDis);
bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
bd.CPUAccessFlags = 0;
dev->CreateBuffer(&bd, NULL, &pCBufferDis);
// Actualizar los datos del buffer
ConstantBufferDis cd;
cd.DispatchSize[0] = float(DispatchSizeX);
cd.DispatchSize[1] = float(DispatchSizeZ);
cd.DispatchSize[2] = float(DispatchSizeX*ThreadGroupsX);
cd.DispatchSize[3] = float(DispatchSizeZ*ThreadGroupsY);
devcon->UpdateSubresource(pCBufferDis, 0, NULL, &cd, 0, 0);

// Crear el constant buffer para el tiempo y la informacin de threads


ZeroMemory(&bd, sizeof(bd));
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof(ConstantBufferDisTime);
bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
bd.CPUAccessFlags = 0;
dev->CreateBuffer(&bd, NULL, &pCBufferDisTime);

// Funcin para iniciar la cmara


void InitCamera()
{
// Inicializar la matriz del mundo
myWorld = XMMatrixIdentity();
// Inicialziar la vista
XMVECTOR Eye = XMVectorSet(-10.0f, 30.0f, 3.0f, 0.0f);
XMVECTOR At = XMVectorSet(30.0f, 2.0f, 30.0f, 0.0f);
XMVECTOR Up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
myView = XMMatrixLookAtLH(Eye, At, Up);
// Inicializar la proyeccion

88

myProjection = XMMatrixPerspectiveFovLH(XM_PIDIV4, 800.0f / 600.0f, 0.01f,


100.0f);
// Crear el constant buffer para las matrices
D3D11_BUFFER_DESC bd;
ZeroMemory(&bd, sizeof(bd));
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof(ConstantBufferMatrix);
bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
bd.CPUAccessFlags = 0;
dev->CreateBuffer(&bd, NULL, &pCBufferMat);

// Actualizar buffer
ConstantBufferMatrix cb;
cb.World = XMMatrixTranspose(myWorld);
cb.View = XMMatrixTranspose(myView);
cb.Projection = XMMatrixTranspose(myProjection);
devcon->UpdateSubresource(pCBufferMat, 0, NULL, &cb, 0, 0);

// Funcin para controlar eventos de windows


LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM
lParam)
{
// Tratamos cada tipo de evento de una manera
switch (message)
{
// Evento cerrar ventana
case WM_DESTROY:
// Cerrar la aplicacin
PostQuitMessage(0);
return 0;
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
// Funcion para calcular un paso de la simulacin
void Calculate()
{
// Informacin del tiempo
LARGE_INTEGER nuevoT;
QueryPerformanceCounter(&nuevoT);
float paso = float(nuevoT.QuadPart - tiempo.QuadPart);
tiempo = nuevoT;
// Limpiamos el estado de la pipeline
devcon->ClearState();
// Indicar los shaders a utilizar
devcon->CSSetShader(pCS, 0, 0);
// Buffers a usar
devcon->CSSetConstantBuffers(0, 1, &pCBufferDisTime);
// Creamos las vistas para acceder a la informacin. Como los buffers se
// intercambian cada paso debemos volver a crear las vistas cada vez
// Creamos la shader resource view para poder leer los gridpoints en la
pipeline

89

D3D11_SHADER_RESOURCE_VIEW_DESC desc;
desc.Format = DXGI_FORMAT_UNKNOWN;
desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
desc.Buffer.ElementOffset = 0;
desc.Buffer.NumElements = numVertices;
dev->CreateShaderResourceView(pWaterSim1, &desc, &pSRVWater);
devcon->CSSetShaderResources(0, 1, &pSRVWater);
// Creamos la unordered access view para poder escribir los gridpoints desde
la pipeline
D3D11_UNORDERED_ACCESS_VIEW_DESC uesc;
uesc.Format = DXGI_FORMAT_UNKNOWN;
uesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
uesc.Buffer.FirstElement = 0;
uesc.Buffer.NumElements = numVertices;
uesc.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_COUNTER;
dev->CreateUnorderedAccessView(pWaterSim2, &uesc, &pUAVWater);
devcon->CSSetUnorderedAccessViews(0, 1, &pUAVWater, 0);
// Actualizar variables
ConstantBufferDisTime cb;
cb.TimeFactor = paso / freq.QuadPart;
cb.DispatchSize[0] = float(DispatchSizeX);
cb.DispatchSize[1] = float(DispatchSizeZ);
cb.DispatchSize[2] = float(SizeX);
cb.DispatchSize[3] = float(SizeZ);
devcon->UpdateSubresource(pCBufferDisTime, 0, NULL, &cb, 0, 0);
// Simular en la GPU
devcon->Dispatch(ThreadGroupsX, ThreadGroupsY, 1);
// Intercambiar buffers
ID3D11Buffer *Temp = pWaterSim1;
pWaterSim1 = pWaterSim2;
pWaterSim2 = Temp;
}

Temp->Release();

// Funcin para renderizar un frame


void Render()
{
// Limpiamos el estado de la pipeline
devcon->ClearState();
// Limpiar el backbuffer a un color gris
float clearColor[4] = { 0.8f, 0.8f, 0.8f, 1.0f };
devcon->ClearRenderTargetView(rtv, clearColor);
// Elegir tipo de primitiva a usar
devcon->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
// Indicamos el layout a utilizar
devcon->IASetInputLayout(pLayout);
// Indicar los shaders a utilizar
devcon->VSSetShader(pVS, 0, 0);
devcon->PSSetShader(pPS, 0, 0);
// Indicar los buffers a usar

90

UINT stride = sizeof(VERTEX);


// Tamao del vrtice
UINT offset = 0;
// Offset inicial
devcon->IASetVertexBuffers(0, 1, &pVBuffer, &stride, &offset);
devcon->IASetIndexBuffer(pIBuffer, DXGI_FORMAT_R16_UINT, 0);
devcon->VSSetConstantBuffers(0, 1, &pCBufferMat);
devcon->VSSetConstantBuffers(1, 1, &pCBufferDis);
// Indicar las vistas a usar
devcon->VSSetShaderResources(0, 1, &pSRVWater);
// Indicamos la configuracin de rasterizado
devcon->RSSetState(pRState);
devcon->RSSetViewports(1, &viewport);
// Indicamos cual es el render target a usar
devcon->OMSetRenderTargets(1, &rtv, NULL);
// Dibujar el vertex buffer al back buffer
devcon->DrawIndexed(numIndices, 0, 0); // N vrtices(indexados) empezando en
el 0
// Intercambiar el backbuffer con el frontal
swapchain->Present(0, 0);
}
// Funcion para cerrar y liberar los objetos usados
void CleanD3D()
{
pVS->Release();
pPS->Release();
pCS->Release();
swapchain->Release();
rtv->Release();
pVBuffer->Release();
pLayout->Release();
pCBufferMat->Release();
pWaterSim1->Release();
pWaterSim2->Release();
pCBufferDis->Release();
pCBufferDisTime->Release();
pRState->Release();
pSRVWater->Release();
pUAVWater->Release();
dev->Release();
devcon->Release();
}

E. 4. Shader de clculo
El clculo de la simulacin se hace en un compute shader utilizando las ideas
introducidas en los apartados de contexto y diseo. A partir de la diferencia de alturas
entre columnas, que tenemos disponibles, se calcularn las diferencias de presin,
aceleracin y nuevo flujo, que es lo que se necesita para modificar la altura de cada
columna.

91

// Estructuras usadas
// Estado de una columna de la simulacion
struct GridPoint
{
float Height;
float4 Flow;
};
// Buffers usados
// Buffer constante con la informacion de tiempo de la simulacion y threads
usados
cbuffer TimeParameters
{
float TimeFactor;
float4 DispatchSize;
};
// Estados de la simulacion, el actual y el nuevo a calcular
RWStructuredBuffer<GridPoint> NewWaterState
: register( u0 );
StructuredBuffer<GridPoint>
CurrentWaterState : register( t0 );
// Datos a usar
// Tamao de la simulacion
#define size_x 16
#define size_y 16
// Tamao de grupo con perimetro extra
#define padded_x (1 + size_x + 1)
#define padded_y (1 + size_y + 1)
// Memoria de grupo para compartir informacion
groupshared GridPoint loadedpoints[padded_x * padded_y];
// Numero de threads por grupo
[numthreads(padded_x, padded_y, 1)]
// Compute shader
void CSMAIN( uint3 GroupID : SV_GroupID, uint3 DispatchThreadID :
SV_DispatchThreadID, uint3 GroupThreadID : SV_GroupThreadID, uint GroupIndex :
SV_GroupIndex )
{
// Tamao de una rejilla (vista)
int gridsize_x = DispatchSize.x;
int gridsize_y = DispatchSize.y;
// Tamao total del mapa de alturas
int totalsize_x = DispatchSize.z;
int totalsize_y = DispatchSize.w;
// Hacemos todos los accesos a la memoria con el estado de la simulacion
actual para guardarlos en la memoria compartida
// Datos iniciales a 0
loadedpoints[GroupIndex].Height = 0.0f;
loadedpoints[GroupIndex].Flow = float4( 0.0f, 0.0f, 0.0f, 0.0f );
// Calcular la posicion dentro del buffer usando los IDs del thread
int3 location = int3( 0, 0, 0 );
location.x = GroupID.x * size_x + ( GroupThreadID.x - 1 );
location.y = GroupID.y * size_y + ( GroupThreadID.y - 1 );

92

int textureindex = location.x + location.y * totalsize_x;


// Cargar la informacion a memoria compartida
loadedpoints[GroupIndex] = CurrentWaterState[textureindex];
// Sincronizar los threads del grupo para asegurar que todos han cargado los
datos
GroupMemoryBarrierWithGroupSync();
//---------------------------------------// Calcular y actualizar los flujos
//
//
o--o x
//
/|\
//
/ | \
//
o o o
//
w
z
y
// Cargar los flujos del estado actual de la simulacion
float4 NewFlow = float4( 0.0f, 0.0f, 0.0f, 0.0f );
// Comprobar que no estamos en el borde derecho del grupo
if ( ( GroupThreadID.x < padded_x - 1 ) && ( location.x < totalsize_x - 1 ) )
{
NewFlow.x = ( loadedpoints[GroupIndex+1].Height loadedpoints[GroupIndex].Height );
// Comprobar que no estamos en el borde inferior del grupo
if ( ( GroupThreadID.y < padded_y - 1 ) && ( location.y < totalsize_y - 1
) )

NewFlow.y = ( loadedpoints[(GroupIndex+1) + padded_x].Height loadedpoints[GroupIndex].Height );


}
}
// Comprobar que no estamos en el borde inferior del grupo
if ( ( GroupThreadID.y < padded_y - 1 ) && ( location.y < totalsize_y - 1 ) )
{
NewFlow.z = ( loadedpoints[GroupIndex+padded_x].Height loadedpoints[GroupIndex].Height );
// Comprobar que no estamos en el borde izquierdo del grupo
if ( ( GroupThreadID.x > 0 ) && ( location.x > 0 ) )
{
NewFlow.w = ( loadedpoints[GroupIndex + padded_x - 1].Height loadedpoints[GroupIndex].Height );
}
}
// Datos usados para calcular los nuevos flujos
const float TIME_STEP = 0.005f;
const float PIPE_AREA = 0.0001f;
const float GRAVITATION = 10.0f;
const float PIPE_LENGTH = 0.2f;
const float FLUID_DENSITY = 1.0f;
const float COLUMN_AREA = 0.05f;
const float DAMPING_FACTOR = 1.0f; // Para que la inercia de la simulacion
vaya disminuyendo
// Aceleracion del flujo

93

float fAccelFactor = ( min( TimeFactor, TIME_STEP ) * PIPE_AREA * GRAVITATION


) / ( PIPE_LENGTH * COLUMN_AREA );
// Calculo del nuevo flujo, sumando el valor anterior.
NewFlow = ( NewFlow * fAccelFactor + loadedpoints[GroupIndex].Flow ) *
DAMPING_FACTOR;
// Actualizar la memoria compartida con el nuevo flujo
loadedpoints[GroupIndex].Flow = NewFlow;
// Sincronizar todos los threads antes de seguir
GroupMemoryBarrierWithGroupSync();
//---------------------------------------// Actualizar la altura de cada columna
// Flujo saliente
loadedpoints[GroupIndex].Height = loadedpoints[GroupIndex].Height + NewFlow.x
+ NewFlow.y + NewFlow.z + NewFlow.w;
// Flujo entrante de la izquierda
loadedpoints[GroupIndex].Height = loadedpoints[GroupIndex].Height loadedpoints[GroupIndex-1].Flow.x;
// Flujo entrante de la esquina superior izquierda
loadedpoints[GroupIndex].Height = loadedpoints[GroupIndex].Height loadedpoints[GroupIndex-padded_x-1].Flow.y;
// Flujo entrante de arriba
loadedpoints[GroupIndex].Height = loadedpoints[GroupIndex].Height loadedpoints[GroupIndex-padded_x].Flow.z;
// Flujo entrante de la esquina superior derecha
loadedpoints[GroupIndex].Height = loadedpoints[GroupIndex].Height loadedpoints[GroupIndex-padded_x+1].Flow.w;
// Actualizar el nuevo estado de la simulacion (ignorando el perimetro)
if ( ( GroupThreadID.x > 0 ) && ( GroupThreadID.x < padded_x - 1 ) &&
( GroupThreadID.y > 0 ) && ( GroupThreadID.y < padded_y - 1 ) )
{
NewWaterState[textureindex] = loadedpoints[GroupIndex];
}
}

E. 5. Shaders de renderizado
El renderizado de la superficie obtenida es sencillo y solo utiliza un vertex y un pixel
shader. El vertex shader transforma la posicin del vrtice, cuya altura obtendr de los
clculos previamente realizados, y elige un color en funcin del grupo de threads donde
se ha realizado la simulacin. El pixel shader simplemente usa este color como color
definitivo.
// Estructuras usadas
// Entrada al vertex shader
struct VS_INPUT
{
float3 position : POSITION; // Posicon del vertice
};

94

// Salida del vertex shader y entrada al pixel shader


struct VS_OUTPUT
{
float4 position : SV_POSITION; // Posicion del pixel
float4 color : COLOR; // Color
};
// Estado de una columna de la simulacion
struct GridPoint
{
float Height;
float4 Flow;
};
// Buffers usados
// Buffer constante con las matrices de transformacion
cbuffer Transforms
{
matrix World;
matrix View;
matrix Projection;
}
// Buffer constante con informacion del numero de threads
cbuffer DispatchParams
{
float4 DispatchSize;
};
// Buffer estructurado con el estado de la simulacion
StructuredBuffer<GridPoint>
CurrentWaterState : register(t0);
// Vertex shader
VS_OUTPUT VSMAIN( in VS_INPUT v )
{
VS_OUTPUT o = (VS_OUTPUT)0;
// Determinar en que posicion del buffer con el estado de la simulacion
buscar la altura
// Coordenadas en 2 dimensiones
int2 coords = int2( floor(v.position.x), floor(v.position.z));
// Pasamos a una sola dimension
int textureindex = coords.x + coords.y * DispatchSize.z;
// Obtener la altura de esa posicion
float height = CurrentWaterState[textureindex].Height;
// Transformar la posicion del vertice a clipspace
float4 SampledPosition = float4( v.position.x, height, v.position.z, 1.0f );
o.position = mul( SampledPosition, World);
o.position = mul( o.position, View);
o.position = mul( o.position, Projection);
// Elegir color del punto en funcion del grupo de threads al que pertenece
int2 GridPosition = (coords / 16.0f );
float ColorIndex = frac( ( GridPosition.x + GridPosition.y ) / 2.0f );
if ( ColorIndex < 0.5f )
o.color = float4( 0.0f, 1.0f, 0.0f, 1.0f );
else

95

o.color = float4( 0.0f, 0.0f, 1.0f, 1.0f );


return o;
}
// Pixel shader
float4 PSMAIN( in VS_OUTPUT input ) : SV_Target
{
return input.color;
}

E. 6. Resultados
El resultado final puede verse en la figura 50

Figura 50: Simulacin de agua con columnas

96

ANEXO F: RUIDO Y FRACTALES


En este anexo, titulado Ruido y fractales, se define qu es el ruido y se distingue entre
varios tipos. Adems se explica el concepto de fractal y como puede construirse uno
usando alguna clase de ruido.

F. 1. Ruido
En nuestro mbito el ruido es una funcin que vara de manera aparentemente aleatoria.
Decimos que es aparente porque aunque no se observe ninguna pauta la funcin debe
ser repetible. Esta aleatoriedad se usa para evitar la aparicin de patrones que, aunque s
existen, no llegan a ser apreciables. Adems el rango de salida de la funcin debe ser
conocido y su ancho de banda limitado.
El ruido se usa habitualmente para generar objetos naturales como agua, montaas o
nubes, ya sea para la construccin de su forma o para la de las texturas que se aplicarn
a su superficie.

F. 2. Tipos de ruido
A continuacin se hace una breve diferenciacin de algunos de los tipos de ruido ms
usados.

F. 2. 1. Ruido de rejilla
Uno de los tipos de ruido ms sencillo y eficiente. Se define una malla para cada punto
de nuestro espacio cuyas coordenadas son enteras y se le asigna un nmero
pseudoaleatorio, normalmente con una permutacin aleatoria previamente calculada de
nmeros enteros en el rango deseado. Para obtener el valor en cualquier punto solo hay
que interpolar entre los puntos de la rejilla que lo rodean. Dependiendo del mtodo
usado para interpolar y del nmero de vecinos utilizados se conseguirn unos resultados
u otros.

F. 2. 2. Ruido de valores
Similar al anterior, en este caso el valor de cada punto de la malla es un nmero
aleatorio entre -1 y 1.

F. 2. 3. Ruido de gradientes
En este caso tenemos tambin una permutacin de nmeros enteros, pero esta vez se usa
para asignar a cada punto de la malla un gradiente pseudoaletorio. Estos gradientes son
generados usando vectores unitarios distribuidos de manera aleatoria en la esfera
unidad. Para calcular el ruido en un punto se usan los puntos de la celda en que se
encuentra, obteniendo el producto escalar del gradiente por el vector que va desde cada
punto de la celda de la rejilla al propio punto e interpolando.

97

F. 2. 4. Ruido de Perlin
Tipo particular del ruido anterior que usa gradientes fijos ya que la permutacin de
enteros ya otorga suficiente aleatoriedad. En cuanto a la funcin usada para interpolar,
esta era originalmente 3t2 2t3 pero la segunda derivada de sta no es 0 ni en t=1 ni en
t=0, por lo que el propio Perlin decidi ms adelante cambiar y usar 6t5 15t4 + 10t3.

F. 2. 5. Ruido de valores-gradientes
El ruido de gradientes es siempre 0 para las coordenadas enteras, por lo que es posible
que aparezca algn patrn. Para tratar de evitarlo el ruido de valores gradientes hace
una suma ponderada de un ruido de valores y un ruido de gradientes.

F. 2. 6. Ruido de rejilla compuesto


Como el primer tipo de ruido comentado pero usando algn kernel ms complejo que
simplemente utilizar los puntos de la celda donde nos encontremos para interpolar,
como por ejemplo una esfera de cierto radio o un cono. De esta manera se evitan
posibles errores alineados a los ejes.

F. 2. 7. Ruido de rejilla disperso


Este tipo de ruido utiliza puntos dispersos para realizar la interpolacin: no se eligen los
ms cercanos, sino puntos aleatorios.

F. 2. 8. Ruidos explcitos
En los ruidos explcitos el valor del ruido se precalcula antes y se guarda, de manera que
a la hora de utilizarlos solo hay que buscar el valor en una tabla, textura o cualquier
lugar donde est almacenado. Esto disminuye el tiempo necesario para obtener el ruido,
pero limita la flexibilidad.

F. 2. 9. Sntesis espectral de Fourier


Se genera un espectro discreto de frecuencias de manera aleatoria y ste se filtra para
que tenga el rango o forma deseados. Despus se aplica una transformada inversa de
Fourier para cambiar del domino de la frecuencia al del espacio, que ser el ruido.

F. 3. Fractales
Un fractal es un patrn que se repite a diferentes escalas y que se utiliza para obtener la
forma de un objeto irregular que no se podra conseguir con los mtodos de la geometra
clsica. Si a su construccin aadimos algn tipo de aleatoriedad tenemos un fractal
aleatorio.
En nuestro caso el patrn viene marcado por una funcin de ruido sumada a distintas
frecuencias y con diferentes escalas.
Una de las funciones fractales aleatorias ms sencillas y utilizadas es la conocida como
fBm, fractal brownian motion, definida por los siguientes parmetros:

98

Punto: lugar donde calculamos el valor del fractal.


H: incremento de la amplitud en cada frecuencia.
Lagunaridad: salto existente entre frecuencias sucesivas.
Octavas: nmero de frecuencias a sumar. Se usa el mismo nombre que en msica
porque normalmente el salto entre frecuencias es de 2.
A continuacin podemos ver el cdigo de dicha funcin:
float fbm(float2 punto, float H, float lagunaridad, float octavas)
{
float value = 0.0f, sum = 0.0f, freq = 1.0f, amp = 1.0f;
// Construccin del fractal
for (float i = 0.0f; i < octavas; i++)
{
value = noise(punto * freq);
sum += value * amp;
freq *= lagunaridad;
amp *= H;
}
return sum;
}

En este caso el patrn viene marcado directamente por el valor del ruido, pero podran
usarse funciones ms complejas como senos o polinomios.
En las figuras 51, 52 y 53 se presentan imgenes de MojoWorlds, mundos enteramente
construidos usando fractales y ruido, para comprobar la potencia de estas tcnicas.

Figura 51: Montaas fractales

99

Figura 52: Lago fractal

Figura 53: Ocano fractal

100

ANEXO G: DOCUMENTACIN DE LA
APLICACIN
A continuacin se presenta la documentacin referente a la aplicacin implementada
para la generacin del paisaje procedural. La documentacin se ha generado de manera
automtica usando el programa DoxyGen.

G. 1. Lista de clases
AudioEngine (Motor de audio )
Camera (Una camara )
Camera::ConstantBufferCam (Buffer con la posicion de la camara )
Camera::ConstantBufferMatrix (Buffer con las matrices de la camara )
Cielo (Cielo de la escena )
D3D11Manager (Controlador de Direct3D 11 )
Datos (Clase con varios datos necesarios )
Datos::ConstantBufferDatos (Buffer con datos para los shaders )
GPUProfiler (Profiler de la ejecucion de la GPU )
Light (Luz )
Light::ConstantBufferLight (Buffer con los datos de una luz )
ObjManager (Manejo de archivos .obj )
Paisaje (Paisaje de la escena )
Pajaros (Controlador de los pajaros )
Pajaros::InfoPajaro (Informacion de un pajaro )
Perlin (Datos del ruido de Perlin )
Planeta (Planeta fractal )
SamplerManager (Clase para el manejo de samplers de texturas
SceneManager (Controlador de la escena )
Shadow (Sombras )
Shadow::ConstantBufferMatrixShadow (Buffer con las matrices de la camara-luz )
TextureManager (Manejo de texturas externas )
VERTEX (Vertice )
WaveLoader (Cargador de archivos .wav )

G. 2. Documentacin de clases
AudioEngine Class Reference
Motor de audio.

Public Member Functions


1. HRESULT InitAudio ()
Iniciar el motor de audio.

2. void LoadSounds ()
Cargar los sonidos.

3. void Play ()
Iniciar reproduccion de sonidos.

101

4. void Clean ()
Liberar recursos.

Public Attributes
1. IXAudio2 * audioeng
Motor de audio.

2. IXAudio2MasteringVoice * audiodev
Audio device.

Camera Class Reference


Una camara.

Classes
1. struct ConstantBufferCam
Buffer con la posicion de la camara.

1. struct ConstantBufferMatrix
Buffer con las matrices de la camara.

Public Member Functions


1. void InitCamera (D3D11Manager *D3D)
Inicio de la camara.

2. void IniciarPaseoAereo ()
Iniciar paseo Aereo.

3. void IniciarPaseoPersona ()
Iniciar paseo Persona.

4. void ZoomIn ()
Acercar la camara.

5. void ZoomOut ()
Alejar la camara.

6. void MoveUp ()
Mover la camara hacia arriba.

7. void MoveDown ()
Mover la camara hacia abajo.

8. void MoveRight ()
Mover la camara hacia la derecha.

9. void MoveLeft ()
Mover la camara hacia la izquierda.

10. void LookRight ()


Girar la camara hacia la derecha.

11. void LookLeft ()


Girar la camara hacia la izquierda.

12. void LookUp ()


Girar la camara hacia arriba.

13. void LookDown ()


Girar la camara hacia abajo.

14. void Home ()


Posicion inicial.

15. void Aire ()


Posicion alejada.

102

16. void Place (XMVECTOR newPos, XMVECTOR newAt)


Colocar la cmara.

17. void UpdateMatrix (XMMATRIX *newWorld)


Actualizar matriz del mundo.

18. void UpdateCamera ()


Actualizar posicion y datos de la camara durante los recorridos.

19. void Clean ()


Liberar recursos.

Public Attributes
1. XMVECTOR camPos
Posicion de la camara.

2. bool camPaseoAereo
Variable que nos indica si estamos en medio del recorrido aereo.

3. bool camPaseoPersona
Variable que nos indica si estamos en medio del recorrido de la persona.

4. ID3D11Buffer * pCBufferMat
Constant buffer de las matrices de mundo, vista y proyeccion.

5. ID3D11Buffer * pCBufferCam
Constant buffer con la posicion de la camara.

Member Function Documentation


void Camera::InitCamera (D3D11Manager * D3D)
Parameters:
D3D
IN: Controlador de Direct3D
void Camera::Place (XMVECTOR newPos, XMVECTOR newAt)
Parameters:
newPos
IN: Nueva posicion
newAt
IN: Nuevo punto de mira
void Camera::UpdateMatrix (XMMATRIX * newWorld)
Parameters:
newWorld
IN: Nueva matriz

Camera::ConstantBufferCam Struct Reference


Buffer con la posicion de la camara.

Public Attributes
1. XMVECTOR CameraPos
Posicion de la camara.

Camera::ConstantBufferMatrix Struct Reference


Buffer con las matrices de la camara.

Public Attributes
1. XMMATRIX World
Mundo.

103

2. XMMATRIX View
Vista.

3. XMMATRIX Projection
Proyeccion.

Cielo Class Reference


Cielo de la escena.

Public Member Functions


1. void InitCielo (D3D11Manager *D3D)
Inicializar el cielo.

2. void Render (Camera *Cam, TextureManager *TextureMan, SamplerManager *SamplerMan)


Renderizar el cielo.

3. void UpdateCielo (Camera *Cam)


Actualizar posicion del cielo.

4. void Clean ()
Liberar recursos.

Member Function Documentation


void Cielo::InitCielo (D3D11Manager * D3D)
Parameters:
D3D
IN: Controlador de Direct3D
void Cielo::Render (Camera * Cam, TextureManager * TextureMan, SamplerManager *
SamplerMan)
Parameters:
Cam
IN: Camara de la escena
TextureMan
IN: Texturas
SamplerMan
IN: Samplers
void Cielo::UpdateCielo (Camera * Cam)
Parameters:
Cam
IN: Camara en torno a la que centramos el cielo

D3D11Manager Class Reference


Controlador de Direct3D 11.

Public Member Functions


1. void InitD3D (HWND hWnd, int windowWidth, int windowHeight)
Inicio de Direct3D.

2. void Clean ()
Liberar recursos.

Public Attributes
1. D3D11_VIEWPORT viewport
Viewport.

2. IDXGISwapChain * swapchain
Swap chain.

104

3. ID3D11Device * dev = NUL


Direct3D device interface.

4. ID3D11DeviceContext * devcon
Direct3D device context.

5. IDXGIFactory * factory
Interfaz para crear objetos DXGI.

6. IDXGIAdapter * adapter
Tarjeta grafica.

7. IDXGIOutput * adapterOutput
Monitor.

8. ID3D11RenderTargetView * rtv
Render Target View.

9. ID3D11Texture2D * pDSB
Depth stencil buffer.

10. ID3D11DepthStencilView * pDSV


Vista del depth buffer.

11. ID3D11InputLayout * pLayout


Formato de entrada a la pipeline (vertices)

12. ID3D11RasterizerState * pRStateCull


Configuracion de la etapa de rasterizado con culling.

13. ID3D11RasterizerState * pRStateNoCull


Configuracion de la etapa de rasterizado sin culling.

14. ID3D11BlendState * pBSTransparent


Blender state para usar transparencias.

Member Function Documentation


void D3D11Manager::InitD3D (HWND hWnd, int windowWidth, int windowHeight)
Parameters:
hWnd
IN: Ventana de la aplicacin
windowWidth
IN: Anchura de la ventana
windowHeight
IN: Altura de la ventana

Datos Class Reference


Clase con varios datos necesarios.

Classes
1. struct ConstantBufferDatos
Buffer con datos para los shaders.

Public Member Functions


1. void InitData (D3D11Manager *D3D)
Inicio de los datos.

2. void UpdateData (float d0, float d1, float d2, float d3)
Actualizar buffer de datos.

3. void Clean ()
Liberar recursos.

Public Attributes
1. int PaisajeX
Dimension X del paisaje.

105

2. int PaisajeZ
Dimension Z del paisaje.

3. int SizeX
Numero de puntos en X.

4. int SizeZ
Numero de puntos en Z.

5. ID3D11Buffer * pCBufferDat
Constant buffer con datos para los shaders.

Member Function Documentation


void Datos::InitData (D3D11Manager * D3D)
Parameters:
D3D
IN: Controlador de Direct3D
void Datos::UpdateData (float d0, float d1, float d2, float d3)
Parameters:
d0
IN: Primer dato del buffer
d1
IN: Segundo dato del buffer
d2
IN: Tercer dato del buffer
d3
IN: Cuarto dato del buffer

Datos::ConstantBufferDatos Struct Reference


Buffer con datos para los shaders.

Public Attributes
1. float data [4]
Tiempo, Tamao de la permutacion, SizeX/Latitud , SizeZ/Longitud.

GPUProfiler Class Reference


Profiler de la ejecucion de la GPU.

Public Member Functions


1. void InitProfiler (D3D11Manager *D3D)
Inicializar el profiler.

2. void SaveFrame1 ()
Guardar info de la imagen 1.

3. void SaveFrame2 ()
Guardar info de la imagen 2.

4. void Profile ()
Recoger y presentar los datos de un frame.

5. void InitEncloser ()
Inicio del frame encloser.

6. void EndEncloser ()
Fin del frame encloser.

7. void InitFrame ()
Inicio del frame.

8. void EndFrame ()
Final del frame.

106

9. void InitCalc ()
Inicio del calculo del agua.

10. void EndCalc ()


Fin del calculo del agua.

11. void InitRender ()


Inicio del renderizado.

12. void EndRender ()


Fin del renderizado.

13. void InitPipeline ()


Inicio de la ejecucion de la pipeline grafica.

14. void EndPipeline ()


Final de la ejecucion de la la pipeline grafica.

15. void Clean ()


Liberar recursos.

Member Function Documentation


void GPUProfiler::InitProfiler (D3D11Manager * D3D)
Parameters:
D3D
IN: Controlador de Direct3D

Light Class Reference


Luz.

Classes
1. struct ConstantBufferLight
Buffer con los datos de una luz.

Public Member Functions


1. void InitLight (D3D11Manager *D3D, Datos *Data)
Inicializacion de la luz.

2. void RotateRight ()
Girar luz hacia la derecha.

3. void RotateLeft ()
Girar luz hacia la izquierda.

4. void Home ()
Posicion inicial.

5. void UpdateLight ()
Actualizar la luz.

6. void Clean ()
Liberar recursos.

Public Attributes
1. XMFLOAT3 lightDir
Direccion de la luz.

2. XMVECTOR lightPos
Posicion de la luz.

3. XMVECTOR lightAt
Lugar al que mira.

4. XMMATRIX lightView
Matriz de vista de la luz.

107

5. XMMATRIX lightProjection
Matriz de proyeccion de la luz.

6. ID3D11Buffer * pCBufferLight
Buffer con los datos de la luz.

7. bool luzActualizada
Acabamos de actualizar la luz.

Member Function Documentation


void Light::InitLight (D3D11Manager * D3D, Datos * Data)
Parameters:
D3D
IN: Controlador de Direct3D
Data
IN: Datos del paisaje

Light::ConstantBufferLight Struct Reference


Buffer con los datos de una luz.

Public Attributes
1. XMFLOAT3 dirLight
Direccion de la luz.

2. float pad
Alineacion del buffer.

3. XMFLOAT4 colorLight
Color de la luz direccional.

4. XMFLOAT4 ambientLight
Componente ambiental.

ObjManager Class Reference


Manejo de archivos .obj.

Public Member Functions


1. void LoadObj (std::vector< VERTEX > *vertices, std::vector< DWORD > *indices, std::wstring
name, XMMATRIX *meshWorld, int *verticesMesh, int *indicesMesh, int tipo)

Carga un archivo .obj.

2. void SaveObj (VERTEX *vertices, UINT SizeX, UINT SizeZ, const char *name)
Crea un archivo .obj.

Member Function Documentation


void ObjManager::LoadObj (std::vector< VERTEX > * vertices, std::vector< DWORD > * indices,
std::wstring name, XMMATRIX * meshWorld, int * verticesMesh, int * indicesMesh, int tipo)
Parameters:
vertices
OUT: Vector con los vertices del objeto
indices
OUT: Vector con los ndices del objeto
name
IN: Fichero .obj
meshWorld
IN: Transformacion del objeto
verticesMesh
OUT: Numero de vertices del objeto
indicesMesh
OUT: Numero de indices
tipo
IN: Tipo de objeto

108

void ObjManager::SaveObj (VERTEX * vertices, UINT SizeX, UINT SizeZ, const char * name)
Parameters:
vertices
IN: Array con los vertices del objeto
SizeX
IN: Tamao en X del array
SizeZ
IN: Tamao en Z del array
name
IN: Nombre del fichero a crear

Paisaje Class Reference


Paisaje de la escena.

Public Member Functions


1. void InitPaisaje (D3D11Manager *D3D, Datos *Data)
Inicializacion del paisaje.

2. void CalcularPaisaje (Datos *Data, Perlin *PerlinData, SamplerManager *SamplerMan)


Calcular el paisaje inicial.

3. void CalcularViento (Datos *Data, Perlin *PerlinData, SamplerManager *SamplerMan)


Calculo del viento.

4. void UpdateAgua (Datos *Data, Perlin *PerlinData, SamplerManager *SamplerMan, Camera


*Cam, GPUProfiler *GPUProf)

Actualizar agua.

5. void Render (Datos *Data, SamplerManager *SamplerMan, TextureManager *TextureMan,


Light *Luz, Shadow *Shade, Camera *Cam)

Renderizado del paisaje.

6. void EscribirPaisaje ()
Guardar .obj del paisaje.

7. void Clean ()
Liberar recursos.

Public Attributes
1. ID3D11Buffer * pVBufferPaisaje
Buffer de vertices del paisaje.

2. ID3D11Buffer * pIBufferPaisaje
Buffer de indices del paisaje.

3. XMMATRIX paisajeWorld
Mundo del paisaje.

4. int numIndices
Numero total de indices.

Member Function Documentation


void Paisaje::InitPaisaje (D3D11Manager * D3D, Datos * Data)
Parameters:
D3D
IN: Controlador de Direct3D
Data
IN: Datos del paisaje
void Paisaje::CalcularPaisaje (Datos * Data, Perlin * PerlinData, SamplerManager * SamplerMan)
Parameters:
Data
IN: Datos del paisaje
PerlinData
IN: Datos del ruido de Perlin
SamplerMan
IN: Samplers de texturas

109

void Paisaje::CalcularViento (Datos * Data, Perlin * PerlinData, SamplerManager * SamplerMan)


Parameters:
Data
IN: Datos del paisaje
PerlinData
IN: Datos del ruido de Perlin
SamplerMan
IN: Samplers de texturas
void Paisaje::UpdateAgua (Datos * Data, Perlin * PerlinData, SamplerManager * SamplerMan,
Camera * Cam, GPUProfiler * GPUProf)
Parameters:
Data
IN: Datos del paisaje
PerlinData
IN: Datos del ruido de Perlin
SamplerMan
IN: Samplers de texturas
Cam
IN: Camara de la escena
GPUProf
IN: Profiler de la GPU
void Paisaje::Render (Datos * Data, SamplerManager * SamplerMan, TextureManager *
TextureMan, Light * Luz, Shadow * Shade, Camera * Cam)
Parameters:
Data
IN: Datos del paisaje
SamplerMan
IN: Samplers de texturas
TextureMan
IN: Texturas externas
Luz
IN: Luces
Shade
IN: Sombras
Cam
IN: Camara

Pajaros Class Reference


Controlador de los pajaros

Classes
1. struct InfoPajaro
Informacion de un pajaro.

Public Member Functions


1. void InitPajaros (D3D11Manager *D3D)
Inicializacion de los pajaros.

2. void UpdatePajaros ()
Actualizar posicion de los pajaros.

3. void Render (Camera *Cam)


Renderizar los pajaros.

4. void Clean ()
Liberar recursos.

Member Function Documentation


void Pajaros::InitPajaros (D3D11Manager * D3D)
Parameters:
D3D
IN: Controlador de Direct3D
void Pajaros::Render (Camera * Cam)
Parameters:
Cam
IN: Camara de la escena

110

Pajaros::InfoPajaro Struct Reference


Informacion de un pajaro.

Public Attributes
1. XMMATRIX pajaroWorld
Mundo del pajaro.

2. XMMATRIX pajaroRotation
Rotacion del pajaro.

3. XMMATRIX pajaroTranslation
Translacion de los pajaros.

4. XMVECTOR pajaroPos
Posicion del pajaro.

5. int pajaroEstadoActual
Estado actual de las alas del pajaro.

6. LARGE_INTEGER pajaroTEstado
Tiempo para controlar el estado del pajaro.

7. LARGE_INTEGER pajaroTPosicion
Tiempo para controlar la posicion de los pajaros.

8. XMVECTOR pajaroGoals [3]


Puntos del camino que sigue el pajaro.

9. int pajaroActualGoal
Actual objetivo del movimiento del pajaro.

10. XMVECTOR pajaroDir


Direccion en la que se mueve el pajaro.

Perlin Class Reference


Datos del ruido de Perlin.

Public Member Functions


1. void InitPerlin (D3D11Manager *D3D)
Crear datos relativos al ruido de Perlin.

2. void Clean ()
Liberar recursos.

Public Attributes
1. ID3D11ShaderResourceView * pSRVTexPerm
Vista con la textura de la permutacion de numeros enteros.

2. ID3D11ShaderResourceView * pSRVTexGrad3
Vista con la textura de los gradientes 3D.

3. ID3D11ShaderResourceView * pSRVTexGrad2
Vista con la textura de los gradientes 2D.

4. float sizePerm = 1024.0f


Tamao de la permutacion.

Member Function Documentation


void Perlin::InitPerlin (D3D11Manager * D3D)
Parameters:
D3D
IN: Controlador de Direct3D

111

Planeta Class Reference


Planeta fractal.

Public Member Functions


1. void InitPlaneta (D3D11Manager *D3D)
Inicio del planeta.

2. void CalcularPlaneta (Perlin *PerlinData, SamplerManager *SamplerMan, Datos *Data)


Calcular fractal del planeta.

3. void Render (Camera *Cam, Perlin *PerlinData, SamplerManager *SamplerMan, Datos *Data)
Renderizar el planeta.

4. void UpdatePlaneta ()
Actualizar planeta.

5. void Clean ()
Liberar recursos.

Member Function Documentation


void Planeta::InitPlaneta (D3D11Manager * D3D)
Parameters:
D3D
IN: Controlador de Direct3D
void Planeta::CalcularPlaneta (Perlin * PerlinData, SamplerManager * SamplerMan, Datos * Data)
Parameters:
PerlinData
IN: Datos del ruido de Perlin
SamplerMan
IN: Samplers de texturas
Data
IN: Datos del paisaje
void Planeta::Render (Camera * Cam, Perlin * PerlinData, SamplerManager * SamplerMan, Datos
* Data)
Parameters:
Cam
IN: Camara
PerlinData
IN: Datos del ruido de Perlin
SamplerMan
IN: Samplers de las texturas
Data
IN: Datos del planeta

SamplerManager Class Reference


Clase para el manejo de samplers de texturas.

Public Member Functions


1. void InitSamplers (D3D11Manager *D3D)
Inciar samplers de texturas.

2. void Clean ()
Liberar recursos.

Public Attributes
1. ID3D11SamplerState * pPointMirrorSampler
Sampler por puntos, mirror.

2. ID3D11SamplerState * pLineMirrorSamplerComp
Sampler linear con comparacion, mirror.

3. ID3D11SamplerState * pLineWrapSampler
Sampler lineal, wrap.

112

Member Function Documentation


void SamplerManager::InitSamplers (D3D11Manager * D3D)
Parameters:
D3D
IN: Controlador de Direct3D

SceneManager Class Reference


Controlador de la escena.

Public Member Functions


1. void InitScene (D3D11Manager *D3D)
Inicializar la escena.

2. void InitFractals (D3D11Manager *D3D)


Iniciar los fractales.

3. void InitFrame ()
Marcar inicio de frame.

4. void UpdateScene (D3D11Manager *D3D)


Actualizar escena.

5. void RenderScene (D3D11Manager *D3D)


Renderizar escena.

6. void EndFrame ()
Marcar final de frame.

7. void ShowFrameInfo ()
Mostrar informacion del frame.

8. void Modify (WPARAM wParam)


Modificar escena.

9. void Clean ()
Liberar recursos.

Member Function Documentation


void SceneManager::InitScene (D3D11Manager * D3D)
Parameters:
D3D
IN: Controlador de Direct3D
void SceneManager::InitFractals (D3D11Manager * D3D)
Parameters:
D3D
IN: Controlador de Direct3D
void SceneManager::UpdateScene (D3D11Manager * D3D)
Parameters:
D3D
IN: Controlador de Direct3D
void SceneManager::RenderScene (D3D11Manager * D3D)
Parameters:
D3D
IN: Controlador de Direct3D
void SceneManager::Modify (WPARAM wParam)
Parameters:
wParam
IN: Tecla pulsada

113

Shadow Class Reference


Sombras.

Classes
1. struct ConstantBufferMatrixShadow
Buffer con las matrices de la camara-luz.

Public Member Functions


1. void InitShadow (D3D11Manager *D3D, Light *Luz, XMMATRIX *world)
Inicializacion de las sombras.

2. void CalcularMapa (ID3D11Buffer *pVBuffer, ID3D11Buffer *pIBuffer, int numIndices)


Calcular mapa de sombras.

3. void UpdateShadow (Light *Luz, XMMATRIX *world)


Actualizar sombras.

4. void Clean ()
Librerar recursos.

Public Attributes
1. ID3D11Buffer * pCBufferShadow
Constant buffer de las matrices de mundo, vista y proyeccion para las sombras.

2. ID3D11ShaderResourceView * pSRVShadow
Vista para leer el mapa de sombras.

Member Function Documentation


void Shadow::InitShadow (D3D11Manager * D3D, Light * Luz, XMMATRIX * world)
Parameters:
D3D
IN: Controlador de Direct3D
Luz
IN: Luz que genera las sombras
world
IN: Mundo de la escena
void Shadow::CalcularMapa (ID3D11Buffer * pVBuffer, ID3D11Buffer * pIBuffer, int numIndices)
Parameters:
pVBuffer
IN: Vertices de la geometria que genera sombra
pIBuffer
IN: Indices de la geometria que genera sombra
numIndices
IN: Numero de indices de la geometria
void Shadow::UpdateShadow (Light * Luz, XMMATRIX * world)
Parameters:
Luz
IN: Luz que genera las sombras
world
IN: Mundo de la escena

Shadow::ConstantBufferMatrixShadow Struct Reference


Buffer con las matrices de la camara-luz.

Public Attributes
1. XMMATRIX World
Mundo.

2. XMMATRIX View
Vista.

3. XMMATRIX Projection
Proyeccion.

114

TextureManager Class Reference


Manejo de texturas externas.

Public Member Functions


1. void InitTextures (D3D11Manager *D3D)
Cargar texturas.

2. void Clean ()
Liberar recursos.

Public Attributes
1. ID3D11ShaderResourceView * pSRVTexMon
Vista de la textura de la montaa

2. ID3D11ShaderResourceView * pSRVTexNormalMon
Vista de la textura con las normales de la montaa

3. ID3D11ShaderResourceView * pSRVTexSand
Vista de la textura de la playa.

4. ID3D11ShaderResourceView * pSRVTexNormalSand
Vista de la textura con las normales de la playa.

5. ID3D11ShaderResourceView * pSRVTexWetSand
Vista de la textura de la playa, zona mojada.

6. ID3D11ShaderResourceView * pSRVTexNormalWetSand
Vista de la textura con las normales de la playa, zona mojada.

7. ID3D11ShaderResourceView * pSRVTexPalmera1
Vista de la textura de la palmera 1.

8. ID3D11ShaderResourceView * pSRVTexPalmera2
Vista de la textura de la palmera 2.

9. ID3D11ShaderResourceView * pSRVTexPalmera3
Vista de la textura de la palmera 3 y 4.

10. ID3D11ShaderResourceView * pSRVTexPalmera5


Vista de la textura de la palmera 5.

11. ID3D11ShaderResourceView * pSRVTexSky


Vista de la textura del cielo.

Member Function Documentation


void TextureManager::InitTextures (D3D11Manager * D3D)
Parameters:
D3D
IN: Controlador de Direct3D

VERTEX Struct Reference


Vertice.

Public Attributes
1. float x
Posicion.x.

2. float y
Posicion.y.

3. float z
Posicion.z.

4. float nx
Normal.x.

115

5. float ny
Normal.y.

6. float nz
Normal.z.

7. float u
Coordenada u de la textura.

8. float v
Coordenada v de la textura.

9. float w
Coordenada w de la textura.

10. int tipo


Tipo de objeto al que pertenece, agua, playas, montaas o palmeras.

11. int numTriangulos


Numero de triangulos a los que pertenece.

12. int triangulos [6]


Triangulos a los que pertenece.

WaveLoader Class Reference


Cargador de archivos .wav.

Public Member Functions


1. HRESULT CargarSonido (WAVEFORMATEXTENSIBLE *wfx, XAUDIO2_BUFFER *buffer,
TCHAR *strFileName)

Cargar fichero .wav.

Member Function Documentation


HRESULT WaveLoader::CargarSonido (WAVEFORMATEXTENSIBLE * wfx,
XAUDIO2_BUFFER * buffer, TCHAR * strFileName)
Parameters:
wfx
Out: Formato de audio
buffer
Out: Buffer de audio
strFileName
In: Nombre del fichero

116

También podría gustarte