Vamos a ver como funcionan los shaders programados en GLSL que es un lenguaje parecido a C.
3.1 GLSL
Como ya he dicho están escritos en algo parecido a C. Siempre se empieza con una declaración de la versión.
Tiene unas variables para comunicarnos con el shader:
- Inputs: sirven para recibir información de ese vértice en concreto. Por ejemplo: color, posición textura... Estas se les conoce como vertex attributes y tienen un límite, como máximo 16 de vértices de 4 componentes.
- Out: sirven para mandar información al siguiente paso de renderizado. Como modificar la posición y luego pasarla.
- Uniforms: son variables globales y que si valor no cambia hasta que se vuelve a enviar otro
3.2 Tipos
Como en c las variables tienen un tipo, ya sea int, float, bool... Pero tambien tiene el tipo vector y matrices.
Vector
Puedes tener vectores de 1,2,3,4 componentes.
vecn
bvecn
ivecn
uvecn
dvecn
Se pueden construir así
vec2 someVec;
vec4 differentVec = someVec.xyxx;
vec3 anotherVec = differentVec.zyw;
vec4 otherVec = someVec.xxxx + anotherVec.yxzy;
3.3 Comunicación entre Shaders
Es posible pasar información del vertex al fragment shader, para ello las variables de out del vertex tienen que coincidir con el in del fragment. Ejemplo
Vertex Shader
#version 330 core
layout (location = 0) in vec3 aPos;
out vec4 vertexColor;
void main() {
gl_Position = vec4(aPos, 1.0);
vertexColor = vec4(0.5, 0.0, 0.0, 1.0);
}
Fragment Shader
#version 330 core
out vec4 FragColor;
in vec4 vertexColor;
void main() {
FragColor = vertexColor;
}
3.4 Uniforms
Como ya hemos dicho antes, son variables globales y se pueden declarar en cualquier etapa de los shaders.
Para mandar información al shader, se hace de la siguiente manera
int vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor");
glUniform4f(vertexColorLocation, v.x, v.y, v.z, v.w);
Primero se obtiene la localización de la variable en memoria, poniendo el nombre exacto de la variable. Siempre primero se tiene que hacer el use antes del uniform.