// HDRBloom closest-hit (runs in SHADE). Half the cubes are "emitters" that // accumulate a strongly super-1.0 radiance (the HDR signal a bloom pass // extracts); the rest are dim Lambert-shaded fillers near/below 1.0 that the // threshold rejects. The linear accumulator is what RESOLVE writes into the // rgba16float scene target — no tonemap here. // // Payload declared here so the assembler sees it before wfPayload / SHADE. struct Payload { color: vec3, }; const SUN_DIR_TO_LIGHT: vec3 = vec3(0.40, 0.85, 0.35); const AMBIENT_COLOR: vec3 = vec3(0.10, 0.11, 0.16); // Distinct per-instance hue so emitters read as different coloured glows. fn instanceAlbedo(i: u32) -> vec3 { let h = i * 2654435761u; return vec3( 0.35 + 0.6 * f32((h >> 0u) & 255u) / 255.0, 0.35 + 0.6 * f32((h >> 8u) & 255u) / 255.0, 0.35 + 0.6 * f32((h >> 16u) & 255u) / 255.0); } fn closesthit_main(ray: RayDesc, hit: HitInfo, payload: ptr) { let meshRec = meshRecords[tlasEntries[hit.instanceId].blasMeshIdx]; let verts = _rtFetchTri(meshRec, hit.primitiveId); let nObj = normalize(cross(verts[1] - verts[0], verts[2] - verts[0])); let nWorld = normalize(vec3( dot(hit.objectToWorldR0.xyz, nObj), dot(hit.objectToWorldR1.xyz, nObj), dot(hit.objectToWorldR2.xyz, nObj))); let albedo = instanceAlbedo(hit.customIndex); let viewDir = -ray.direction; let nFacing = select(-nWorld, nWorld, dot(nWorld, viewDir) > 0.0); let nDotL = max(0.0, dot(nFacing, normalize(SUN_DIR_TO_LIGHT))); // Every third cube is a bright emitter (HDR, > 1.0); the rest stay dim. if ((hit.customIndex % 3u) == 0u) { // View-independent emission so the whole face glows uniformly. rtAccumulate(albedo * 9.0); } else { rtAccumulate(albedo * (AMBIENT_COLOR + vec3(0.55 * nDotL))); } }