concinnity-device 0.18.65

GPU backends (Metal, Vulkan, DirectX) behind a device facade for Concinnity
Documentation
// src/vulkan/shaders/raymarch_template.glsl
//
// Engine-shipped opaque fragment template for raymarched SDF volumes on Vulkan.
// Appended to the user's fragment shader at compile time (after the helpers +
// the user's `map` / `shade` definitions). GLSL port of `raymarch_fragment` in
// directx/shaders/raymarch_template.hlsl: same control flow, same
// depth-compositing rules, same shading sequence.
//
// The proxy vertex shader (raymarch_proxy.vert) rasterised the bounding-box
// back faces, so each fragment seeds a ray that pierces the box. Hit depth flows
// out through `gl_FragDepth` redeclared `depth_less` (the GLSL analogue of
// HLSL's `SV_DepthLessEqual` / Metal's `[[depth(less)]]`): the hardware depth
// test against the existing MSAA depth discards hits behind rasterised geometry,
// and the same write feeds raymarched-surface depth back into the depth buffer
// so downstream passes (decals, fog, SSR) see the SDF. The encoder re-resolves
// the MSAA colour into hdr_resolve after this pass so the single-sample post
// stack picks up the raymarched pixels.

layout(location = 0) in vec3 v_world_pos;
layout(location = 0) out vec4 out_color;

// `depth_less`: preserve early-Z while allowing the shader to write a smaller
// depth, matching the HLSL `SV_DepthLessEqual` contract.
layout(depth_less) out float gl_FragDepth;

void main() {
    vec3 cam = rmview.view_cam_pos;
    vec3 ray_dir = normalize(v_world_pos - cam);

    // Clip the ray to the volume's AABB (slab test; handles camera-inside).
    vec3 box_min = vol.vol_centre - vol.vol_extent;
    vec3 box_max = vol.vol_centre + vol.vol_extent;
    vec2 box_t = rayBox(cam, ray_dir, box_min, box_max);
    if (box_t.y < max(box_t.x, 0.0)) {
        discard;
    }
    float t_enter = max(box_t.x, 0.001);
    float t_max = min(box_t.y, vol.vol_max_distance);
    if (t_enter >= t_max) {
        discard;
    }

    RayHit hit = coneRaymarch(cam, ray_dir, t_enter, t_max, rmview.view_time);
    if (!hit.hit) {
        discard;
    }

    vec3 hit_pos = cam + ray_dir * hit.t;
    vec3 normal = sdfNormal(hit_pos, vol.vol_params, rmview.view_time, 0.001);
    vec2 frag_uv = gl_FragCoord.xy / rmview.view_viewport;
    SdfSurface surf = shade(hit_pos, normal, vol.vol_params, rmview.view_time, frag_uv);

    vec3 view_dir = -ray_dir;
    vec3 color = shadeAmbientIbl(surf, normal, view_dir, rmview.view_prefilter_mip_count);
    if (lights.num_dir > 0) {
        float shadow_factor = 1.0;
        if (vol.vol_receive_shadows != 0) {
            shadow_factor = sampleSunShadow(hit_pos, hit.t, gl_FragCoord.xy);
        }
        color += shadePbrSun(surf, normal, view_dir, lights.dir[0], shadow_factor);
    }
    color += surf.transmitted;

    // Reproject the hit through view_vp for gl_FragDepth -- same matrix the
    // proxy rasterised with, so the depth shares the rasterised NDC depth space.
    vec4 hit_clip = rmview.view_vp * vec4(hit_pos, 1.0);
    out_color = vec4(color, 1.0);
    gl_FragDepth = hit_clip.z / max(hit_clip.w, 1e-6);
}