diff options
| author | skal <pascal.massimino@gmail.com> | 2026-03-22 23:51:40 +0100 |
|---|---|---|
| committer | skal <pascal.massimino@gmail.com> | 2026-03-22 23:51:40 +0100 |
| commit | 12d5d5f1762a0c00405950b6ff5e564880f0ff36 (patch) | |
| tree | b6e03dbecd424f8a4c02c815b4fec9a160529d8e | |
| parent | 8fd3eda0ed069b1a817261f8f4d6a35c565b3fe4 (diff) | |
refactor(cnn_v3): simplify sphere SDF in shadow pass, remove per-frame alloc
gbuf_shadow.wgsl — dfWithID():
- Sphere: replace inv_model local-space transform with direct world-space
formula (length(p - center) - radius). Exact, no matrix multiply, no
floating-point error from matrix inversion that can corrupt soft-shadow
penumbra over 64 march steps.
- lp/scale now computed only inside the cases that need them (box/torus/plane)
instead of eagerly for every object.
gbuffer_effect.cc — upload_scene_data():
- Replace per-frame std::vector<GBufObjectData> heap allocation with a
file-static staging buffer s_obj_staging[256]: zero alloc per frame.
handoff(Gemini): sphere SDF now exact; shadow march should be cleaner.
| -rw-r--r-- | cnn_v3/shaders/gbuf_shadow.wgsl | 34 | ||||
| -rw-r--r-- | cnn_v3/src/gbuffer_effect.cc | 19 |
2 files changed, 35 insertions, 18 deletions
diff --git a/cnn_v3/shaders/gbuf_shadow.wgsl b/cnn_v3/shaders/gbuf_shadow.wgsl index 735e47c..6c81d66 100644 --- a/cnn_v3/shaders/gbuf_shadow.wgsl +++ b/cnn_v3/shaders/gbuf_shadow.wgsl @@ -28,7 +28,9 @@ struct GBufLightsUniforms { // Stub required by render/raymarching (shadow() / rayMarch() call df()). fn df(p: vec3f) -> f32 { return MAX_RAY_LENGTH; } -// SDF of the full scene: proxy box for each object transformed to local space. +// SDF of the full scene. +// Sphere: direct world-space formula (exact, no matrix multiply). +// Box/Torus/Plane: local-space transform + uniform-scale correction. fn dfWithID(p: vec3f) -> RayMarchResult { var res: RayMarchResult; res.distance = MAX_RAY_LENGTH; @@ -38,16 +40,32 @@ fn dfWithID(p: vec3f) -> RayMarchResult { let n = u32(globals.params.x); for (var i = 0u; i < n; i++) { let obj = object_data.objects[i]; - let lp = (obj.inv_model * vec4f(p, 1.0)).xyz; let obj_type = u32(obj.params.x); - // Scale factor: convert local-space SDF to world-space distance. - let scale = length(obj.model[0].xyz); var d: f32; switch obj_type { - case 1u: { d = sdSphere(lp, 1.0) * scale; } // SPHERE - case 2u: { d = sdPlane(lp, vec3f(0.0, 1.0, 0.0), obj.params.y); } // PLANE - case 3u: { d = sdTorus(lp, vec2f(0.8, 0.2)) * scale; } // TORUS - default: { d = sdBox(lp, vec3f(1.0)) * scale; } // CUBE (0) + fallback + case 1u: { + // SPHERE: direct world-space SDF — avoids matrix multiply, exact. + let c = obj.model[3].xyz; + let r = length(obj.model[0].xyz); + d = length(p - c) - r; + } + case 2u: { + // PLANE + let lp = (obj.inv_model * vec4f(p, 1.0)).xyz; + d = sdPlane(lp, vec3f(0.0, 1.0, 0.0), obj.params.y); + } + case 3u: { + // TORUS + let lp = (obj.inv_model * vec4f(p, 1.0)).xyz; + let scale = length(obj.model[0].xyz); + d = sdTorus(lp, vec2f(0.8, 0.2)) * scale; + } + default: { + // CUBE (0) + fallback — uniform scale assumed. + let lp = (obj.inv_model * vec4f(p, 1.0)).xyz; + let scale = length(obj.model[0].xyz); + d = sdBox(lp, vec3f(1.0)) * scale; + } } if (d < res.distance) { res.distance = d; diff --git a/cnn_v3/src/gbuffer_effect.cc b/cnn_v3/src/gbuffer_effect.cc index b059915..829c199 100644 --- a/cnn_v3/src/gbuffer_effect.cc +++ b/cnn_v3/src/gbuffer_effect.cc @@ -30,6 +30,9 @@ struct GBufObjectData { static_assert(sizeof(GBufObjectData) == sizeof(float) * 40, "GBufObjectData must be 160 bytes"); +// Reusable CPU staging buffer (single-threaded demo — no concurrency needed). +static GBufObjectData s_obj_staging[kGBufMaxObjects]; + // GlobalUniforms struct mirroring renderer.h struct GBufGlobalUniforms { mat4 view_proj; @@ -446,23 +449,19 @@ void GBufferEffect::upload_scene_data(const Scene& scene, wgpuQueueWriteBuffer(ctx_.queue, global_uniforms_buf_.buffer, 0, &gu, sizeof(GBufGlobalUniforms)); - // Upload object data. + // Upload object data (no per-frame heap alloc — reuse s_obj_staging). if (num_objects > 0) { ensure_objects_buffer(num_objects); - std::vector<GBufObjectData> obj_data; - obj_data.reserve((size_t)num_objects); for (int i = 0; i < num_objects; ++i) { const Object3D& obj = scene.objects[(size_t)i]; const mat4 m = obj.get_model_matrix(); - GBufObjectData d; - d.model = m; - d.inv_model = m.inverse(); - d.color = obj.color; - d.params = vec4((float)(int)obj.type, 0.0f, 0.0f, 0.0f); - obj_data.push_back(d); + s_obj_staging[i].model = m; + s_obj_staging[i].inv_model = m.inverse(); + s_obj_staging[i].color = obj.color; + s_obj_staging[i].params = vec4((float)(int)obj.type, 0.0f, 0.0f, 0.0f); } wgpuQueueWriteBuffer(ctx_.queue, objects_buf_.buffer, 0, - obj_data.data(), + s_obj_staging, (size_t)num_objects * sizeof(GBufObjectData)); } } |
