GLSL básico desde cero


Introducción – Conceptos

GLSL es el acrónimo de OpenGL Shading Language (Lenguaje Sombreador de OpenGL), una tecnología parte del API estandar OpenGL, que permite especificar segmentos de programas gráficos que serán ejecutados sobre el GPU. Su contrapartida en DirectX es el HLSL.

GLUT es un sistema de ventanas independientes para escribir programas OpenGL. Implementa una API de ventanas sencilla, las cuales hacen que el aprendizaje acerca de explorar la programación de OpenGL sea muy fácil.

Logo de GLEW
Logo de GLEW

GLEW (OpenGL Extension Wrangler Library, es decir, Biblioteca disputadora de extensiones OpenGL) es un plataforma cruzada (entorno de ejecución) de extensiones de código abierto C/C++ para cargar librerias que ayuden en la consulta y extensiones OpenGL. GLEW suministra mecanimos eficientes en tiempo de ejecución para determinar que extensiones OpenGL están soportadas en la plataforma objetivo.

Instalación

Para instalar las librerias necesarias en Ubuntu Intrepid 8.10 necesitamos instalar las bibliotecas de ejecución de GLEW y GLUT (la más actual al momento de escribir es la 1.5 para GLEW y 3 para GLUT) y desarrollo de GLEW y GLUT.

Desde Synaptic buscar los paquetes libglew1.5, libglew-dev, freeglut3, freeglut3-dev o desde una simple linea en el terminal:

$ sudo apt-get install libglew1.5 libglew-dev freeglut3 freeglut3-dev

Código sencillo de ejemplo

Crearemos un fichero init.c con el siguiente código (a continuación lo explico):

/* init.c
Inicializa GLEW y hace varias pruebas sobre sus primitivas

Linea de compilación:
gcc init.c -o init -lGLEW -lGLU -lGL -lglut
*/
#include < stdio.h >
#include < stdlib.h >

#include < GL/glew.h > // Proporciona funcionalidad a gl y glu
#include < GL/glut.h > // Proporciona funcionalidad a glut

int main(int argc,char **argv) 
{
    glutInit(&argc,argv); //Inicializa la biblioteca GLUT
    glutCreateWindow("Prueba GLEW"); //Crea una ventana y da paso un contexto OpenGL

    GLenum err=glewInit(); // Crea un contexto de render válido para OpenGL
    if(GLEW_OK!=err)
    {// Problema: fallo de glewInit, algo esta seriamente mal.
        fprintf(stderr,"Error: %s\n",glewGetErrorString(err)); //Mostrar el error
        exit(EXIT_FAILURE);
    }

    //Mostramos la versión de GLEW
    fprintf(stdout,"Estado: Usando GLEW %s\n",glewGetString(GLEW_VERSION));

    if(glewIsSupported("GL_VERSION_2_0"))
    {
        printf("Listo para OpenGL 2.0\n");
        //Más código aquí
    }
    else
    {
        printf("OpenGL 2.0 no soportado\n");
        exit(EXIT_FAILURE);
    }

    glutMainLoop();

    return 0;
}

Lo primero que necesitamos es incluir las bibliotecas estandar de entrada y salida de C (stdio.h) para mostrar mensajes y la biblioteca estándar (stdlib.h) para funciones como exit() con constantes como EXIT_FAILURE.

Despues añadimos las bibliotecas de GLEW y GLUT, glew.h y glut.h respectivamente.

Creamos un main y llamamos a la primitiva glutInit() con los argumentos de nuestro main para que se inicialice la biblioteca GLUT, a continuación creamos una ventana que da paso al contexto OpenGL con la primitiva glutCreateWindow() pasandole como argumento el nombre que tendrá la ventana, en nuestro caso «Prueba GLEW».

Una vez se ha creado el contexto OpenGL, ya podemos iniciar GLEW con la primitiva glewInit() que nos devolvera un valor de tipo GLenum que nos informará de posibles estados de error.

Despues comprobaremos si hubo error comparando dicho error con la constante GLEW_OK y si hay error, llamaremos a la primitiva glewGetString() para convertir el error a un mensaje y mostrarlo por la salida de errores estándar.

Si por el contrario todo va bien comprobamos si OpenGL 2.0 esta soportado por nuestro sistema y tarjeta gráfica, para ello invocamos a glewIsSupported() pasandole como argumento la constante que identifica a OpenGL 2.0 que es GL_VERSION_2_0. Si no hay fallos, ya podremos añadir más codigo (como Shaders) y hacer nuestras operaciones con OpenGL.

Si no mostraremos un error. Y por último devolvemos el control del programa a GLUT con glutMainLoop() que esperará que ocurran eventos en nuestro programa para reaccionar.

Compilación

Escribiremos lo siguiente en el terminal para crear el ejecutable:

$ gcc init.c -o init -lGLEW -lGLU -lGL -lglut

Observad, que incluimos las opciones -GLEW, -lGLU -lGL -lglut por cada biblioteca que utilizamos. Sin ellas no sería posible la compilación.

Para ejecutar el programa:

$ ./init

Errores frecuentes

1) Error: Error: Missing GL version

Despues de invocar a glutInit() debe crearse un contexto OpenGL, es decir, debemos invocar alguna función que realice las inicializaciones previas de OpenGL y este quede iniciado.

En nuestro ejemplo llamamos a glutCreateWindow() con lo que creamos una ventana que inicia dicho contexto. Puede ser que hayas omitido esta línea de código y por ello te aparezca este mensaje.

2) error: #error gl.h included before glew.h
error: #error glext.h included before glew.h

Has incluido antes glut.h que glew.h, recuerda el orden. Una manera fácil y nemotécnica es pensar que glew es escribirlos en orden alfabético, ya que glew.h empieza por gle y glut.h por glu.

3) error: GL/glut.h: No existe el fichero ó directorio

¿Has comprobado que tienes todos los paquetes intalados que se recomiendan en el artículo? Problablemente te falten.

4) ¿Tu fallo no esta aqui?

Explicalo en los comentarios o mandame un email y trataré ayudarte en lo que este a mi alcance.

Conclusiones

Este artículo esta realizado bajo mi propia experiencia y escrito para una lectura «amigable», no me considero ningún experto, luego puede haber incoherencias o errores en el artículo y códigos mostrados.

Por otro lado, este artículo se centra más en el tema pÅ•áctico y la filosofía «show me the code«, si estás interesado en el tema y quieres profundizar aún mas en algunos conceptos teóricos, pero de manera informal y amigable, te recomiendo el artículo de mi colega Greenbyte: Programación de GLSL Shaders


11 pensamientos en “GLSL básico desde cero”

  1. Shader no se traduce como sombra sino como sombreador. Es como cuando dices que se usa un sombreado gouraud o sombreado phong o flat. Mas bien hace referencia a las propiedades de la superficie y el termino correcto si esque hay traducción directa sería «Material».

  2. Hola, estoy iniciandome en el lenguaje openGL Shading, antes que nada darte la enorabuena por el sitio, no habia encontrado una explicación tan detalla de como instalar glew y un ejemplo sencillo de código. Tras ejecutar el comando sudo correspondiente, he lanzado la orden de compilado, apareciendo los siguientes errores:
    init.c:7:22: error: stdio.h : No existe el fichero ó directorio
    init.c:8:23: error: stdlib.h : No existe el fichero ó directorio
    init.c:10:65: error: GL/glew.h : No existe el fichero ó directorio
    init.c:11:61: error: GL/glut.h : No existe el fichero ó directorio
    init.c: En la función ‘main’:
    init.c:18: error: ‘GLenum’ no se declaró aquí (primer uso en esta función)
    init.c:18: error: (Cada identificador no declarado solamente se reporta una vez
    init.c:18: error: para cada funcion en la que aparece.)
    init.c:18: error: expected ‘;’ before ‘err’
    init.c:19: error: ‘GLEW_OK’ no se declaró aquí (primer uso en esta función)
    init.c:19: error: ‘err’ no se declaró aquí (primer uso en esta función)
    init.c:21: aviso: declaración implícita incompatible de la función interna ‘fprintf’
    init.c:21: error: ‘stderr’ no se declaró aquí (primer uso en esta función)
    init.c:21: aviso: el formato ‘%s’ espera el tipo ‘char *’, pero el argumento 3 es de tipo ‘int’
    init.c:22: aviso: declaración implícita incompatible de la función interna ‘exit’
    init.c:22: error: ‘EXIT_FAILURE’ no se declaró aquí (primer uso en esta función)
    init.c:26: aviso: declaración implícita incompatible de la función interna ‘fprintf’
    init.c:26: error: ‘stdout’ no se declaró aquí (primer uso en esta función)
    init.c:26: error: ‘GLEW_VERSION’ no se declaró aquí (primer uso en esta función)
    init.c:26: aviso: el formato ‘%s’ espera el tipo ‘char *’, pero el argumento 3 es de tipo ‘int’
    init.c:30: aviso: declaración implícita incompatible de la función interna ‘printf’
    init.c:35: aviso: declaración implícita incompatible de la función interna ‘printf’
    init.c:36: aviso: declaración implícita incompatible de la función interna ‘exit’

  3. @Ares: Probablemente te falten las bibliotecas de compilación básicas de C.
    Prueba a instalar el paquete build-essential y cuentame que tal:
    sudo apt-get install build-essential

  4. Antes que nada, gracias por contestar tan pronto, han desaparecido algunos de los errores tras instalar el paquete, pero algunos persisten:

    init.c:7:22: error: stdio.h : No existe el fichero ó directorio
    init.c:8:23: error: stdlib.h : No existe el fichero ó directorio
    init.c:10:65: error: GL/glew.h : No existe el fichero ó directorio
    init.c:11:61: error: GL/glut.h : No existe el fichero ó directorio
    init.c: En la función ‘main’:
    init.c:18: error: ‘GLenum’ no se declaró aquí (primer uso en esta función)
    init.c:18: error: (Cada identificador no declarado solamente se reporta una vez
    init.c:18: error: para cada funcion en la que aparece.)
    init.c:18: error: expected ‘;’ before ‘err’
    init.c:19: error: ‘GLEW_OK’ no se declaró aquí (primer uso en esta función)
    init.c:19: error: ‘err’ no se declaró aquí (primer uso en esta función)
    init.c:21: aviso: declaración implícita incompatible de la función interna ‘fprintf’
    init.c:21: error: ‘stderr’ no se declaró aquí (primer uso en esta función)
    init.c:21: aviso: el formato ‘%s’ espera el tipo ‘char *’, pero el argumento 3 es de tipo ‘int’
    init.c:22: aviso: declaración implícita incompatible de la función interna ‘exit’
    init.c:22: error: ‘EXIT_FAILURE’ no se declaró aquí (primer uso en esta función)
    init.c:26: aviso: declaración implícita incompatible de la función interna ‘fprintf’
    init.c:26: error: ‘stdout’ no se declaró aquí (primer uso en esta función)
    init.c:26: error: ‘GLEW_VERSION’ no se declaró aquí (primer uso en esta función)
    init.c:26: aviso: el formato ‘%s’ espera el tipo ‘char *’, pero el argumento 3 es de tipo ‘int’
    init.c:30: aviso: declaración implícita incompatible de la función interna ‘printf’
    init.c:35: aviso: declaración implícita incompatible de la función interna ‘printf’
    init.c:36: aviso: declaración implícita incompatible de la función interna ‘exit’

  5. @Ares: puede ser que hayas puesto #include < stdio.h >
    en vez de #include (con el simbolo mayor y menor junto) (lo mismo para el resto de bibliotecas).
    En el artículo el plugin de wordpress para mostrar código no me permite ponerlo junto, por eso lo puse así, pero en realidad va junto. Si sigues con problemas, avísame de nuevo.

  6. Hola, gracias por todo, ese era el error, el resultado es una ventana vacía, no? eso es lo que me sale a mí, un saludo de estudiante de informática a estudiante de informática!!!

  7. @Ares: si, en este caso aparecerá una ventana vacía y en el terminal algun mensaje. Simplemente este tutorial es para inicializar el sistema GLSL. En otros tutoriales que publique tienes resultados con salida.

    Saludos

  8. Hola, si no te importa quería realizarte una nueva consulta, conoces alguna librería gráfica que permita generar una aplicación cuyo resultado de ejecución sea un programa en OpenGL Shading?

  9. Hola, yo soy nuevo en opengl, estaba tratando de correr un ejemplo, segui el ejemplo del libro azul de opengl, pero me da un resultado
    ERROR: missing version, exactamente en la linea de glewInit(). Por favor, dime que debo hacer.

Deja un comentario

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.