The per-vertex attribute in the shader programming helps receive data in the vertex shader from OpenGL ES program for each unique vertex attribute. The received data value is not shared among the vertices. The vertex coordinates, normal coordinates, texture coordinates, color information, and so on are the example of per-vertex attributes. The per-vertex attributes are meant for vertex shaders only, they cannot be directly available to the fragment shader. Instead, they are shared via the vertex shader through out variables.
Typically, the shaders are executed on the GPU that allows parallel processing of several vertices at the same time using multicore processors. In order to process the vertex information in the vertex shader, we need some mechanism that sends the data residing on the client side (CPU) to the shader on the server side (GPU). This recipe will be helpful to understand the use of per-vertex attributes to communicate with shaders.
The vertex shader in the Programming shaders in GL shading language 3.0 recipe contains two per-vertex attributes named VertexPosition
and VertexColor
:
// Incoming vertex info from program to vertex shader in vec4 VertexPosition; in vec4 VertexColor;
The VertexPosition
contains the 3D coordinates of the triangle that defines the shape of the object that we intend to draw on the screen. The VertexColor
contains the color information on each vertex of this geometry.
In the vertex shader, a non-negative attribute location ID uniquely identifies each vertex attribute. This attribute location is assigned at the compile time if not specified in the vertex shader program. For more information on specifying the ID, refer to the See also section of this recipe.
Basically, the logic of sending data to their shader is very simple. It's a two-step process:
Query attribute: Query the vertex attribute location ID from the shader.
Attach data to the attribute: Attach this ID to the data. This will create a bridge between the data and the per-vertex attribute specified using the ID. The OpenGL ES processing pipeline takes care of sending data.
Follow this procedure to send data to a shader using the per-vertex attribute:
Declare two global variables in
NativeTemplate.cpp
to store the queried attribute location IDs ofVertexPosition
andVertexColor
:GLuint positionAttribHandle; GLuint colorAttribHandle;
Query the vertex attribute location using the
glGetAttribLocation
API:positionAttribHandle = glGetAttribLocation (programID, "VertexPosition"); colorAttribHandle = glGetAttribLocation (programID, "VertexColor");
This API provides a convenient way to query an attribute location from a shader. The return value must be greater than or equals to
0
in order to ensure that attribute with given name exists.Syntax:
GLint glGetAttribLocation(GLuint program, const GLchar *name);
Variable
Description
program
This is the handle of a successfully linked OpenGL program
name
This is the name of the vertex attribute in the shader source program
Send the data to the shader using the
glVertexAttribPointer
OpenGL ES API:// Send data to shader using queried attrib location glVertexAttribPointer(positionAttribHandle, 2, GL_FLOAT, GL_FALSE, 0, gTriangleVertices); glVertexAttribPointer(colorAttribHandle, 3, GL_FLOAT, GL_FALSE, 0, gTriangleColors);
The data associated with geometry is passed in the form of an array using the generic vertex attribute with the help of the
glVertexAttribPointer
API.Syntax:
void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid * pointer);
Variable
Description
index
This is the index of the generic vertex attribute.
size
This specifies the number of components per generic vertex attribute. The number must be
1
,2
,3
,or4
. The initial value is4
.type
This is the data type of each component in the array containing geometry info.
normalized
This specifies whether any fixed-point data values should be normalized (
GL_TRUE
) or converted directly as fixed-point values (GL_FALSE
) when they are accessed.stride
This is used for consecutive generic attribute; it specifies the offset between them.
pointer
These are pointers to the first attribute of the array data.
The generic vertex attributes in the shaders must be enabled by using the
glEnableVertexAttribArray
OpenGL ES API:// Enable vertex position attribute glEnableVertexAttribArray(positionAttribHandle); glEnableVertexAttribArray(colorAttribHandle);
It's important to enable the attribute location. This allows us to access data on the shader side. By default, the vertex attributes are disabled.
Syntax:
void glEnableVertexAttribArray(GLuint index);
Variable
Description
index
This is the index of the generic vertex attribute to be enabled
Similarly, the attribute can be disabled using
glDisableVertexAttribArray
. This API has the same syntax as that ofglEnableVertexAttribArray
.Store the incoming per-vertex attribute color
VertexColor
into the outgoing attributeTriangleColor
in order to send it to the next stage (fragment shader):in vec4 VertexColor; // Incoming data from CPU . . . out vec4 TriangleColor; // Outgoing to next stage void main() { . . . TriangleColor = VertexColor; }
Receive the color information from the vertex shader and set the fragment color:
in vec4 TriangleColor; // Incoming from vertex shader out vec4 FragColor; // The fragment color void main() { FragColor = TriangleColor; };
The per-vertex attribute variables VertexPosition
and VertexColor
defined in the vertex shader are the lifelines of the vertex shader. These lifelines constantly provide the data information form the client side (OpenGL ES program or CPU) to server side (GPU). Each per-vertex attribute has a unique attribute location available in the shader that can be queried using glGetAttribLocation
. The per-vertex queried attribute locations are stored in positionAttribHandle
; colorAttribHandle
must be bound with the data using attribute location with glVertexAttribPointer
. This API establishes a logical connection between client and server side. Now, the data is ready to flow from our data structures to the shader. The last important thing is the enabling of the attribute on the shader side for optimization purposes. By default, all the attribute are disabled. Therefore, even if the data is supplied for the client side, it is not visible at the server side. The glEnableVertexAttribArray
API allows us to enable the per-vertex attributes on the shader side.
Refer to the Managing variable attributes with qualifiers recipe in Chapter 3, New Features of OpenGL ES 3.0