rdpe 0.1.0

Reaction Diffusion Particle Engine - GPU particle simulations made easy
Documentation
# 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).

```wgsl
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.

```wgsl
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).

```wgsl
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].

```wgsl
// 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.

```wgsl
// 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]

```wgsl
// 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)`.

```wgsl
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

```rust
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