Page 132 - Computer Graphics Handout
P. 132
The problem is how to apply this matrix. Suppose that we set up the data arrays as in our previous examples by executing the
colorcube function as part of our initialization. Thus, we have color and position data in the arrays quad_colors and points for 36
vertices.We can use a second array
point4 new_points[36];
to hold the transformed points and then apply the rotations in the display callback
for(i=0; i<36; i++)
{
new_points[i] = ctm*points[i];
}
However, these transformed positions are on the CPU, not on the GPU. To get them into the pipeline, we can initialize the vertex
array to be new_points rather than points initially,
loc = glGetAttribLocation(program, "vPosition");
glEnableVertexAttribArray(loc);
glVertexAttribPointer(loc, 4, GL_FLOAT, GL_FALSE, 0,
BUFFER_OFFSET(0));
and then in the display callback send these points to the GPU:
glBindVertexArray(abuffer);
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(new_points), new_points,
GL_STATIC_DRAW);
glDrawArrays(GL_TRIANGLES, 0, N);
glutSwapBuffers();
There is, however, a major weakness in this approach. We are applying the current transformation in the application program and
sending the vertex positions to the GPU every time we want to update the display. Consequently, we are not using the power of the
GPU and having the performance determined by how fast we can send data from the CPU to the GPU. In applications, where we
have complex geometry, this approach will lead to poor performance.
Our second approach will be to send the vertex data to the GPU once. Every time we update the transformation matrix, we will send
a new transformation matrix to the GPU and update the vertex positions on the GPU. First, we must examine how to get such data
from the CPU to the GPU.
3.12.2 Uniform Variables
In a given application, a variable may change in a variety of ways. When we send vertex attributes to a shader, these attributes can
be different for each vertex in a primitive. We may also want parameters that will remain the same for all vertices in a primitive or
equivalently for all the vertices that are displayed when we execute a function such as glDrawArrays. Such variables are called
uniformqualified variables. For example, in our present example, we want the same rotation matrix to apply to all the vertices in
the points array. We set up uniform variables in much the same way as we did for vertex attributes. Suppose that we want to send
the elapsed time from the application to the vertex shader. In the application, we can use GLUT to get the elapsed time in
milliseconds
float etime;
etime = 0.001*glutGet(GLUT_ELAPSED_TIME);
In the vertex shader, we might have a corresponding variable time. For example, the following shader varies the x component of
each vertex sinusoidally:
uniform float time;
attribute vec4 vPosition;
void main()
{
vPosition.x *= (1+sin(time));
gl_Position = vPosition;
}
We still must establish a connection between the corresponding time variables in the application and the shader and get the values
from the application to the shader. After the shaders have been compiled and linked, we can get the correspondence in the
application in a manner similar to vertex attributes.We get the location by
GLint timeParam;
timeParam = glGetUniformLocation(program, "time");
Now whenever we want to send the elapsed time to the shader, we execute
132

