Primer acercamiento a Shaders con GLSL
Abstract:
Se brinda una introducción al manejo de shaders, particularmente en el lenguaje GLSL. Se muestra su forma de trabajo, su utilización, la instalación de las bibliotecas necesarias para trabajar con GLSL y al final se muestra una pequeña aplicación que hace uso de Shaders.
Introducción
OpenGL (Open Graphics Library) es una especificación desarrollada por Silicon Graphics Inc. para la creación de aplicaciones que produzcan gráficos 2D y 3D.
Para trabajar con OpenGL es recomendable utlizar GLUT (OpenGL Utility Toolkit) el cual es una biblioteca escrita por Mark Kilgard para facilitar el desarrollo de aplicaciones con OpenGL sin entrar en detalles minuciosos de cualquier entorno en particular. No debe confundirse con GLU (OpenGL Utility Library) el cual es un conjunto de funciones de dibujado basadas en las primitivas de OpenGL.
Antecedentes
Anteriormente solo era posible configurar el funcionamiento de la tarjeta gráfica (si la tarjeta lo soportaba) y utilizar los modelos definidos por OpenGL para iluminación, sombreado, etc. No era posible programar la tarjeta gráfica. A partir de 2001 con el advenimiento de las tarjetas NVIDIA GeForce 3 y ATI Raedon 8500 fue posible alcanzar virtualmente grandiosos efectos creando pequeños programas de longitud fija que serían ejecutados por el GPU. Pero tales programas eran difíciles de codificar puesto que se escribían en un lenguaje pseudo-ensamblador y tenían algunas limitaciones.
GLSL (OpenGL Shading Lenguage) es un lenguaje de programación (similar a C/C++) creado por OpenGL ARB (Architecture Review Board) para crear programas (llamados shaders ) que serán ejecutados en la GPU.
GLSL permitió utilizar shaders más complejos y de tamaño variable, subrutinas, ciclos, arreglos de longitud variable, pero sobre todo un lenguaje de programación más familiar para la mayoría de los desarrolladores.
Ventajas
La ventaja de usar shaders es la gran mejora en el despeño de cálculos de ilumincación y transformación de geometría. Por su naturaleza intrínsecamente paralelizable, los shaders pueden aplicar transformaciones sobre un gran conjunto de elementos al mismo tiempo, e.g., cada pixel en un area de la pantalla. Con shaders es posible crear un modelo de ilumincación propio en lugar de usar el modelo fijado para la ilumincación de OpenGL.
Inicialmente los shaders fueron creados para realizar el sombreado (shading) de pixeles (i.e., la variación de niveles de oscuridad en un modelo) y es precisamente de esta técnica por la cual proviene su nombre: shader.
Otro gran beneficio de los shaders es que podemos transferir carga de trabajo, como el movimiento de algunos gráficos, del CPU al GPU, liberando al CPU para que pueda realizar tareas adicionales. También es posible manipular sistemas de partículas, renderizado de alto rango dinámico HDR, iluminación pixel por pixel, cómputo de propósito genreal (GPGPU), etc.
Existen dos tipos de shaders en GLSL: Vertex Shader y Fragment Shader. Ambos forman parte del pipeline de rendering de OpenGL.
|
|
Vertex Shader
Este tipo de shader se ejecutan sobre cada uno de los vértices de entrada al procesador gráfico. Proporcionan un control general sobre todos los vértices, sus datos asociados y su manipulación (transformaciones, normalización, iluminación, color, etc.). Cuando un conjunto completo de vertex shaders es compilado y enlazado, se genera un vertex shader ejecutable que trabaja sobre el procesador de vértices.
Desde otro punto de vista, el vertex shader es un archivo fuente que contiene el código de entrada para el procesador gráfico.
Fragment Shader
Trabaja sobre cada fragmento generado durante el proceso de rasterización, al igual que el vertex shader permite manipular vértices, el fragment shader permite manipular fragmentos (aplicación de texturas, niebla, convoluciones, etc). Cuando un conjunto de fragment shaders es compilado, se genera un fragment shader ejecutable que trabaja sobre el procesador de fragmentos. Un shader de fragmentos no puede cambiar una pocisión de algún fragmento, así como tampoco es permitido el acceso a fragmentos vecinos.
Desde otro punto de vista, el fragment shader es un archivo que contiene el código fuente que se ejecutará en el procesador de fragmentos.
Para fines ilustrativos se nombrará vertShader.glsl al archivo que contiene el código fuente del vertex shader y fragShader.glsl al respectivo archivo del fragment shader. Realmente el nombre y la extensión de estos archivos es irrelevante.
Tipos de datos
Al igual que en C, existen tipos de datos en GLSL para respresentar
diferentes valores, a continuación se presentan los más elementales.
|
Existen vectores de tipos de datos que nos permiten manipular un conjunto (arreglo) del mismo tipo de dato.
- vec2, vec3, vec4
- Vectores de flotantes de dos, tres y cuatro entradas
pectivamente. - ivec2, ivec3, ivec4
- Vectores de enteros de dos, tres y cuatro entradas
respectivamente. - bvec2, bvec3, bvec4
- Vectores de booleanos de dos, tres y cuatro entradas
respectivamente. - mat2, mat3, mat4
- Matríz de flotantes de 2×2, 3×3 y 4×4 respectivamente.
Instalando y configurando GLSL.
Antes de utlizar shaders en GLSL, se deben tener instaladas algunas bibliotecas que faciltan su desarrollo. Tal es el caso de GLUT y GLEW.
La instalación de GLUT se puede hacer desde cualquier administrador de paquetes. Solo basta con instalar:
- freeglut3
- freeglut3-dev
- libglut3
- libglut3-dev
Adicionalmente se deben tener los paquetes virtuales:
- freeglut-dev
- libglut
- libglut-dev
- libhugs-glut
GLEW proporciona mecanismos eficientes que nos permiten determinar cuales extensiones de OpenGL son soportadas por nuestra plataforma.
Para instalar GLEW se puede obtener de:
http://sourceforge.net/projects/glew/files/glew/1.5.3/glew-1.5.3.tgz/download
Lo cual nos permite obtener un archvio llamado glew-1.5.3.tgz. Ahora abrimos una temrminal y escribimos:
$ tar zxvf glew-1.5.3.tgz $ cd glew-1.5.3.tgz/ $ sudo make $ sudo make install
Lo cual debe instalar las bibliotecas de GLEW en /usr/include/GL y /usr/lib
Para obtener información adicional se puede consultar:
http://glew.sourceforge.net/install.html
Para compilar en OpenGL:
gcc -lglut -lGL example.c
Para compilar en GLEW:
gcc -lGLEW -lglut -lGL example.c
Prueba de soporte para GLSL
Para comprobar que nuestra instalación de GLEW y de OpenGL ha sido correcta, así como para verificar si nuestra plataforma y tarjeta gráfica soportan los shaders de GLSL, debemos compilar y ejecutar el siguiente código.
/* *** glslSupport.c *** @author Jorge Alejandro Gutierrez Orozco Checks whether the platform supports GLSL shaders with GLEW. compilation: gcc -lglut -lGL -lGLEW glslSupport.c -o glslSupport execution ./glslSupport */ #include <GL/glew.h> #include <GL/glut.h> #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { glutInit(&argc, argv); glutCreateWindow("Are Shaders Suported ?"); /* you need to create a valid OpenGL rendering context */ GLenum err = glewInit(); printf("\nis GLEW suported?"); if (GLEW_OK != err) { /* glewInit failed */ printf("\n\tStatus: Error - %s\n", glewGetErrorString(err)); } else { printf("\n\tStatus: Using GLEW %s\n", glewGetString(GLEW_VERSION)); } printf("\nAre vertex and fragments programs suported?"); if (GLEW_ARB_vertex_program && GLEW_ARB_fragment_program) { printf("\n\tIt is safe to use the ARB_programs extensions here.\n\n "); } else { printf("\n\tNot Totally ready \n\n"); exit(1); } return EXIT_SUCCESS; }
Uso de Shaders
Existen una serie de procesos que se deben hacer para utilizar un shader:
- Obtener del código fuente del shader a partir de un archivo.
- Crear los objetos shaders y el objeto programa.
- Cargar los objetos shaders con el código leído del archivo fuente .
- Compilar los Objetos Shaders
- Adjuntar los shaders al objeto programa.
- Ligar el objeto programa con nuestra aplicación.
- Indicar a nuestra aplicación que utilice nuestro objeto programa en lugar de las funciones de OpenGL.
Un objeto shader representa el código fuente, un objeto programa representa una parte usable del pipeline de rendering. El objeto programa contiene tanto al objeto vertex shader como al objeto fragment shader.
Descripción
Antes de empezar a utilizar shaders, debemos crear una aplicación OpenGL, puede ser cualquier ejemplo, sería bueno compilarlo y ejecutarlo para comprobar que al menos las bibliotecas de GLUT están correctamente instaladas y nuestro hardware está configurado adecuadamente.
Después debemos agregar la biblioteca de GLEW.
#include <GL/glew.h>Se deben definir los objetos de los shaders y el objeto programa que los contendrá de manera que sean accesibles de cualquier lugar de nuestra aplicación.
GLhandleARB vShaderObj,fShaderObj,programObject;
A continuación debemos obtener el código fuente de ambos shaders a partir de los archivos.
char *vertexSource = textfileRead("vertShader.glsl"); char *fragmentSource = textfileRead("fragShader.glsl");
Crear los objetos shaders y el objeto programa.
vShaderObj = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); fShaderObj = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); programObject = glCreateProgramObjectARB();
Agregar el código fuente obtenido a nuestros objetos shaders.
const char * vs = vertexSource; const char * fs = fragmentSource; glShaderSourceARB(vShaderObj, 1, &vs,NULL); glShaderSourceARB(fShaderObj, 1, &fs,NULL);
Donde:
- vShaderObj
- Objeto shader al cual se le agregará el código fuente obtenido.
- 1
- Número de cadenas enviadas al objeto shader.
- vs
- Apuntador al código fuente.
- NULL
- Todas las cadenas son terminadas con NULL.
Para compilar los objetos shaders:
glCompileShaderARB(vShaderObj); glCompileShaderARB(fShaderObj);
Se debe enlazar los objetos shaders compilados a nuestro objeto programa:
glAttachObjectARB(programObject,vShaderObj); glAttachObjectARB(programObject,fShaderObj);
Ligar el objeto programa con nuestra aplicación e indicarle que lo use.
glLinkProgramARB(programObject); glUseProgramObjectARB(programObject);
Eliminar un shader
Antes de eliminar un shader se debe desligar de todos los objetos.
void glDetachObjectARB(GLhandleARB container, GLhandleARB attached); void glDeleteObjectARB(GLhandleARB object);
Ejemplos
Para efectos ilusatrtivos se ha implementado el siguiente ejemplo:
Sin shaders la imagen original resulta:

Veamos el siguiente fragment shader:
/* fragShader.glsl */ void main (void) { gl_FragColor = vec4 (0.5, 0.4, 0.3, 1.0); }
Y también agregamos el siguiente vertex shader:
/* vertShader.glsl */ void main(void) { vec4 v = gl_Vertex; v.x = v.x * 0.2; v.y = v.y * 0.6; gl_Position = gl_ModelViewProjectionMatrix * v; }
La imagen obtenida sería similar a la siguiente:
Como se puede observar a la figura, utilizando el mismo código es posible hacer modificaciones a un modelo, en este sencillo ejemplo se escala la figura en el vertex shader y se le cambia el color en el fragment shader.
Problemas comunes.
AL momento de compilar se pueden generar los siguientes errores:
cannot find -lgl cannot find -lglew ld returned 1 exit status
Basta con reemplazar -lgl y -lglew por -lGL y -lGLEW respectivamente. En sistemas Unix la distinción entre mayúsculas y minúsculas es importante, se observa que -lglut es con minúsculas y además que al incluir las cabeceras en el código estas deben ser con mayúsculas. En caso de que la sintaxis sea correcta lo más seguro es que se hayan instalado incorrectamente las bibliotecas de GLEW o GLUT.
Si la compilación es exitosa, es posible que en la ejecución se presente el siguiente error:
Segmentation fault
Esto normalmente ocurre cuando GLEW no ha sido aún inicializado, se debe agregar glewInit(); antes de cualquier llamada a alguna función de GLEW.
Si el error persiste entonces los archivos que contienen la fuente de los shaders no han sido encontrados, se debe revisar el nombre de los archivos y la ruta para verificar que su acceso es correcto.
Quizá te interese :
El Registro de Windows El registro de Windows se crea durante la instalación del sistema operat ...
#include #include #include void cifrar (char *archivo, char *llave); void descifrar (ch ...
#include #include char bufer[500]; typedef struct swav { char Riff[4]; long longRi ...












[...] This post was mentioned on Twitter by Daniel Doctor. Daniel Doctor said: RT @tweetmeme Primer acercamiento a Shaders con GLSL http://bit.ly/bk9GqG [...]
en GLSL se permite la creacion de arrays sin tamaño, para despues volver a declararlos con tamaño. Me hace falta una situacion en que esto verdaderamente sea util, y haga falta. Alguien que haya trabajado con glsl y tenga mas experiencia podria ayudarme..