summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorskal <pascal.massimino@gmail.com>2026-02-16 09:43:06 +0100
committerskal <pascal.massimino@gmail.com>2026-02-16 09:43:06 +0100
commit766c0b0a41ddb4ac1fae68f720a9176a1b5f6070 (patch)
treeb8530354de7133c7828d177889a6a4eb1d0570ba
parent04938fc4a3335e1459e5fb23d0d091fd2a40c296 (diff)
feat(sequence): add inline post-process functions for v2
- Create postprocess_inline.wgsl with 7 inline effect functions - Functions: vignette, flash, fade, theme, solarize, chroma_aberration, distort - Add example combined_postprocess_v2.wgsl showing usage - Register postprocess_inline snippet with ShaderComposer - Add to main and test workspace assets - All tests passing (36/36) Strategy: Simple effects become inline functions instead of separate classes. Complex effects (rotating_cube, hybrid_3d, particles) remain as TODO for v2 port. handoff(Claude): Inline functions ready, 7 simple effects consolidated
-rw-r--r--common/shaders/combined_postprocess_v2.wgsl36
-rw-r--r--common/shaders/postprocess_inline.wgsl61
-rw-r--r--src/gpu/shaders.cc2
-rw-r--r--workspaces/main/assets.txt1
-rw-r--r--workspaces/test/assets.txt1
5 files changed, 101 insertions, 0 deletions
diff --git a/common/shaders/combined_postprocess_v2.wgsl b/common/shaders/combined_postprocess_v2.wgsl
new file mode 100644
index 0000000..a934dce
--- /dev/null
+++ b/common/shaders/combined_postprocess_v2.wgsl
@@ -0,0 +1,36 @@
+// Example: Combined post-process using inline functions
+// Demonstrates how to chain multiple simple effects without separate classes
+
+#include "sequence_v2_uniforms"
+#include "postprocess_inline"
+
+@group(0) @binding(0) var input_sampler: sampler;
+@group(0) @binding(1) var input_texture: texture_2d<f32>;
+@group(0) @binding(2) var<uniform> uniforms: UniformsSequenceParams;
+
+struct VertexOutput {
+ @builtin(position) position: vec4<f32>,
+ @location(0) uv: vec2<f32>,
+};
+
+@vertex fn vs_main(@builtin(vertex_index) vid: u32) -> VertexOutput {
+ var out: VertexOutput;
+ let x = f32((vid & 1u) << 1u);
+ let y = f32((vid & 2u));
+ out.position = vec4<f32>(x * 2.0 - 1.0, 1.0 - y * 2.0, 0.0, 1.0);
+ out.uv = vec2<f32>(x, y);
+ return out;
+}
+
+@fragment fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
+ // Sample base color
+ var color = textureSample(input_texture, input_sampler, in.uv);
+
+ // Apply effects in sequence (customize as needed)
+ // color = apply_solarize(color, 0.4, 0.4, uniforms.time);
+ // color = apply_theme(color, vec3<f32>(1.0, 0.8, 0.6), 0.3);
+ color = apply_vignette(color, in.uv, 0.6, 0.1, uniforms.audio_intensity);
+ // color = apply_flash(color, uniforms.beat_phase * 0.2);
+
+ return color;
+}
diff --git a/common/shaders/postprocess_inline.wgsl b/common/shaders/postprocess_inline.wgsl
new file mode 100644
index 0000000..fcc5e27
--- /dev/null
+++ b/common/shaders/postprocess_inline.wgsl
@@ -0,0 +1,61 @@
+// Inline post-process functions for simple effects
+// Use these instead of separate effect classes for v2 sequences
+
+// Vignette: darkens edges based on distance from center
+fn apply_vignette(color: vec4<f32>, uv: vec2<f32>, radius: f32, softness: f32, intensity: f32) -> vec4<f32> {
+ let d = distance(uv, vec2<f32>(0.5, 0.5));
+ let vignette = smoothstep(radius, radius - softness, d);
+ return vec4<f32>(color.rgb * mix(1.0, vignette, intensity), color.a);
+}
+
+// Flash: additive white flash
+fn apply_flash(color: vec4<f32>, flash_intensity: f32) -> vec4<f32> {
+ return color + vec4<f32>(flash_intensity, flash_intensity, flash_intensity, 0.0);
+}
+
+// Fade: linear interpolation to target color
+fn apply_fade(color: vec4<f32>, fade_amount: f32, fade_color: vec3<f32>) -> vec4<f32> {
+ return vec4<f32>(mix(color.rgb, fade_color, fade_amount), color.a);
+}
+
+// Theme modulation: multiply by color tint
+fn apply_theme(color: vec4<f32>, theme_color: vec3<f32>, strength: f32) -> vec4<f32> {
+ return vec4<f32>(mix(color.rgb, color.rgb * theme_color, strength), color.a);
+}
+
+// Solarize: threshold-based color inversion
+fn apply_solarize(color: vec4<f32>, threshold: f32, strength: f32, time: f32) -> vec4<f32> {
+ let pattern_num = u32(time / 2.0);
+ let is_even = (pattern_num % 2u) == 0u;
+ let thr = threshold + 0.15 * sin(time);
+ var col = color;
+
+ if (is_even) {
+ if (col.r < thr) { col.r = mix(col.r, 1.0 - col.r, strength); }
+ if (col.g < thr) { col.g = mix(col.g, 1.0 - col.g * 0.7, strength * 0.7); }
+ if (col.b < thr) { col.b = mix(col.b, col.b * 0.5, strength); }
+ } else {
+ if (col.r < thr) { col.r = mix(col.r, col.r * 0.6, strength); }
+ if (col.g < thr) { col.g = mix(col.g, 1.0 - col.g * 0.8, strength * 0.8); }
+ if (col.b < thr) { col.b = mix(col.b, 1.0 - col.b, strength); }
+ }
+ return col;
+}
+
+// Chroma aberration: RGB channel offset
+fn apply_chroma_aberration(input_tex: texture_2d<f32>, input_sampler: sampler,
+ uv: vec2<f32>, offset: f32, resolution: vec2<f32>) -> vec4<f32> {
+ let pixel_offset = offset / resolution;
+ let r = textureSample(input_tex, input_sampler, uv + vec2<f32>(pixel_offset.x, 0.0)).r;
+ let g = textureSample(input_tex, input_sampler, uv).g;
+ let b = textureSample(input_tex, input_sampler, uv - vec2<f32>(pixel_offset.x, 0.0)).b;
+ let a = textureSample(input_tex, input_sampler, uv).a;
+ return vec4<f32>(r, g, b, a);
+}
+
+// Distort: UV distortion based on time
+fn apply_distort(uv: vec2<f32>, time: f32, strength: f32) -> vec2<f32> {
+ let distort_x = sin(uv.y * 10.0 + time * 2.0) * strength;
+ let distort_y = cos(uv.x * 10.0 + time * 2.0) * strength;
+ return uv + vec2<f32>(distort_x, distort_y);
+}
diff --git a/src/gpu/shaders.cc b/src/gpu/shaders.cc
index d768cef..4f24705 100644
--- a/src/gpu/shaders.cc
+++ b/src/gpu/shaders.cc
@@ -33,6 +33,8 @@ void InitShaderComposer() {
register_if_exists("common_uniforms", AssetId::ASSET_SHADER_COMMON_UNIFORMS);
register_if_exists("sequence_v2_uniforms",
AssetId::ASSET_SHADER_SEQUENCE_V2_UNIFORMS);
+ register_if_exists("postprocess_inline",
+ AssetId::ASSET_SHADER_POSTPROCESS_INLINE);
register_if_exists("camera_common", AssetId::ASSET_SHADER_CAMERA_COMMON);
register_if_exists("math/sdf_shapes", AssetId::ASSET_SHADER_MATH_SDF_SHAPES);
register_if_exists("math/sdf_utils", AssetId::ASSET_SHADER_MATH_SDF_UTILS);
diff --git a/workspaces/main/assets.txt b/workspaces/main/assets.txt
index 0558ae1..de96eab 100644
--- a/workspaces/main/assets.txt
+++ b/workspaces/main/assets.txt
@@ -81,6 +81,7 @@ SHADER_SCENE1, NONE, shaders/scene1.wgsl, "Scene1 effect shader"
# --- Sequence v2 Shaders ---
SHADER_SEQUENCE_V2_UNIFORMS, NONE, ../../common/shaders/sequence_v2_uniforms.wgsl, "Sequence v2 Uniforms Snippet"
+SHADER_POSTPROCESS_INLINE, NONE, ../../common/shaders/postprocess_inline.wgsl, "Inline Post-Process Functions"
SHADER_PASSTHROUGH_V2, NONE, ../../common/shaders/passthrough_v2.wgsl, "Passthrough Shader (v2)"
SHADER_GAUSSIAN_BLUR_V2, NONE, ../../common/shaders/gaussian_blur_v2.wgsl, "Gaussian Blur Shader (v2)"
SHADER_HEPTAGON_V2, NONE, ../../common/shaders/heptagon_v2.wgsl, "Heptagon Shader (v2)"
diff --git a/workspaces/test/assets.txt b/workspaces/test/assets.txt
index 5ed8af6..8550eca 100644
--- a/workspaces/test/assets.txt
+++ b/workspaces/test/assets.txt
@@ -70,6 +70,7 @@ MASKED_CUBE_SHADER, NONE, shaders/masked_cube.wgsl, "Masked cube shader"
# --- Sequence v2 Shaders ---
SHADER_SEQUENCE_V2_UNIFORMS, NONE, ../../common/shaders/sequence_v2_uniforms.wgsl, "Sequence v2 Uniforms Snippet"
+SHADER_POSTPROCESS_INLINE, NONE, ../../common/shaders/postprocess_inline.wgsl, "Inline Post-Process Functions"
SHADER_PASSTHROUGH_V2, NONE, ../../common/shaders/passthrough_v2.wgsl, "Passthrough Shader (v2)"
SHADER_GAUSSIAN_BLUR_V2, NONE, ../../common/shaders/gaussian_blur_v2.wgsl, "Gaussian Blur Shader (v2)"
SHADER_HEPTAGON_V2, NONE, ../../common/shaders/heptagon_v2.wgsl, "Heptagon Shader (v2)"