Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Shader Utilities

RDPE includes built-in utility functions that are automatically available in all compute shaders. Use them in Rule::Custom or your custom functions.

Random & Hash Functions

Pseudo-random number generation based on integer hashing.

hash(n: u32) -> u32

Hash a u32 to a pseudo-random u32.

hash2(p: vec2<u32>) -> u32

Hash a 2D coordinate.

hash3(p: vec3<u32>) -> u32

Hash a 3D coordinate.

rand(seed: u32) -> f32

Returns a random float in the range [0, 1).

let r = rand(index * 12345u);  // Different value per particle

rand_range(seed: u32, min_val: f32, max_val: f32) -> f32

Returns a random float in the specified range.

let speed = rand_range(index, 0.5, 2.0);

rand_vec3(seed: u32) -> vec3<f32>

Returns a random vector with components in [-1, 1]. Not normalized.

rand_sphere(seed: u32) -> vec3<f32>

Returns a random point on a unit sphere (normalized).

let direction = rand_sphere(index * 7u);
p.velocity = direction * 2.0;

Noise Functions

Gradient noise for smooth, natural-looking randomness.

noise2(p: vec2<f32>) -> f32

2D simplex noise. Returns values in [-1, 1].

noise3(p: vec3<f32>) -> f32

3D simplex noise. Returns values in [-1, 1].

// Noise-based force field
let force = vec3(
    noise3(p.position * 2.0 + uniforms.time),
    noise3(p.position * 2.0 + uniforms.time + vec3(100.0, 0.0, 0.0)),
    noise3(p.position * 2.0 + uniforms.time + vec3(0.0, 100.0, 0.0))
);
p.velocity += force * uniforms.delta_time;

fbm2(p: vec2<f32>, octaves: i32) -> f32

2D fractal Brownian motion. Layered noise for more detail.

fbm3(p: vec3<f32>, octaves: i32) -> f32

3D fractal Brownian motion.

// More detailed noise with 4 octaves
let turbulence = fbm3(p.position * 1.5, 4);

Color Functions

Convert between color spaces.

hsv_to_rgb(h: f32, s: f32, v: f32) -> vec3<f32>

Convert HSV to RGB.

  • h: Hue [0, 1] (wraps)
  • s: Saturation [0, 1]
  • v: Value/brightness [0, 1]
// Rainbow based on particle position
let hue = (p.position.x + 1.0) * 0.5;  // Map -1..1 to 0..1
p.color = hsv_to_rgb(hue, 0.8, 1.0);

rgb_to_hsv(rgb: vec3<f32>) -> vec3<f32>

Convert RGB to HSV. Returns vec3(h, s, v).

let hsv = rgb_to_hsv(p.color);
let new_hue = hsv.x + 0.1;  // Shift hue
p.color = hsv_to_rgb(new_hue, hsv.y, hsv.z);

Complete Example

use rdpe::prelude::*;

#[derive(Particle, Clone)]
struct Mote {
    position: Vec3,
    velocity: Vec3,
    #[color]
    color: Vec3,
}

fn main() {
    Simulation::<Mote>::new()
        .with_particle_count(25_000)
        .with_spawner(|i, _| Mote {
            position: Vec3::new(
                rand::random::<f32>() * 2.0 - 1.0,
                rand::random::<f32>() * 2.0 - 1.0,
                rand::random::<f32>() * 2.0 - 1.0,
            ),
            velocity: Vec3::ZERO,
            color: Vec3::ONE,
        })
        .with_rule(Rule::Custom(r#"
            // 3D noise force field
            let scale = 2.0;
            let t = uniforms.time * 0.3;

            let force = vec3<f32>(
                noise3(p.position * scale + vec3<f32>(t, 0.0, 0.0)),
                noise3(p.position * scale + vec3<f32>(0.0, t, 100.0)),
                noise3(p.position * scale + vec3<f32>(0.0, 100.0, t))
            );

            p.velocity += force * uniforms.delta_time * 2.0;

            // Color based on FBM noise
            let color_noise = fbm3(p.position * 1.5 + uniforms.time * 0.2, 3);
            let hue = (color_noise + 1.0) * 0.25 + 0.5;
            p.color = hsv_to_rgb(hue, 0.8, 1.0);
        "#.into()))
        .with_rule(Rule::Drag(1.0))
        .with_rule(Rule::WrapWalls)
        .run();
}

Performance Notes

  • Hash functions are very fast - use liberally
  • Noise functions are moderately expensive - a few calls per particle is fine
  • FBM multiplies the cost by the number of octaves
  • For heavy noise use, consider lowering particle count or octaves