In which you learn how to send parameters to a shader.
The fragment shader's job is to set the color of any pixel that is part of a point, line, or triangle. In the applications you've written so far, the color has been hardcoded in the shader using a line like this:
fragmentColor = vec4(0.0, 0.0, 1.0, 1.0);
Every pixel drawn by this shader will be blue. Suppose you want to provide a user interface that allows the user to change the color. You could embed JavaScript expressions inside the shader program, recompile the source code, and reupload the shader program to the GPU. But that's a lot like building a new house just to make it a different color. A cheaper solution is to use uniforms.
A uniform is a parameter that is sent to the shader instead of hardcoded inside it. You add a uniform by declaring a global variable in either your vertex or fragment shader and tagging it with the keyword uniform
. This fragment shader, for example, receives a uniform named color
:
uniform vec3 color;
out vec4 fragmentColor;
void main() {
fragmentColor = vec4(color, 1.0);
}
They are called uniforms because they hold steady across all pixels touched by a draw call.
The color
uniform in this shader must be set before you issue a draw call. The ShaderProgram
class provides a handful of methods for setting uniforms of different types. To set a vec3
, which in GLSL is a collection of three floats, you call the setUniform3f
method:
// Draw cyan triangles.
shaderProgram.setUniform3f('color', 0, 1, 1);
vao.drawSequence(gl.TRIANGLES);
Though the uniform value will be the same across all pixels of a drawn object, the uniform can be changed between draw calls. For example, this code draws an object first with red triangles and then with blue triangles:
// Draw red triangles.
shaderProgram.setUniform3f('color', 1, 0, 0);
vao.drawSequence(gl.TRIANGLES);
// Draw blue triangles.
shaderProgram.setUniform3f('color', 0, 0, 1);
vao.drawSequence(gl.TRIANGLES);
Get uniforms working in your hello-triangles
application by completing the following exercises.
main.js
:
function setColor(r, g, b) {
shaderProgram.bind();
shaderProgram.setUniform3f('color', r, g, b);
shaderProgram.unbind();
render();
}
// Assignment to window makes a value globally accessible. Without
// it, calling the setColor function from the browser's developer
// tools is difficult.
window.setColor = setColor;
setColor
with three parameters in [0, 1].