Enviar datos al vertex shader

Este tutorial nos enseña como enviar datos al vertex shader, específicamente vértices, por ahora, para formar una figura requerimos de varios vértices, para un triangulo necesitamos 3, uno para cada esquina, por lo veremos como almacenar estos vértices en la memoria de la GPU para que el vertex shader pueda acceder a ellos y dibujar la figura deseada.

Necesitamos modificar el vertex shader para que reciba los datos de entrada, en este caso los vértices que componen el triangulo que dibujaremos, crearemos un tipo de variable llamado “vertex attribute” esta es una variable cuyo valor cambiara cada vez que se ejecute el vertex shader, el vertex shader se ejecuta una o varias veces según lo indique el comando de dibujo, por lo que la variable tomará el valor de un vértices diferente en cada pasada.

#version 330 core

layout (location = 0) in vec4 vPosition;

void main()
{
     gl_Position = vPosition;
}

vPosition es una variable de entrada (in), de tipo (vec4) arreglo flotante de 4 componentes (X, Y, Z, W), layout (location = 0) indica que el vertex attribute se localiza en el índice 0, si omitimos este fragmento de código el sistema lo asignara automáticamente, si existen dos variables la primera será 0, la segunda 1 y así sucesivamente.


Vertex Array Object


Un vertex array object (VAO) es un objeto que representa una entrada hacia el shader, para crear un vao usamos la función void glGenVertexArrays(GLsizei n, GLuint* arrays); que crea n vaos y devuelve sus identificadores en arrays y void glBindVertexArray(GLuint array); para enlazar el vao identificado por array al contexto y comenzar a utilizarlo.

void glGenVertexArrays(GLsizei n, GLuint * arrays);
void glBindVertexArray(GLuint array);

Para almacenar los datos necesitamos in Buffer, al igual que en el vao las funciones glGen* y glBind* nos ayudan a crear los buffer, además necesitaremos la función glBufferData para almacenar los datos en el buffer indicado, seguido vemos el prototipo de la función:
void glBufferData(GLenum target, GLsizeiptr size, const GLvoid * data, GLenum usage);

static const float data[] =
{
     0.25, -0.25, 0.0, 1.0,
    -0.25, -0.25, 0.0, 1.0,
     0.25,  0.25, 0.0, 1.0
};

// generar un id para el buffer
glGenBuffers(1, &buffer);
// enlazar el buffer
glBindBuffer(GL_ARRAY_BUFFER, buffer);
// almacenar datos en el buffer
glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);

GL_BUFFER_ARRAY es usado para indicar que el buffer será usado para almacenar los datos de vértices, existen otros tipos para otros propósitos, los iremos viendo a medida que avancemos.

sizeof(data) lo usamos al momento de introducir los datos en el buffer para indicar el tamaño en bytes que deseamos reservar, data es un arreglo flotante de vértices, almacena los 4 componentes requeridos (X, Y, Z, W).

GL_STATIC_DRAW indica como será usado el buffer, en este caso se indica que el buffer será modificado una vez pero será utilizado muchas veces como fuente de datos para dibujar.

void glVertexAttribPointer(GLuint index,
  GLint size,
  GLenum type,
  GLboolean normalized,
  GLsizei stride,
  const GLvoid * pointer);
void glEnableVertexAttribArray(GLuint index);

Estas funciones son utilizadas para decirle a OpenGL como están organizados los datos en el buffer, index: índice del vertex attibute (vPosition), size: cantidad de componentes (4), type: tipo de datos (GL_FLOAT), normalized: los datos están normalizados (GL_FASLE), stride y pointer no los usamos de momento, los establecemos a 0 y NULL respectivamente.

Para activar el vertex attribute llamado vPosition localizado en el índice 0 usamos glEnableVertexAttribArray(0) cuando terminemos de utilizarlo lo desactivaremos con glDIsableVertexAttribArray(0).

// describir los datos y activar vPosition
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0);

Para dibujar un triangulo modificamos el comando de dibujo para dibujar usando el modo GL_TRIANGLES, además la cantidad de vértices a dibujar serán 3, el comando quedara de este modo: glDrawArrays(GL_TRIANGLES, 0, 3);, usando el modo GL_POINTS dibujaremos las tres esquinas del triangulo.

opengl vertex data

Enviar varias entradas al shader


Podemos generar uno o varios buffer y almacenar diferentes datos en ellos, como: vértices, colores, normales, texturas, etc., veamos como enviarle dos conjuntos de datos al vertex shader, uno con información de vértices, esto es lo que acabamos de hacer, y otro con información de colores.

Primero modificaremos el vertex shader agregando otra variable de entrada (in vec4 vColor), esta almacenará los datos de color (RGBA) y una variable de salida también para el color (out vec4 color), esto nos permitirá enviar los datos de color del vertex shader al fragment shader, necesitaremos modificar el fragment shader para que reciba los datos de color, por lo que agregaremos una variable de entrada (in vec4 color).

Vertex Shader Modificado

layout (location = 0) in vec4 vPosition;
layout (location = 1) in vec4 vColor;

out vec4 color;

void main()
{
     gl_Position = vPosition;
     color = vColor; 
}

Fragment Shader Modificado

in vec4 color;
out vec4 fColor;

void main()
{
     fColor = color;
}

Creamos el buffer, teniendo en cuenta que requerimos dos, uno para vértices y otro para colores, y que usaremos la función glEnableVertexAttribArray(0) con el índice 0 para activar vPosition y glEnableVertexAttribArray(1) para activar vColor.

Una variable de salida (out) en el vertex shader se convierte en una variable de entrada (in) en el fragment shader.

opengl dibujar tiangulo
Si dibujamos puntos (GL_POINTS) veremos un punto de cada color especificado, para colorear el área del triangulo los colores son interpolados.

GitHub: OpenGL Buffer Data

Comentarios

Entradas populares de este blog

Conectar SQL Server con Java

Entrenar OpenCV en Detección de Objetos

Detección de figuras geométricas