feat(sdf3d): IBL / environment reflections on the SDF path (ADR-0060 Phase 2) - #359
Open
jeffcrouse wants to merge 3 commits into
Open
feat(sdf3d): IBL / environment reflections on the SDF path (ADR-0060 Phase 2)#359jeffcrouse wants to merge 3 commits into
jeffcrouse wants to merge 3 commits into
Conversation
…Phase 2) Vivid's IBL was dormant — the ENVIRONMENT-fragment machinery + a fallback cube existed in Render3D, but no operator produced an environment, so neither meshes nor SDF surfaces got reflections. Phase 2 builds the source and wires it into the raymarched SDF path (finishing ADR-0060's unification; folds in Phase 3's 'one environment + procedural fallback'). - New Environment operator: bakes a procedural dark-stage sky OR a loaded equirectangular .hdr into irradiance + GGX-prefiltered cubemaps + a split-sum BRDF LUT, and emits the ENVIRONMENT scene fragment. HDR path: stbi_loadf -> RGBA16Float -> an equirect->cube pass; the procedural sky is the asset-free fallback. - Shared create_ibl_bind_group_layout() in gpu_3d.h + a custom_ibl flag on VividSceneFragment, so SDF3D's group-1 IBL layout is group-equivalent to Render3D's group 2 and Render3D's existing real/fallback IBL bind groups bind onto the SDF pipeline unchanged (no new fallback machinery). - SDF3D: a group-1 IBL slot on the pipeline + split-sum ambient/specular terms in the shader (reusing the Phase 1 F0/NdotV/roughness), gated on has_environment. Render3D binds the scene IBL (or the black fallback) at group 1 on the custom SDF dispatch. - blob demo reflects a committed royal_esplanade 1k HDRI (Poly Haven, CC0); BLOB_HDRI=/path overrides, BLOB_HDRI='' selects the procedural sky. Verified: full ctest green, 0 GPU validation errors; a Render3D mesh sphere, an SDF3D sphere, and the blob metaballs all reflect the environment (procedural + real 1k/4k HDRIs). ABI stays additive; vendored gpu_3d.h snapshots synced. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
Production gate (core): ✅ PASS
|
The split-sum BRDF LUT was generated with roughness = 1 - uv.y but sampled at vec2f(NdotV, roughness), so the roughness axis was FLIPPED — every IBL surface read the BRDF response for (1 - its roughness). Generate it as roughness = uv.y to match the sampler. Fixes the energy/appearance of all IBL (mesh + SDF). Also bump the base/prefiltered cube to 256^2 and the GGX prefilter to 256 samples for a crisper reflection. Known limitation (follow-up): the single-mip GGX prefilter shows coherent-sample rings on a near-perfect mirror (roughness -> 0); glossy surfaces (the blob demo) are clean. The proper fix is PDF-based mip sampling of the environment, which needs a base-cube mip chain. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… in an HDR hall A dedicated ADR-0060 Phase 2 showcase: a near-mirror SDF sphere reflecting a loaded royal_esplanade equirect HDRI via image-based lighting, with the same environment drawn as the skybox behind it. An orbit camera (Clock-driven) plus a faint tarnish (subtle roughness smudges + fine scratches, committed maps) make it obviously a rotating reflective object; no direct lights — everything on the ball is reflected environment. The slight gloss also hides the single-mip prefilter rings a perfect mirror would show. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Builds on the merged Phase 1 (#357). Makes SDF metaballs reflect a real environment — the last big visual gap between the SDF path and the mesh path.
The discovery
Reading the code first revealed Vivid's IBL was entirely dormant: the
ENVIRONMENT-fragment machinery + a fallback cube existed in Render3D, but no operator ever produced an environment, so meshes had no reflections either. So Phase 2 couldn't be "bind the existing cubemaps" — it had to build the source. (This also delivers ADR-0060's Phase 3 goal.)What's in it
Environmentoperator — bakes a procedural dark-stage sky or a loaded equirect.hdrinto irradiance + GGX-prefiltered cubemaps + a split-sum BRDF LUT (all render-pass based, cached), emits theENVIRONMENTfragment. HDR:stbi_loadf→ RGBA16Float → an equirect→cube pass.create_ibl_bind_group_layout()(gpu_3d.h) + acustom_iblfragment flag — so SDF3D's group-1 IBL layout is group-equivalent to Render3D's group 2, and Render3D's existing real + fallback IBL bind groups bind onto the SDF pipeline unchanged.F0/NdotV), gated onhas_environment. Render3D binds the scene IBL (or the black fallback) at group 1 on the custom SDF dispatch — one added block.media/blob/);BLOB_HDRI=/pathoverrides,BLOB_HDRI=''uses the procedural sky.Verification
Render3Dmesh sphere, anSDF3Dsphere, and the blob metaballs all reflect the environment — procedural dark-stage sky (cyan/magenta studio reflections on the wet liquid metal) and real CC0 HDRIs (studio / day / night / royal_esplanade). All were byte-black on the SDF path before.boolfragment field; group-1 is pipeline-internal). Vendoredgpu_3d.hsnapshots synced (guard passes).Follow-up (not blocking)
Skybox/IBL render without tone mapping, so a bright HDRI blows out the background (the reflection is correct) — an exposure/tonemap control is a good later add.
🤖 Generated with Claude Code