pub const REFLECTION: &str = "// Roughness-aware reflection composite, split into two passes so the wide\n// glossy blur runs at reduced resolution. One fragment per compile, selected by\n// a define so each variant declares exactly the resources it binds (Metal and\n// DXIL indices are assigned in declaration order, so an unused declaration\n// would shift the live ones):\n//\n// REFLECTION_BLUR - reduced resolution: weight-averages the SSR / RT\n// resolve target over a roughness-scaled cone into the\n// blur target. This is the expensive part (up to 17\n// taps), so running it at a fraction of the pixels is\n// the saving.\n// REFLECTION_COMPOSITE - full resolution: lerps the FULL-RES sharp reflection\n// against the upsampled blur by roughness, then\n// composites over the scene. A near-mirror\n// (roughness ~0) reads the sharp full-res tap so it\n// stays razor-sharp; a rough surface reads the cheap\n// upsampled blur, which is low-frequency anyway.\n//\n// Pairs with `fullscreen_vertex` in fullscreen.slang.\n\n// Surfaces rougher than this get no reflection (the resolve already wrote\n// weight 0); below it the blur cone ramps from a sharp mirror at 0 to\n// REFL_BLUR_MAX. Locked to concinnity_core::gfx::ssr::REFLECTION_ROUGHNESS_CUT\n// by unit test, so the SSR, RT, and composite passes can never disagree on it.\nstatic const float REFLECTION_ROUGHNESS_CUT = 0.6;\n\n#if defined(REFLECTION_BLUR)\n\n// The resolve target (rgb = reflected radiance, a = Fresnel/gloss composite\n// weight) and the G-buffer roughness the cone radius keys off.\n[[vk::binding(0, 0)]] Sampler2D<float4> reflection;\n[[vk::binding(1, 0)]] Sampler2D<float4> rough_tex;\n\n// Largest blur-cone radius in UV at the cut. This is the composite blur cone, a\n// separate quantity from the resolve\'s own in-tap gather radius.\nstatic const float REFL_BLUR_MAX = 0.02;\n\n// Two 8-tap rings (45-degree steps) at half and full radius approximate the\n// widening glossy reflection cone.\nstatic const float2 REFL_RING[8] = {\n float2( 1.0, 0.0 ), float2( 0.70710678, 0.70710678),\n float2( 0.0, 1.0 ), float2(-0.70710678, 0.70710678),\n float2(-1.0, 0.0 ), float2(-0.70710678, -0.70710678),\n float2( 0.0, -1.0 ), float2( 0.70710678, -0.70710678),\n};\n\n[shader(\"fragment\")]\nfloat4 reflection_blur_fragment([[vk::location(0)]] float2 uv : TEXCOORD0) : SV_Target\n{\n float4 c = reflection.Sample(uv);\n float roughness = rough_tex.Sample(uv).r;\n float radius = saturate(roughness / REFLECTION_ROUGHNESS_CUT) * REFL_BLUR_MAX;\n\n // Weight each tap by its own coverage so weightless (non-reflecting) taps\n // cannot drag their colour in; a reflective edge then fades smoothly.\n float3 sum_rw = c.rgb * c.a;\n float sum_w = c.a;\n float taps = 1.0;\n if (radius > 1e-5)\n {\n for (int ring = 0; ring < 2; ring++)\n {\n float rr = radius * (ring == 0 ? 0.5 : 1.0);\n for (int i = 0; i < 8; i++)\n {\n float4 t = reflection.Sample(uv + REFL_RING[i] * rr);\n sum_rw += t.rgb * t.a;\n sum_w += t.a;\n taps += 1.0;\n }\n }\n }\n float3 blurred = sum_w > 1e-4 ? sum_rw / sum_w : c.rgb;\n float weight = sum_w / taps;\n return float4(blurred, weight);\n}\n\n#elif defined(REFLECTION_COMPOSITE)\n\n// reflection: the full-res resolve target (rgb = radiance, a = weight). scene:\n// the base HDR scene. gbuffer: normal+depth, with .a = linear depth. rough_tex:\n// the G-buffer roughness. blur_tex: the reduced-resolution blur from pass 1.\n[[vk::binding(0, 0)]] Sampler2D<float4> reflection;\n[[vk::binding(1, 0)]] Sampler2D<float4> scene;\n[[vk::binding(2, 0)]] Sampler2D<float4> gbuffer;\n[[vk::binding(3, 0)]] Sampler2D<float4> rough_tex;\n[[vk::binding(4, 0)]] Sampler2D<float4> blur_tex;\n\n[shader(\"fragment\")]\nfloat4 reflection_composite_fragment([[vk::location(0)]] float2 uv : TEXCOORD0) : SV_Target\n{\n float3 base = scene.Sample(uv).rgb;\n float depth = gbuffer.Sample(uv).a;\n float4 c = reflection.Sample(uv);\n // Background, or a pixel that does not reflect (weight 0): keep the scene.\n // A tiny weight is still honoured so the composite is exact at the edges.\n if (depth <= 0.0 || c.a <= 0.0)\n {\n return float4(lerp(base, c.rgb, c.a), 1.0);\n }\n\n // 0 at a mirror -> use the sharp full-res tap; 1 at the cut -> use the cheap\n // upsampled blur. The blur is low-frequency, so the bilinear upsample is\n // visually free; only the sharp branch needs full-res detail.\n float t = saturate(rough_tex.Sample(uv).r / REFLECTION_ROUGHNESS_CUT);\n float4 b = blur_tex.Sample(uv);\n\n float3 reflected = lerp(c.rgb, b.rgb, t);\n float weight = lerp(c.a, b.a, t);\n return float4(lerp(base, reflected, weight), 1.0);\n}\n\n#else\n#error \"reflection.slang: define REFLECTION_BLUR or REFLECTION_COMPOSITE\"\n#endif\n";Expand description
reflection.slang.