summaryrefslogtreecommitdiff
path: root/doc/SDF_EFFECT_GUIDE.md
diff options
context:
space:
mode:
authorskal <pascal.massimino@gmail.com>2026-02-28 08:29:44 +0100
committerskal <pascal.massimino@gmail.com>2026-02-28 08:29:44 +0100
commit514b8d7141d1346c48c9e301d2b89fd5e5f42cc9 (patch)
treea04933a6e3d1021efcd606607c66fc7d6205fd88 /doc/SDF_EFFECT_GUIDE.md
parente39ccafe38134ac8b06fc0b14c2537293fc9fa89 (diff)
remove SDFEffect base class and sdf_test, update SDF_EFFECT_GUIDE
- Delete unused SDFEffect base class (src/gpu/sdf_effect.h) - Delete sdf_test.wgsl and SHADER_SDF_TEST from assets.txt - Rewrite SDF_EFFECT_GUIDE.md based on Scene1 canonical pattern: correct bindings (2/3), vec4f syntax, UniformsSequenceParams - Fix missing newline at end of gpu.h handoff(Claude): SDF cleanup done, guide updated to match current Effect API
Diffstat (limited to 'doc/SDF_EFFECT_GUIDE.md')
-rw-r--r--doc/SDF_EFFECT_GUIDE.md217
1 files changed, 126 insertions, 91 deletions
diff --git a/doc/SDF_EFFECT_GUIDE.md b/doc/SDF_EFFECT_GUIDE.md
index fba80e7..06511e5 100644
--- a/doc/SDF_EFFECT_GUIDE.md
+++ b/doc/SDF_EFFECT_GUIDE.md
@@ -1,86 +1,144 @@
# SDF Effect Guide
-Streamlined workflow for SDF raymarching effects using the `SDFEffect` base class.
+Workflow for SDF raymarching effects. Canonical example: `Scene1`.
---
-## Quick Start
+## C++ Pattern
+
+Inherit from `Effect`. Add `UniformBuffer<CameraParams> camera_params_` as a member,
+passed as `effect_params` to `pp_update_bind_group`.
```cpp
// src/effects/my_sdf_effect.h
-class MySDFEffect : public SDFEffect {
- MySDFEffect(const GpuContext& ctx);
- void render(WGPURenderPassEncoder pass,
- const CommonPostProcessUniforms& uniforms) override;
- RenderPass pass_;
+#pragma once
+#include "gpu/camera_params.h"
+#include "gpu/effect.h"
+#include "gpu/uniform_helper.h"
+#include "gpu/wgpu_resource.h"
+
+class MySdfEffect : public Effect {
+ public:
+ MySdfEffect(const GpuContext& ctx, const std::vector<std::string>& inputs,
+ const std::vector<std::string>& outputs, float start_time,
+ float end_time);
+
+ void render(WGPUCommandEncoder encoder, const UniformsSequenceParams& params,
+ NodeRegistry& nodes) override;
+
+ private:
+ RenderPipeline pipeline_;
+ BindGroup bind_group_;
+ UniformBuffer<CameraParams> camera_params_;
};
```
```cpp
// src/effects/my_sdf_effect.cc
#include "effects/my_sdf_effect.h"
+#include "effects/shaders.h"
#include "gpu/gpu.h"
-#include "gpu/shaders.h"
+#include "gpu/post_process_helper.h"
+#include "util/mini_math.h"
+
+MySdfEffect::MySdfEffect(const GpuContext& ctx,
+ const std::vector<std::string>& inputs,
+ const std::vector<std::string>& outputs,
+ float start_time, float end_time)
+ : Effect(ctx, inputs, outputs, start_time, end_time) {
+ HEADLESS_RETURN_IF_NULL(ctx_.device);
+
+ create_nearest_sampler();
+ create_dummy_scene_texture();
+
+ camera_params_.init(ctx_.device);
-MySDFEffect::MySDFEffect(const GpuContext& ctx) : SDFEffect(ctx) {
- ResourceBinding bindings[] = {
- {uniforms_.get(), WGPUBufferBindingType_Uniform},
- {camera_params_.get(), WGPUBufferBindingType_Uniform}};
- pass_ = gpu_create_render_pass(ctx_.device, ctx_.format,
- my_sdf_shader_wgsl, bindings, 2);
- pass_.vertex_count = 3;
+ pipeline_.set(create_post_process_pipeline(
+ ctx_.device, WGPUTextureFormat_RGBA8Unorm, my_sdf_shader_wgsl));
}
-void MySDFEffect::render(WGPURenderPassEncoder pass,
- const CommonPostProcessUniforms& uniforms) {
- uniforms_.update(ctx_.queue, uniforms);
+void MySdfEffect::render(WGPUCommandEncoder encoder,
+ const UniformsSequenceParams& params,
+ NodeRegistry& nodes) {
+ // Update camera (orbiting example)
+ CameraParams cam;
+ const float R = 6.0f;
+ const vec3 ro(R * sin(params.time * 0.5f), 2.0f, R * cos(params.time * 0.5f));
+ cam.inv_view = mat4::look_at(ro, vec3(0, 0, 0), vec3(0, 1, 0)).inverse();
+ cam.fov = 1.0472f; // 60 degrees
+ cam.near_plane = 0.1f;
+ cam.far_plane = 100.0f;
+ cam.aspect_ratio = 1.0f; // aspect handled in shader
+ camera_params_.update(ctx_.queue, cam);
- // Orbiting camera
- vec3 cam_pos(std::cos(uniforms.time * 0.5f) * 5.0f, 2.0f,
- std::sin(uniforms.time * 0.5f) * 5.0f);
- update_camera(cam_pos, vec3(0, 0, 0), vec3(0, 1, 0), 0.785398f, 0.1f, 100.0f,
- uniforms.aspect_ratio);
+ WGPUTextureView output_view = nodes.get_view(output_nodes_[0]);
- wgpuRenderPassEncoderSetPipeline(pass, pass_.pipeline);
- wgpuRenderPassEncoderSetBindGroup(pass, 0, pass_.bind_group, 0, nullptr);
- wgpuRenderPassEncoderDraw(pass, pass_.vertex_count, 1, 0, 0);
+ pp_update_bind_group(ctx_.device, pipeline_.get(), bind_group_.get_address(),
+ dummy_texture_view_.get(), uniforms_buffer_.get(),
+ camera_params_.get());
+
+ WGPURenderPassColorAttachment color_attachment = {};
+ gpu_init_color_attachment(color_attachment, output_view);
+
+ WGPURenderPassDescriptor pass_desc = {};
+ pass_desc.colorAttachmentCount = 1;
+ pass_desc.colorAttachments = &color_attachment;
+
+ WGPURenderPassEncoder pass =
+ wgpuCommandEncoderBeginRenderPass(encoder, &pass_desc);
+ wgpuRenderPassEncoderSetPipeline(pass, pipeline_.get());
+ wgpuRenderPassEncoderSetBindGroup(pass, 0, bind_group_.get(), 0, nullptr);
+ wgpuRenderPassEncoderDraw(pass, 3, 1, 0, 0); // Fullscreen triangle
+ wgpuRenderPassEncoderEnd(pass);
+ wgpuRenderPassEncoderRelease(pass);
}
```
+---
+
+## WGSL Pattern
+
+Binding layout (standard post-process):
+- `@binding(0)` — sampler (unused for SDF, but layout requires it)
+- `@binding(1)` — input texture (unused for SDF)
+- `@binding(2)` — `UniformsSequenceParams`
+- `@binding(3)` — `CameraParams`
+
```wgsl
// workspaces/main/shaders/my_sdf.wgsl
-#include "common_uniforms"
+#include "sequence_uniforms"
#include "camera_common"
#include "math/sdf_shapes"
#include "render/raymarching"
-@group(0) @binding(0) var<uniform> uniforms: CommonUniforms;
-@group(0) @binding(1) var<uniform> camera: CameraParams;
+@group(0) @binding(2) var<uniform> uniforms: UniformsSequenceParams;
+@group(0) @binding(3) var<uniform> camera: CameraParams;
-fn df(p: vec3<f32>) -> f32 {
+fn df(p: vec3f) -> f32 {
return sdSphere(p, 1.0);
}
@vertex
-fn vs_main(@builtin(vertex_index) vid: u32) -> @builtin(position) vec4<f32> {
+fn vs_main(@builtin(vertex_index) vid: u32) -> @builtin(position) vec4f {
let x = f32((vid & 1u) << 2u) - 1.0;
let y = f32((vid & 2u) << 1u) - 1.0;
- return vec4<f32>(x, y, 0.0, 1.0);
+ return vec4f(x, y, 0.0, 1.0);
}
@fragment
-fn fs_main(@builtin(position) pos: vec4<f32>) -> @location(0) vec4<f32> {
- let uv = (pos.xy / uniforms.resolution - 0.5) * 2.0;
+fn fs_main(@builtin(position) pos: vec4f) -> @location(0) vec4f {
+ let uv = (pos.xy / uniforms.resolution - 0.5) * 2.0
+ * vec2f(uniforms.aspect_ratio, 1.0);
let ray = getCameraRay(camera, uv);
let t = rayMarch(ray.origin, ray.direction, 0.0);
- var col = vec3<f32>(0.1);
+ var col = vec3f(0.1);
if (t < MAX_RAY_LENGTH) {
let hit_pos = ray.origin + ray.direction * t;
let n = normal(hit_pos);
- col = vec3<f32>(n * 0.5 + 0.5);
+ col = n * 0.5 + 0.5;
}
- return vec4<f32>(col, 1.0);
+ return vec4f(col, 1.0);
}
```
@@ -88,77 +146,54 @@ fn fs_main(@builtin(position) pos: vec4<f32>) -> @location(0) vec4<f32> {
## Available Uniforms
-### CommonUniforms (binding 0)
-- `resolution`: vec2 (screen size)
-- `time`: float (physical seconds)
-- `beat_time`: float (musical beats)
-- `beat_phase`: float (0-1 within beat)
-- `audio_intensity`: float (peak)
-- `aspect_ratio`: float
+### UniformsSequenceParams (binding 2)
+- `resolution`: vec2f
+- `time`: f32 (physical seconds)
+- `beat_time`: f32 (musical beats)
+- `beat_phase`: f32 (0–1 within beat)
+- `audio_intensity`: f32
+- `aspect_ratio`: f32
-### CameraParams (binding 1)
-- `inv_view`: mat4x4 (inverse view matrix)
-- `fov`: float (vertical FOV in radians)
-- `near_plane`, `far_plane`: float
-- `aspect_ratio`: float
+### CameraParams (binding 3)
+- `inv_view`: mat4x4f (inverse view matrix)
+- `fov`: f32 (vertical FOV, radians)
+- `near_plane`, `far_plane`: f32
+- `aspect_ratio`: f32
---
## WGSL Helpers
-From `camera_common.wgsl`:
-
+### `camera_common`
```wgsl
-fn getCameraRay(cam: CameraParams, uv: vec2<f32>) -> Ray;
-fn getCameraPosition(cam: CameraParams) -> vec3<f32>;
-fn getCameraForward(cam: CameraParams) -> vec3<f32>;
-fn getCameraUp(cam: CameraParams) -> vec3<f32>;
-fn getCameraRight(cam: CameraParams) -> vec3<f32>;
+fn getCameraRay(cam: CameraParams, uv: vec2f) -> Ray;
+fn getCameraPosition(cam: CameraParams) -> vec3f;
+fn getCameraForward(cam: CameraParams) -> vec3f;
```
-From `render/raymarching.wgsl`:
-
+### `render/raymarching`
```wgsl
-fn rayMarch(ro: vec3<f32>, rd: vec3<f32>, initt: f32) -> f32;
-fn normal(pos: vec3<f32>) -> vec3<f32>;
-fn shadow(lp: vec3<f32>, ld: vec3<f32>, mint: f32, maxt: f32) -> f32;
+fn rayMarch(ro: vec3f, rd: vec3f, initt: f32) -> f32;
+fn normal(pos: vec3f) -> vec3f;
+fn shadow(lp: vec3f, ld: vec3f, mint: f32, maxt: f32) -> f32;
```
-From `math/sdf_shapes.wgsl`:
-
+### `math/sdf_shapes`
```wgsl
-fn sdSphere(p: vec3<f32>, r: float) -> f32;
-fn sdBox(p: vec3<f32>, b: vec3<f32>) -> f32;
-fn sdTorus(p: vec3<f32>, t: vec2<f32>) -> f32;
-fn sdPlane(p: vec3<f32>, n: vec3<f32>, h: f32) -> f32;
-```
-
----
-
-## Camera Control
-
-```cpp
-// Method 1: Manual values
-update_camera(position, target, up, fov, near, far, aspect);
-
-// Method 2: Camera object
-Camera cam;
-cam.position = vec3(0, 5, 10);
-cam.target = vec3(0, 0, 0);
-update_camera(cam, uniforms.aspect_ratio);
+fn sdSphere(p: vec3f, r: f32) -> f32;
+fn sdBox(p: vec3f, b: vec3f) -> f32;
+fn sdTorus(p: vec3f, t: vec2f) -> f32;
+fn sdPlane(p: vec3f, n: vec3f, h: f32) -> f32;
```
---
## Registration Checklist
+Follow `doc/EFFECT_WORKFLOW.md`. SDF-specific notes:
1. Add shader to `workspaces/main/assets.txt`
-2. Add extern declaration to `src/gpu/shaders.h`
-3. Add definition to `src/gpu/shaders.cc`
-4. Add `.cc` to `cmake/DemoSourceLists.cmake` (both headless & normal)
-5. Include header in `src/gpu/demo_effects.h`
-6. Add to `src/tests/gpu/test_demo_effects.cc`
-
----
-
-## Example: workspaces/main/shaders/sdf_test.wgsl
+2. Add `.cc` to `CMakeLists.txt` GPU_SOURCES (**both** headless and normal sections)
+3. Include header in `src/gpu/demo_effects.h`
+4. Add to `workspaces/main/timeline.seq` with priority modifier (`+`, `=`, or `-`)
+5. Add to `src/tests/gpu/test_demo_effects.cc` under `scene_effects`
+6. Build: `cmake --build build -j4 && cd build && ./test_demo_effects`