Introducción a los Shader (GLSL)
Los shaders no son mas que simples programas que se ejecutan en el procesador gráfico GPU, son escritos en el lenguaje GLSL, el cual es bastante similar a C, como cualquier otro programa los shaders deben ser compilados y enlazados, solo que el compilador y el enlazador o linker están integrados en la API OpenGL.
OpenGL cuenta con diferentes tipos de shaders, cada uno en su nivel correspondiente, de momento veremos los dos shaders requeridos Vertex Shader en el primer nivel y Fragment Shader en el último, los demos están ubicados entre estos dos y son opcionales.
![opengl pipeline opengl pipeline](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyAquYWQSZDUKZJI2iAj1JJhCsWAal1-wHjlVs1a475coq4B704plbxVzCoqT6byQ67TDhjQQi62Mln4SxODefWTx7wyX86eZKsGSZLKOwzwcP2BbyRINXQeJSA2fB_aaSmDqc9S6SJQ/?imgmax=800)
Vertex shader, en su forma mas simple:
Como cualquier programa tenemos el ya conocido método
Fragment Shader, establece el color de salida a verde:
Este shader presenta una variable de salida fColor de cuatro componentes que esta vez representan un color (R, G, B, A), sus canales rojo, verde, azul y opacidad, en este shader se genera el color de salida de la figura a dibujar.
Lo primero que haremos será crear un shader object que nos permitirá añadirle código para luego compilarlo, hacemos esto para ambos shaders, el código fuente puede ser leído de un archivo externo, o directamente de un arreglo de caracteres.
Una vez tengamos los shaders compilados debemos crear un programa que los ejecutará, para ello primero creamos el programa y luego enlazamos ambos shaders a este programa.
Podemos obtener información sobre la compilación y enlazado de los shaders, los métodos logShader() y logLink() hacen estas tareas, son de mucha ayuda para detectar errores en nuestro código GLSL.
Para dibujar en pantalla lo primero que haremos será limpiar la misma,
Finalmente usaremos el comando de dibujo
De momento no tenemos vértices almacenados en memoria y nuestro vertex shader es estático tiene una posición fija definida,
OpenGLShader es la clase C++ que encapsula las tareas de creación, compilación, enlazado y detección de errores de los shaders.
![opengl compilar shader opengl compilar shader](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0gR3ey02vtxxM9ChsD4q5_NTyWZmh0ggYK1sRLNZ0sWqTKTmzjV4OwwPIm3XX_BxNOVRbhQ3rqXpwBQM-xfB568Lkj2qtc8Bm0mZQjD8Wwfc0o23JZ1Tdro349gzvGem_tscRr4d26g/?imgmax=800)
Esta es la salida de nuestro primer programa hecho con API moderna de OpenGL, de momento la posición y color del punto son fijos, una aplicación real como un juego por ejemplo requiere del manejo de millones de vértices y colores diferentes por lo que en la siguiente publicación veremos como enviarle un conjunto de vértices y colores a nuestros shaders.
GitHut: Vertex y Fragment Shader en OpenGL
OpenGL cuenta con diferentes tipos de shaders, cada uno en su nivel correspondiente, de momento veremos los dos shaders requeridos Vertex Shader en el primer nivel y Fragment Shader en el último, los demos están ubicados entre estos dos y son opcionales.
Vertex shader, en su forma mas simple:
#version 330 core void main() { gl_Position = vec4(0,0,0,1); }
Como cualquier programa tenemos el ya conocido método
void main() { }
este es el punto de entrada o inicio de la aplicación, gl_Position es una variable reservada del shader, nos sirve para indicar la posición de los vértices en los cuatro componentes (X, Y, Z, W), en este caso nos dice que debemos dibujar en la coordenada (0,0,0), el valor W lo establecemos a 1, mas adelante lo explicaremos, #version 330 core
indica qué versión manejaremos.Fragment Shader, establece el color de salida a verde:
#version 330 core out vec4 fColor; void main() { fColor = vec4(0.0, 1.0, 0.0, 1.0); }
Este shader presenta una variable de salida fColor de cuatro componentes que esta vez representan un color (R, G, B, A), sus canales rojo, verde, azul y opacidad, en este shader se genera el color de salida de la figura a dibujar.
Compilar y enlazar los shaders
Lo primero que haremos será crear un shader object que nos permitirá añadirle código para luego compilarlo, hacemos esto para ambos shaders, el código fuente puede ser leído de un archivo externo, o directamente de un arreglo de caracteres.
GLuint compileShader(std::string& source, GLenum type) { GLuint shader{ 0 }; if (!source.empty()) { const GLchar* code = const_cast<GLchar*>(source.c_str()); // crear el shader object shader = glCreateShader(type); // agregar el codigo al sahder glShaderSource(shader, 1, &code, NULL); // compilar el shader indicado glCompileShader(shader); logShader(shader, type == GL_FRAGMENT_SHADER ? "Fragment" : "Vertex"); } return shader; }
Una vez tengamos los shaders compilados debemos crear un programa que los ejecutará, para ello primero creamos el programa y luego enlazamos ambos shaders a este programa.
GLuint createProgram(GLuint vertex, GLuint fragment) { // crear el program object program = glCreateProgram(); // añadir los shaders al programa glAttachShader(program, vertex); glAttachShader(program, fragment); // enlazar el programa glLinkProgram(program); logLink(); // eliminar los shaders, ya no son necesarios glDeleteShader(vertex); glDeleteShader(fragment); return program; }
Podemos obtener información sobre la compilación y enlazado de los shaders, los métodos logShader() y logLink() hacen estas tareas, son de mucha ayuda para detectar errores en nuestro código GLSL.
Dibujar en pantalla
Para dibujar en pantalla lo primero que haremos será limpiar la misma,
glClear(GL_COLOR_BUFFER_BIT);
limpiar el buffer de color, debemos indicarle al comando de dibujo que shader usaremos glUseProgram(program);
Finalmente usaremos el comando de dibujo
glDrawArrays(GL_POINTS, 0, 1);
este le indica al vertex shader como dibujar los vértices almacenados, GL_POINT es el modo de dibujo, indica que se debe dibujar un punto, 0 el índice del primer vértice y 1 la cantidad de vértices a dibujar.De momento no tenemos vértices almacenados en memoria y nuestro vertex shader es estático tiene una posición fija definida,
gl_Position = vec4(0,0,0,1);
por lo que la salida será un punto justo en el centro de la pantalla, usamos glPointSize(15.0f);
para aumentar el tamaño del punto y que este sea visible fácilmente.class Tutorial_01 : public OpenGLWindow { void onstart() override { glPointSize(15.0f); shader_simple.compile("simple.vertex_shader", "simple.fragment_shader"); } void onrender(double time) override { glClear(GL_COLOR_BUFFER_BIT); shader_simple.use(); glDrawArrays(GL_POINTS, 0, 1); } OpenGLShader shader_simple; };
OpenGLShader es la clase C++ que encapsula las tareas de creación, compilación, enlazado y detección de errores de los shaders.
Esta es la salida de nuestro primer programa hecho con API moderna de OpenGL, de momento la posición y color del punto son fijos, una aplicación real como un juego por ejemplo requiere del manejo de millones de vértices y colores diferentes por lo que en la siguiente publicación veremos como enviarle un conjunto de vértices y colores a nuestros shaders.
GitHut: Vertex y Fragment Shader en OpenGL
Comentarios
Publicar un comentario