summaryrefslogtreecommitdiff
path: root/tools/shadertoy/README.md
blob: 878b53ced97da3469e8636a36dd6e2a70618eb3f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# ShaderToy Conversion Guide

Convert ShaderToy shaders to demo effects. See `doc/EFFECT_WORKFLOW.md` for full integration checklist.

## Quick Start (Automated)

```bash
# Generate effect files from ShaderToy code
./tools/shadertoy/convert_shadertoy.py tunnel.txt Tunnel
./tools/shadertoy/convert_shadertoy.py blur.txt Blur --post-process
./tools/shadertoy/convert_shadertoy.py tunnel.txt Tunnel --shader-only  # regen shader only

# Follow printed instructions to integrate (assets.txt, shaders.h, CMakeLists.txt, timeline.seq)
```

Generates: `src/effects/<name>_effect.{h,cc}` + `src/shaders/<name>.wgsl`

## Manual Templates

```bash
cp tools/shadertoy/template.h   src/effects/myeffect_effect.h
cp tools/shadertoy/template.cc  src/effects/myeffect_effect.cc
cp tools/shadertoy/template.wgsl src/shaders/myeffect.wgsl
```

Then rename `ShaderToyEffect` → `MyeffectEffect` in `.h` and `.cc`, paste shader code into `fs_main()`, and follow `doc/EFFECT_WORKFLOW.md`.

## GLSL → WGSL Conversions

| ShaderToy | WGSL |
|-----------|------|
| `iResolution.xy` | `uniforms.resolution` |
| `iTime` | `uniforms.time` |
| `fragCoord` | `in.position.xy` (pixel) or `in.uv * uniforms.resolution` |
| `float` | `f32` |
| `vec2/vec3/vec4` | `vec2f/vec3f/vec4f` |
| `mat2/mat3/mat4` | `mat2x2f/mat3x3f/mat4x4f` |
| `mod(x, y)` | `x % y` |
| `texture(iChannel0, uv)` | `textureSample(txt, smplr, uv)` |
| `fragColor = col;` | `return col;` |
| `float foo(vec2 p)` | `fn foo(p: vec2f) -> f32` |

## Example

**Input:**
```glsl
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    vec2 uv = fragCoord / iResolution.xy;
    vec3 col = 0.5 + 0.5 * cos(iTime + uv.xyx + vec3(0,2,4));
    fragColor = vec4(col, 1.0);
}
```

**Output WGSL:**
```wgsl
@fragment fn fs_main(in: VertexOutput) -> @location(0) vec4f {
    let uv = in.uv;
    let col = vec3f(0.5) + 0.5 * cos(uniforms.time + uv.xyx + vec3f(0.0, 2.0, 4.0));
    return vec4f(col, 1.0);
}
```

## Available Uniforms (`UniformsSequenceParams`, binding 2)

| Field | Type | Description |
|-------|------|-------------|
| `resolution` | `vec2f` | Screen dimensions |
| `aspect_ratio` | `f32` | Width/height |
| `time` | `f32` | Physical time (seconds) |
| `beat_time` | `f32` | Musical beats (absolute) |
| `beat_phase` | `f32` | Fractional beat [0..1] |
| `audio_intensity` | `f32` | Audio peak |

## Custom Parameters (optional, binding 3)

**C++** (must be 16-byte aligned):
```cpp
struct MyParams { float speed; float scale; float _pad[2]; };
static_assert(sizeof(MyParams) == 16, "...");
UniformBuffer<MyParams> params_;  // add to .h
```

**WGSL:**
```wgsl
struct MyParams { speed: f32, scale: f32, _pad0: f32, _pad1: f32, }
@group(0) @binding(3) var<uniform> params: MyParams;
```

Also pass `params_.get()` instead of `{nullptr, 0}` in `pp_update_bind_group()`.