1 Eduardo Cortejoso 04-36867, Jormar Arellano 05-37840 Real Time Shading Languages Resumen (Abstract)— Se tratan dos temas principales, los Shaders y los Real Time Shading Languages. Los Real Time shading Languages implementan los distintos tipos de shader para aprovechar al maximo los beneficios de cada uno. Pasaremos a explicar que son cada uno de estos conceptos y como se relacionan. Palabras clave— Shader, Real Time Shading, Pixel Shader, Geometry Shader, Vertex Shader I. INTRODUCCIÓN L OS Real Time Shading Languages son una herramienta sumamente imporante para generar una buena calidad de imagen a tiempo real. Cabe destacar que al renderizar una imagen en tiempo real, tenemos que considerar el tiempo y costo que pueden tener las implementaciones de estos lenguajes y sus shaders respectivos. Es importante analizar como cada Lenguaje implementa los distintos tipos de shader, como aprovechan sus beneficios y como trabajan entre ellos. II. REAL TIME SHADING LANGUAGES Esta es la categoría de lenguajes que se usan para crear los Shaders. Existe una variedad de estos lenguejes, pero en nuestro estudio nos enfocaremos en los 3 más importantes: GLSL (para openGL), HLSL (Desarrollado por Microsoft), y Cg (Desaollado por NVIDIA). Independientemente del lenguaje que utilicemos al momento de crear Shaders, hay que tener en mente varias cosas: 1. El lenguaje provee, por defecto, acceso a las propiedades establecidas por el usuario (texturas, luces, etc…), y lo hace a través de variables. Estas variables son de solo lectura. 2. Independientemente del lenguaje que se este usando, hay propiedades que no son modificables desde los Shaders (texturas, fuentes de luz, matriz de proyección, matriz de normales, etc…). 3. El lenguaje provee un mecanismo especial para la intercomunicación entre los Shaders. Las diferencias entre un lenguaje y otro está en los detalles sintácticos, y en el alcance del lenguaje. De esto hablaremos más adelante. III. GLSL GLSL es el acrónimo para OpenGL Shading Language. También conocido como GLslang, GLSL es un lenguaje de código abierto basado en C/C++, que permite modificar directamente el pipeline del procesamiento gráfico (por medio de Shaders). En nuestro estudio, este fue el lenguaje que tomamos como referencia principal ilustrar los pasos a seguir para crea un Shader. Algunos de los beneficios de este GLSL son: Soporte multiplataforma, y compactibilidad en múltiples sistemas operativos, incluyendo mac OS, Windows, y Linux. Los Shaders escritos en este lenguaje pueden ser usados en cualquier trajea de video, independientemente del vendedor. Es posible generar código optimizado para la arquitecura de una tarjeta gráfica en particular en particular, ya que cada vendedor provee, un driver que incluye el compilador de GLSL. A. Tipos de datos en GLSL Hay 3 tipo de datos primitivos convencionales: float, int, bool. Para todos estos, disponemos de unos ipos particulares para manipular vectores (de 2, 3, y cuatro dimensiones, respectivamente): vec2, vec3, vec4 vector de float ivec2, ivec3, ivec4 vector de int bvec2, bvec3, bvec4 vector de bool En particular, para los float tenemos un tipo especial para manejar matrices de 2x2, 3x3, y 4x4, respectivamente: mat2, mat3, mat4 Samplers son tipos especiales para representar texturas, y hacer “texture sampling”. Este tipo de variables siempre es uniform, es decir, no cambia dentro de la ejecución de un Shader. Los tipos de samplers disponibles son: sampler1D, sampler2D, sampler3D (para texturas de 1, 2 y 3 dimensiones), entre otros… Modificadores de variables Sirven para determinar las salidas y entradas de un Shader. En escencia, determinan el comportamiento de una variable dentro de un Shader. Son tres: Uniforms: son valores que no camian durante el rendering (posición ó color de la luz, texturas, etc…) Este tipo de variable es de solo lectura, y esta disponible en cualquier shader (Vertex, Geometric y Fragment). Attributes: Disponibles solo en el Vertex Shader. Son variables 2 que contienen toda la información referente a un vertice: posición, normal, color, etc. Son de solo lectura. Varyings: Sirven de puente para comunicar un Vertex Shader conun Fragment Shader. Estas variables son interpoladas entre las primitivas, y no se puede modificar su valor en el Fragment Shader. Para usarla, hay que declararla como variable global en el código fuente de ambos Shaders. Algunas variables uniformes predefinidas: gl_ModelViewMatrix, gl_ModelViewProjectionMatrix, gl_NormalMatrix Algunos variables attributes predefinidas (representan una propiedad de un vertice) gl_Vertex (posición), gl_Normal (vector normal), gl_Color (color). Algunas variables “Varyings” predefinidas: gl_FrontColor, gl_BackColor Si, en lugar de establecer la componente z a cero, usamos una función seno respecto a x tendríamos: void main(void) { vec4 v = vec4(gl_Vertex); v.z = sin(5.0*v.x )*0.25; gl_Position = gl_ModelViewProjectionMatrix * v; } El lenguaje también proporciona algunas funciones predefinidas, a fin de agilizar operaciones comunes con vecores y matrices. Por ejemplo: dot (producto punto), cross (producto cruz) , normalize (normaliza un vector). B. Vertex Shader en GLSL Cuando estamos escribiendo un Vertex Shader, debemos, por lo menos, establecer el valor de la variable predefinida gl_Position (vector de 4 dimensiones), la cual indica la posición de ese vértice en el espacio. En el siguiente ejemplo, modificamos directamente la posición de un vértice (exactamente, establecemos la componente z en cero). void main(void) { vec4 v = vec4(gl_Vertex); v.z = 0.0; gl_Position = gl_ModelViewProjectionMatrix * v; } El resultado (visto desde varios angulos): C. Fragment Shader en GLSL Cuando estamos escribiendo un Fragment Shader, debemos, por lo menos, establecer el valor de la variable predefinida gl_FragColor (vector de 4 dimensiones), la cual indica el color final de ese pixel, que va a parar al frame buffer. Como ejemplo, tenemos este trivial fragment Shader: void main(void) { gl_FragColor = vec4(0.9, 0.2, 0.2, 1.0); } Que da como resultado que todos los píxeles se pinen de un tono rojizo. D. Geometric Shader Los geometric Shader estan entre el Vertex Shader, y el Fragment Shader. Tienen la habilidad de crear nuevos vértices, y cambiar la geometría a partir de la ya exsitente. 3 void main(void) { int i; for(i=0; i< gl_VerticesIn; i++){ gl_Position = gl_PositionIn[i]; EmitVertex(); } EndPrimitive(); }; void main( in a2v IN, out v2p OUT ) { OUT.Position = mul(IN.Position, ModelViewMatrix); OUT.Color = IN.Color; } B. Pixel Shader //New piece of geometry! We just swizzle the x and y terms for(i=0; i< gl_VerticesIn; i++){ gl_Position = gl_PositionIn[i]; gl_Position.xy = gl_Position.yx; EmitVertex(); } eNdPrimitive(); } IV. HLSL Acrónimo para High Level Shading Language, HLSL es un lenguaje desarrllado por Microsoft para usarlo con el API de Direct3D de Microsoft. Es análogo a GLSL en cuanto a funcionalidad, variando sólo en las características propias del lenguaje. Para comenzar, HLSL también posee tipos de datos especiales para denotar vectores y matrices. En ese aspecto, es más flexible que GLSL, ya que aca si se pueden usar matrices que no sean cuadradas: 4x3, 2x3, etc. También posee tipos particulares para manejar texturas. La forma de crear Shader es ligeramente diferente que en GLSL, ya que eneste lenguaje, se deben definir las estucturas de entrada y salida, para Shader, y usarlas en la declaración del main en el programa principal de un Shader. A. Vertex Shader Aca vemos un ejemplo: float4x4 ModelViewMatrix; /* * Estructura de entrada. Es lo que espera el Vertex Shader */ struct a2v { float4 Position : POSITION; float4 Color : COLOR0; }; /* * Estructura de salida. Es lo que el Vertex Shader le pasa al Fragment Shader */ struct v2p { float4 Position : POSITION; float4 Color : COLOR0; float brightness; sampler2D tex0; sampler2D tex1; /* * Estructura de entrada. Es lo que el Pixel Shader espera del Vertex Shader */ struct v2p { float4 Position : POSITION; float2 Texcoord0 : TEXCOORD0; float2 Texcoord1 : TEXCOORD1; float4 Color : COLOR0; }; struct p2f { float4 Color : COLOR0; }; void main( in v2p IN, out p2f OUT ) { float4 color = tex2D(tex0, IN.Texcoord0); float4 bump = tex2D(tex1, IN.Texcoord1); OUT.Color = brightness * IN.Color * color; } V. CG Este es un Shading language desarrollado por Nvidia, en colaboración con Microsoft. Por esto ultimo, es extremadamente similar al lenguaje HLSL. Por consiguiente, hereda muchas de las características sintácticas de HLSL, mientras que ofrece un mayor desempaño para las tarjetas Nvidia. Su diferencia principal radica en que este lenguaje puede ser compilado para diferentes tarjetas de video, brindando asi la posibilidad de compilar, el mismo código fuente, para openGL ó DirectX. La forma de elaborar un Shader es similar a HLSL, por lo que pasaremos a discutir algunas características de este lenguaje en particular. A. Características del lenguaje 4 CG proporciona las estructuras y los arreglos, incluyendo matrices multidimensionales. También proporciona todos los operadores aritméticos de C (, *, /, etc.), un tipo booleano y los operadores booleanos y relacionales (| |, &&, !) . También posee el famoso operador ternario de los lenguajes de programación (?:). El usuario puede definir sus propias funciones (aunque no pueden definirse funciones recursivas). Cg proporciona un subconjunto de control de flujo de las construcciones C (do, while, for, if, break, continue)… otras construcciones como GOTO no se admiten en la aplicación actual del CG actual sino que se reservan las palabras clave necesarias. Al momento de compilar un programa en Cg, uno escoge el perfil que desea para dicha compilación; es decir, se especifica si se compila un Vertex Shader, un Geometric Shader, o un Fragment Shader. Al igual que C, Cg no obliga a la precisión y el alcance de sus datos tipos. En la práctica, el perfil elegido para la compilación determina la la representación concreta para cada tipo de datos. float, half, y double pretenden representar valores continuos. Int es un entero tipo de datos, normalmente se usa para recorrer e indexación. CG proporciona # include, # define, # ifdef, etc emparejar la C preprocesador. También se soporta la sobrecarga de funciones. Los tipos especiales de Cg para manejar vectores y matrices, son los mismos que HLSH. Por ejemplo, float4 vec1 = float4(4.0, -2.0, 5.0, 3.0); …declara un vector de 4 dimensiones. El lenguaje provee una librería estandar para manipular operaciones comunes entre vectores y matrices VI. CONCLUSIONES Existen tres lenguajes principales para programar directamente en un GPU: GLSL (openGL), HLSL (para DirectX),y Cg (Nvidia). Sin importar que tipo de Shader se quiera crear, debemos de usar alguno de estos tres lenguajes. A la hora de elegir un lenguaje en concreto, lo más importante es tener claro cual es la plataforma objetivo del programa, y con que tecnologías contamos. GLSL y Cg son lenguajes bastante adaptables en cualquier plataforma (soporte para Windows, linux y mac OS), mientras que HLSL sólo tiene soporte en Windows. GLSL es un lenguaje que esta soportado por casi todos los proveedores de tarjetas graficas, los cuales incluyen en sus drivers un compilador para dicho lenguaje, logrando optimizaciones particulares para hardware particulares. HLSL esta estrechamente ligado con DirectX , y Window. Algunas consolas de videojuegos (como la X-Box) son compatibles con este lenguaje. Este lenguaje es mucho más flexible, sintácticamente hablando, que GLSL, ya que ofrece dimensiones de matrices variadas (en GLSL todas las matrices son cuadradas), y algunos alegan que a la hora de escribir un Shader en particular, quedan mucho más claros los parámetros de entrada y salida del mismo. Cg es un lenguaje más neutral. Si bien es extremadamente similar a HLSL, permite ser compilado para Nvidia y DirectX. Ofrece compactibilidad con múltiples APIs (OpenGL, DirectX 8 y DirectX 9). Más aún, el compilador puede ser configurado para que genere el lenguaje ensamblador compactible con el estandar de openGL, permitiendo optimizar manualmente los aspectos que se consideren necesarios. Ninguno de estos lenguajes pretende reemplazar a cualquier otro de propósito general. Ciertamente, son lenguajes especializados en el área, que persiguen los mismos objetivos y tienen el mismo alcance, algunos dotados de optimizaciones para tecnologías específicas, estableciendo cada uno una metodología diferente para alcanzar la meta, los Shaders. VII. REFERENCES http://en.wikipedia.org/wiki/GLSL http://en.wikipedia.org/wiki/Cg_%28programming_language% 29 http://nehe.gamedev.net/data/articles/article.asp?article=21 http://cirl.missouri.edu/gpu/glsl_lessons/glsl_geometry_shader /index.html http://www.gamedev.net/columns/hardcore/dxshader1/ http://www.gamedev.net/columns/hardcore/dxshader2/ http://www.gamedev.net/columns/hardcore/dxshader3/ http://www.gamedev.net/columns/hardcore/dxshader4/