// RTStress closest-hit (runs in SHADE). Computes flat-shaded Lambert from // the hit triangle's geometric normal, accumulates ambient, and — if the // surface faces the sun — emits a shadow ray toward the sun. The shadow // ray's miss (sun visible) adds the direct term; its hit (occluded) adds // nothing because RT_FLAG_SKIP_CLOSEST_HIT suppresses closesthit on hit. // // Payload declared here so the assembler sees it before wfPayload / SHADE. struct Payload { color: vec3, // shadow ray: pending direct contribution shadowRay: u32, // 0 primary, 1 shadow }; const SUN_DIR_TO_LIGHT: vec3 = vec3(0.40, 0.85, 0.35); const SUN_COLOR: vec3 = vec3(1.15, 1.05, 0.90); const AMBIENT_COLOR: vec3 = vec3(0.12, 0.13, 0.18); // Cheap per-instance albedo so the grid reads as distinct cubes (and any // TLAS flicker as instance count scales is obvious). 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 worldPos = ray.origin + ray.direction * hit.t; let viewDir = -ray.direction; let nFacing = select(-nWorld, nWorld, dot(nWorld, viewDir) > 0.0); let sunDir = normalize(SUN_DIR_TO_LIGHT); let nDotL = max(0.0, dot(nFacing, sunDir)); rtAccumulate(albedo * AMBIENT_COLOR); if (nDotL > 0.0) { var sp: Payload; sp.color = albedo * SUN_COLOR * nDotL; sp.shadowRay = 1u; let shadowOrigin = worldPos + nFacing * 0.05; rtEmitRay(shadowOrigin, 0.01, sunDir, 100000.0, RT_FLAG_SKIP_CLOSEST_HIT | RT_FLAG_TERMINATE_ON_FIRST_HIT, 0xFFu, 0u, 0u, sp); } }