Tutorial Sintaxis GLSL
En este tutorial veremos la sintaxis de GLSL, nos enfocaremos en el uso de la versión 3.3 como mínimo, en el Tutorial Introducción a GLSL vimos todos los detalles teóricos que debemos conocer antes de empezar, veamos nuestro primer fragmento de código.
La primera línea de código
Vemos también la manera de añadir comentarios, igual que el lenguaje C usamos // para definir una línea de comentarios y /* */ para agregar un comentario en varias líneas.
La función
A continuación se describen los tipos de datos con los que cuenta GLSL, algunos ya los conocemos del lenguaje C, a diferencia de este no contamos con punteros ni cadenas de caracteres.
Tenemos solo cuatro tipos básicos:
Los vectores pueden tener 2, 3 o 4 componentes de uno de los tipos básicos, tenemos:
GLSL soporta los siguientes tipos de matrices: mat2, mat2x2, mat3, mat3x3, mat4, mat4x4, mat2x3, mat2x4, mat3x2, mat3x4, mat4x2, mat4x3.
Las variables son inicializadas usando el operador “=”, para los vectores y matrices lo hacemos mediante el constructor del tipo correspondiente.
En los vectores podemos usar los siguientes nombres para acceder a cada uno de sus componentes, también podemos hacerlo a través de su índice, como si fuese un arreglo.
Una matriz puede verse como un arreglo de vectores, si deseamos establecer la primera columna de una matriz, lo haríamos de este modo:
Grupo de nombres usados para acceder a las cuatro componente de un vector que represente una posición {x, y, z, w}, cuando el vector representa un color {r, g, b, a}, si representa una coordenada de textura {s, t, p, q}, el primer nombre de cada grupo accede a la primera componente del vector, por lo que da igual usar x, r, s esto ocurre con los demás nombres, decidimos si usar uno u otro solo por claridad.
En GLSL en posible reordenar las componentes de un vector para crear uno nuevo, esto se le llama: “swizzle”, para hacerlo colocamos el nombre de componente en el orden deseado, no solo podemos cambiar el orden, también podemos repetir el nombre cuantas veces sea necesario para conseguir la cantidad de componentes finales, veamos un ejemplo:
No podemos mezclar los grupos de nombres, es un error usar por ejemplo: pos0.xt.
Al igual que el lenguaje C contamos son las sentencias if-else para la toma de decisiones, también es posible utilizar swicth el uso de ambos es el común que conocemos de lenguajes como el ya mencionado C/C++, C# o Java.
Si el if contiene una sola instrucción podemos omitir las llaves, ahora mostramos un ejemplo de swicth.
Tenemos disponibles las siguientes sentencias de repetición: for, while, do-while, también son bastante familiares por lo que solo mostramos un ejemplo de su sintaxis.
Recordemos siempre tener cuidado con los ciclos infinitos.
#version 330 /* directiva para el preprocesador define la version a utilizar */ void main(){ // codigo del shader }
La primera línea de código
#version 330
define la versión con la que trabajaremos, 3.3 se identifica como 330, si deseáramos, por ejemplo, usar la versión 4.3 usaríamos la directiva #version 340
.Vemos también la manera de añadir comentarios, igual que el lenguaje C usamos // para definir una línea de comentarios y /* */ para agregar un comentario en varias líneas.
La función
void main() { }
a diferencia de C no debe retornar valor, podemos definir otras funciones que devuelvan un valor del tipo indicado y con cero, uno o varios argumentos, como en C la función main es el punto de inicio del programa.Tipos de Datos
A continuación se describen los tipos de datos con los que cuenta GLSL, algunos ya los conocemos del lenguaje C, a diferencia de este no contamos con punteros ni cadenas de caracteres.
Tenemos solo cuatro tipos básicos:
- bool: para definir un tipo booleano, true o false.
- int: valor numérico entero con signo, positivo o negativo.
- uint: valor numérico entero sin signo, positivo.
- float: define un tipo punto flotante.
bool bValue = false; // Boolean true or false int iValue = 42; // Signed integer uint uiValue = 3929u; // unsigned integer float fValue = 42.0f; // Floating point value
Los vectores pueden tener 2, 3 o 4 componentes de uno de los tipos básicos, tenemos:
- vec2, vec3, vec4: vector de 2, 3, 4 componentes de tipo float
ivec2, ivec3, ivec4: vector de 2, 3, 4 componentes de tipo int
uvec2, uvec3, uvec4: vector de 2, 3, 4 componentes de tipo uint
bvec2, bvec3, bvec4: vector de 2, 3, 4 componentes de tipo bool
GLSL soporta los siguientes tipos de matrices: mat2, mat2x2, mat3, mat3x3, mat4, mat4x4, mat2x3, mat2x4, mat3x2, mat3x4, mat4x2, mat4x3.
Inicializar Variables
Las variables son inicializadas usando el operador “=”, para los vectores y matrices lo hacemos mediante el constructor del tipo correspondiente.
float a = 1.0; // Ok bool switch = false; // Ok ivec3 a = ivec3(1, -2, 3); // Ok uvec2 a = uvec2(-1, 2); // Error, uvec2 solo admite enteros sin signo vec3 a(1.0, 2.0); // Error, debemos usar el constructor vec3 a = vec3(1.0, 2.0); // Ok // Podemos combinar varios tipos para crear uno nuevo, // solo tener en cuenta que el numero de componentes corresponda vec4 a = vec4(1.0, vec3(0.0, 1.0, 0.0)); vec4 a = vec4(vec3(0.0, 1.0, 0.0), 0.9); vec4 a = vec4(vec2(1.0, 1.0), vec2(0.5, 0.5));
En los vectores podemos usar los siguientes nombres para acceder a cada uno de sus componentes, también podemos hacerlo a través de su índice, como si fuese un arreglo.
Una matriz puede verse como un arreglo de vectores, si deseamos establecer la primera columna de una matriz, lo haríamos de este modo:
mat4 mvp; // establecer la primera columna de la matrix 4 x 4 mvp[0] = vec4(0.0f, 1.0f, 0.0f, 1.0f); // usando el contructor para inicializar la matriz mat4 model = mat4(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); // constructor para crear la matriz identidad mat4 identity = mat4(1.0f);
Grupo de nombres usados para acceder a las cuatro componente de un vector que represente una posición {x, y, z, w}, cuando el vector representa un color {r, g, b, a}, si representa una coordenada de textura {s, t, p, q}, el primer nombre de cada grupo accede a la primera componente del vector, por lo que da igual usar x, r, s esto ocurre con los demás nombres, decidimos si usar uno u otro solo por claridad.
vec3 p; p.x = 2; // Establece la primera componente del vector, equivale a: p.r = 2; p.s = 2; p[0] = 2; p.w = 4; // Error, solo tenemos 3 componentes, p[3] no existe en un vec3.
En GLSL en posible reordenar las componentes de un vector para crear uno nuevo, esto se le llama: “swizzle”, para hacerlo colocamos el nombre de componente en el orden deseado, no solo podemos cambiar el orden, también podemos repetir el nombre cuantas veces sea necesario para conseguir la cantidad de componentes finales, veamos un ejemplo:
// Color en formato RGB vec3 color_rgb = vec4(0.5, 0.2, 1.0); // Color en formato BGR vec3 color_bgr = color_rgb.bgr; // equivale a usar: color_rgb.zyx vec4 pos0 = vec4(3, 5, 2, 1); vec3 pos1 = pos0.xxy; // Ok vec2 pos2 = pos0.yyy; // Error, se requieren 3 componentes
No podemos mezclar los grupos de nombres, es un error usar por ejemplo: pos0.xt.
Control de Flujo
Al igual que el lenguaje C contamos son las sentencias if-else para la toma de decisiones, también es posible utilizar swicth el uso de ambos es el común que conocemos de lenguajes como el ya mencionado C/C++, C# o Java.
if(a < threshold) lightColor = vec4(1.0, 0.0, 0.0, 1.0); else if(a == threshold) lightColor = vec4(0.0, 1.0, 0.0, 1.0); else if((a > threshold + 1) && (a <= threshold + 2)) { lightColor = vec4(0.0, 0.0, 1.0, 1.0); lightIntesity = vec4(0.85); } else lightColor = vec4(1.0, 1.0, 1.0, 1.0);
Si el if contiene una sola instrucción podemos omitir las llaves, ahora mostramos un ejemplo de swicth.
switch(var) { case 1: // cuando var = 1 lightColor = vec4(1.0, 0.0, 0.0, 1.0); break; case 2: // cuando var = 2 lightColor = vec4(0.0, 1.0, 0.0, 1.0); break; default: // en cualquier otro caso lightColor = vec4(1.0, 1.0, 1.0, 1.0); }
Tenemos disponibles las siguientes sentencias de repetición: for, while, do-while, también son bastante familiares por lo que solo mostramos un ejemplo de su sintaxis.
for(int i = 0; i < 5; i++) { n = n * i + 1; } while(m < 20) { m = (m + 1) * 2; } do { p = p / 2.0; } while(p >= 10.5);
Recordemos siempre tener cuidado con los ciclos infinitos.
Comentarios
Publicar un comentario