Passing In Uniforms
Uniforms are used to control a shader while it is running. They can pass in data such as object transforms, the time, the screen resolution or anything else really.
There are two parts to passing in a uniform:
- Finding where the uniform is using
gl.get_uniform_location(&program, name)
- When the program is active setting the value of the uniform using
gl.uniform*
to set the value.
I've also changed the triangle to being a single full-screen quad. This means we can now do fancy pixel-shader-rendering:
Yes that's a single quad. The Shader is taken from shadertoy, written by "iq" and used under CC-BY-NC-SA 3.0.
For this I passed in a floating point number for time, and a float vec2 for resolution:
let uniform_resolution = gl.get_uniform_location(&program, "iResolution");
let uniform_time = gl.get_uniform_location(&program, "iTime");
<< snip >>
gl.use_program(Some(&self.program));
gl.uniform1f(self.uniform_time.as_ref(), self.time);
gl.uniform2f(
self.uniform_resolution.as_ref(),
self.resolution.0 as f32,
self.resolution.1 as f32,
);
There are some gotcha's. The uniform name has to exist in the shader and be used.
So if you have the a shader that declares uniform float iTime
but then never
uses it, the uniform will be compiled out, and get_uniform_location
will
return None
. Because the gl.uniform*
functions can handle None, the result
is simply that it has no effect.
Another gotcha is that the program must be active (
gl.use_program(Some(&self.program));
) when you set the uniform value.
Otherwise you'll get a warning in console and nothing will happen.