pub const RT_TRACE: &str = "// The inline ray-query reflection trace, spliced into a shader at its RT_TRACE\n// marker (see slang_source.rs). The second half of the ray-tracing splice:\n// RT_TYPES declares the records ahead of a shader\'s bindings, this traverses\n// them. One traversal loop for every target -- `RayQuery` lowers to\n// `raytracing::intersection_query` on Metal, `SPV_KHR_ray_query` on Vulkan and\n// SM 6.5 DXIL on DirectX. Nothing here may spell either marker.\n//\n// Hooks the including shader must provide, because each differs per binding\n// model or per pass:\n// rt_params, scene_tlas, geom - the bound params / TLAS / geometry table\n// vert_float / svert_float - one float of the static / deformed stream\n// index_at / skinned_index_word - one u32 index of the static / skinned IB\n// prefilter_level(dir, lod) - the IBL prefilter cube at an explicit mip\n// pool_sample_level0(idx, uv) - the bindless pool at mip 0 (RT_TEXTURED)\n\n// Dielectric base reflectance for the Fresnel.\nstatic const float RT_F0 = 0.04;\n// Floats per `Vertex` (56-byte stride): position, normal, tangent, colour, uv.\nstatic const uint VERTEX_FLOATS = 14u;\n// Skinned objects flag bit 31 of `normal_index`; the trace then fetches the hit\n// triangle from the deformed-vertex / skinned index buffers, which mirror\n// the static layout. The flag is masked off before the pool sample, so skinned\n// hits shade textured like static ones. Matches render_types::RT_SKINNED_FLAG.\nstatic const uint RT_SKINNED_FLAG = 0x80000000u;\n\n// Attribute fetchers into the shared 14-float `Vertex` (normal at float 3,\n// tangent at 6, uv at 12), addressed by absolute vertex index `vi`. The\n// `skinned` set reads the deformed buffer, which carries the identical layout.\nfloat3 rt_vertex_normal(uint vi)\n{\n uint b = vi * VERTEX_FLOATS;\n return float3(vert_float(b + 3u), vert_float(b + 4u), vert_float(b + 5u));\n}\nfloat3 rt_vertex_tangent(uint vi)\n{\n uint b = vi * VERTEX_FLOATS;\n return float3(vert_float(b + 6u), vert_float(b + 7u), vert_float(b + 8u));\n}\nfloat2 rt_vertex_uv(uint vi)\n{\n uint b = vi * VERTEX_FLOATS;\n return float2(vert_float(b + 12u), vert_float(b + 13u));\n}\nfloat3 rt_skinned_normal(uint vi)\n{\n uint b = vi * VERTEX_FLOATS;\n return float3(svert_float(b + 3u), svert_float(b + 4u), svert_float(b + 5u));\n}\nfloat3 rt_skinned_tangent(uint vi)\n{\n uint b = vi * VERTEX_FLOATS;\n return float3(svert_float(b + 6u), svert_float(b + 7u), svert_float(b + 8u));\n}\nfloat2 rt_skinned_uv(uint vi)\n{\n uint b = vi * VERTEX_FLOATS;\n return float2(svert_float(b + 12u), svert_float(b + 13u));\n}\n\n// One index from the skinned index buffer. The skinned BLAS bakes absolute\n// indices, so no base_vertex is added.\nuint rt_skinned_index(uint o)\n{\n return skinned_index_word(o);\n}\n\n// Decode a tangent-space normal map texel. Only X and Y are read; Z is\n// reconstructed from them, so a two-channel source (BC5) decodes the same as an\n// RGBA8 one and normal maps can ship as BC5 blocks.\nfloat3 decode_normal_map(float2 encoded)\n{\n float2 nxy = encoded * 2.0 - 1.0;\n return float3(nxy, sqrt(saturate(1.0 - dot(nxy, nxy))));\n}\n\n// Sun visibility at a hit: 0 where a second ray toward the sun is occluded (a\n// cast shadow inside the reflection), 1 where the sun is visible.\n//\n// RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH is what an occlusion query wants and\n// is what the Vulkan and DirectX legs get; the Metal target drops it (slangc\n// does not map the flag to `intersection_params::accept_any_intersection`), so\n// there the query commits the closest hit instead of the first. Same answer,\n// more traversal.\nfloat rt_shadow(float3 hp, float3 n)\n{\n RayDesc sr;\n sr.Origin = hp + n * 0.02;\n sr.Direction = normalize(rt_params.sun_dir.xyz);\n sr.TMin = 0.001;\n sr.TMax = rt_params.max_distance;\n\n RayQuery<RAY_FLAG_FORCE_OPAQUE | RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH> sq;\n sq.TraceRayInline(scene_tlas, RAY_FLAG_NONE, 0xFFu, sr);\n // Drained rather than stepped once: with the opacity forced there is no\n // non-opaque candidate to resolve, and discarding the step\'s result trips an\n // unused-value warning out of the Metal compiler on slangc\'s emitted call.\n while (sq.Proceed()) {}\n return (sq.CommittedStatus() == COMMITTED_TRIANGLE_HIT) ? 0.0 : 1.0;\n}\n\n// Metallic/roughness hit shading: a sun diffuse term (dielectric only, masked\n// by the shadow ray) plus split IBL -- diffuse irradiance along N, and a\n// specular tap along the onward reflection at a roughness-selected prefilter\n// mip, tinted by F0. Metals drop the diffuse term and tint the reflected\n// environment by their albedo. The material\'s self-emission is added on top, so\n// glowing surfaces light up in reflections. With no EnvironmentMap bound the\n// IBL pair degrades to a small constant ambient.\nfloat3 rt_shade_hit(float3 n, float3 albedo, float hit_rough, float metallic, float3 emissive,\n float3 dir, bool ibl, float max_mip, float shadow)\n{\n float3 f0 = lerp(float3(RT_F0), albedo, metallic);\n float3 diff_a = albedo * (1.0 - metallic);\n float ndl = saturate(dot(n, rt_params.sun_dir.xyz));\n float3 sun = diff_a * rt_params.sun_color.xyz * ndl * shadow;\n if (!ibl)\n {\n return sun + (diff_a + f0) * 0.03 + emissive;\n }\n float3 spec = prefilter_level(reflect(dir, n), hit_rough * max_mip);\n float3 diff = prefilter_level(n, max_mip) * diff_a;\n return sun + diff + spec * f0 + emissive;\n}\n\n// Trace one reflection ray from `origin` along `dir` and shade what it hits.\n// Returns false when the ray escaped the scene, leaving `shaded` untouched: the\n// miss fallback is the caller\'s, because a screen-space resolve and a glass\n// pane want different ones.\nbool rt_trace_reflection(float3 origin, float3 dir, bool ibl, float max_mip, out float3 shaded)\n{\n shaded = float3(0.0);\n\n RayDesc ray;\n ray.Origin = origin;\n ray.Direction = dir;\n ray.TMin = 0.01;\n ray.TMax = rt_params.max_distance;\n\n RayQuery<RAY_FLAG_FORCE_OPAQUE> rq;\n rq.TraceRayInline(scene_tlas, RAY_FLAG_NONE, 0xFFu, ray);\n while (rq.Proceed()) {}\n\n if (rq.CommittedStatus() != COMMITTED_TRIANGLE_HIT)\n {\n return false;\n }\n\n // The instance\'s position in the TLAS instance array, which every host\n // builds in geometry-table order. NOT CommittedInstanceID: that is the user\n // instance id, which the Metal target reads from a descriptor field only\n // MTLAccelerationStructureUserIDInstanceDescriptor carries, and the engine\n // builds Default descriptors.\n uint inst = rq.CommittedInstanceIndex();\n uint tri = rq.CommittedPrimitiveIndex();\n float2 b = rq.CommittedTriangleBarycentrics();\n float hit_t = rq.CommittedRayT();\n\n RtGeomEntry e = geom[inst];\n bool skin = (e.normal_index & RT_SKINNED_FLAG) != 0u;\n uint nidx = e.normal_index & ~RT_SKINNED_FLAG;\n uint o = e.index_offset + tri * 3u;\n float w0 = 1.0 - b.x - b.y;\n\n float3 nl, tl;\n float2 huv;\n if (skin)\n {\n uint i0 = rt_skinned_index(o);\n uint i1 = rt_skinned_index(o + 1u);\n uint i2 = rt_skinned_index(o + 2u);\n nl = rt_skinned_normal(i0) * w0 + rt_skinned_normal(i1) * b.x + rt_skinned_normal(i2) * b.y;\n tl = rt_skinned_tangent(i0) * w0 + rt_skinned_tangent(i1) * b.x + rt_skinned_tangent(i2) * b.y;\n huv = rt_skinned_uv(i0) * w0 + rt_skinned_uv(i1) * b.x + rt_skinned_uv(i2) * b.y;\n }\n else\n {\n uint i0 = index_at(o) + e.base_vertex;\n uint i1 = index_at(o + 1u) + e.base_vertex;\n uint i2 = index_at(o + 2u) + e.base_vertex;\n nl = rt_vertex_normal(i0) * w0 + rt_vertex_normal(i1) * b.x + rt_vertex_normal(i2) * b.y;\n tl = rt_vertex_tangent(i0) * w0 + rt_vertex_tangent(i1) * b.x + rt_vertex_tangent(i2) * b.y;\n huv = rt_vertex_uv(i0) * w0 + rt_vertex_uv(i1) * b.x + rt_vertex_uv(i2) * b.y;\n }\n\n float3x3 m3 = (float3x3)e.model;\n float3 hit_n = normalize(mul(m3, nl));\n if (dot(hit_n, dir) > 0.0)\n {\n hit_n = -hit_n;\n }\n float3 hit_tan = mul(m3, tl);\n\n float3 tint = float3(e.tint_r, e.tint_g, e.tint_b);\n float3 emissive = float3(e.emissive_r, e.emissive_g, e.emissive_b);\n float shadow = rt_shadow(origin + dir * hit_t, hit_n);\n\n#ifdef RT_TEXTURED\n // Explicit level 0: a reflected ray\'s screen-space UV gradients are\n // unstable (neighbouring pixels hit unrelated triangles), so sampling the\n // base mip avoids gradient-driven mip thrash. Skinned hits take the same\n // path -- their textures live in the same pool and the geometry entry\n // carries the real indices.\n float3 albedo = tint * pool_sample_level0(e.albedo_index, huv);\n // Perturb the geometric normal by the tangent-space normal map. The\n // flat-normal fallback decodes to (0, 0, 1) so N is unchanged when an object\n // has no map; a degenerate tangent (procedural meshes may carry none) skips\n // it and keeps the geometric normal.\n float3 n = hit_n;\n float tlen = length(hit_tan);\n if (tlen > 1e-4)\n {\n float3 nm = decode_normal_map(pool_sample_level0(nidx, huv).xy);\n float3 t = hit_tan / tlen;\n t = normalize(t - n * dot(n, t)); // Gram-Schmidt\n float3 bt = cross(n, t);\n n = normalize(t * nm.x + bt * nm.y + n * nm.z);\n }\n // Colour the self-emission by the emissive map (the bistro string lights),\n // mirroring the main bindless pass. Gated on a non-zero pool index; the flat\n // variant has no pool and keeps the scalar emissive.\n if (e.emissive_map_index != 0u)\n {\n emissive *= pool_sample_level0(e.emissive_map_index, huv);\n }\n shaded = rt_shade_hit(n, albedo, e.roughness, e.metallic, emissive, dir, ibl, max_mip, shadow);\n#else\n shaded = rt_shade_hit(hit_n, tint, e.roughness, e.metallic, emissive, dir, ibl, max_mip, shadow);\n#endif\n return true;\n}\n";Expand description
rt_trace.slang.