Comment on page
Custom Shaders
With valora, you can shade each path with its own shader, and define custom uniforms. We'll start with this simple GLSL fragment shader:
#version 400
uniform vec3 color;
uniform float scale;
uniform float height;
uniform float width;
out vec4 frag;
void main() {
vec2 pos = gl_FragCoord.xy / scale;
vec3 white = vec3(1., 1., 1.);
frag = vec4(mix(white, color, pos.x / width), 1.);
}
Save this to a file named
pattern.frag
.Now, we'll use valora's shader API to define some uniforms and load the shader. A shader in valora is made of two parts:
- 1.The shader program. This is the GLSL above, which exposes an interface to provide uniforms.
- 2.The uniforms bound to the shader.
First let's define the uniforms type in Rust:
#[derive(UniformSet, Copy, Clone, Debug)]
struct Uniforms {
/// A solid color overlay on the shader pattern.
color: (f32, f32, f32),
/// The vector scale of the output.
scale: f32,
/// Width of the output.
width: f32,
/// Height of the output.
height: f32,
}
The derive macro
UniformSet
will generate mappings from the field types to something we can send to the GPU, should such a mapping exist for the type.Now let's load the shader and draw with it:
fn main() -> Result<()> {
run_fn(Options::from_args(), |gpu, world, _rng| {
let mut program = ShaderProgram::new(&gpu, "pattern.frag")?;
let uniforms = Uniforms {
color: Hsv::new(0., 0.7, 0.7).into_rgb::<Srgb>().into_components(),
scale: world.scale,
width: world.width,
height: world.height,
};
let shader = program.bind(uniforms);
Ok(move |ctx: Context, canvas: &mut Canvas| {
canvas.set_color(LinSrgb::new(1., 1., 1.));
canvas.paint(Filled(ctx.world));
canvas.set_shader(shader.clone());
let square = Ngon::square(world.center(), 200.);
canvas.paint(Filled(square));
})
})
}
If you run the painting with
cargo run --release
, and change the GLSL, you'll notice that the view pane will update live!
A path rendered with a custom shader.
We can update our uniform values each frame. Once the uniforms are updated, we can rebind with the shader program to make a new shader.
let hue = ctx.time.as_secs_f32().sin().abs() * 40.;
uniforms.color = Hsv::new(hue, 0.7, 0.7).into_rgb::<Srgb>().into_components();
canvas.set_shader(program.bind(uniforms));

Last modified 3yr ago