From 126231756a0003dd1102034b6f72e47540edcd9f Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Sun, 27 Apr 2025 20:37:42 +0200 Subject: [PATCH] Add slang shader for ray tracing reflection sample --- shaders/slang/_rename.py | 6 + shaders/slang/compileshaders.py | 6 +- .../raytracingreflections.slang | 144 ++++++++++++++++++ 3 files changed, 153 insertions(+), 3 deletions(-) create mode 100644 shaders/slang/raytracingreflections/raytracingreflections.slang diff --git a/shaders/slang/_rename.py b/shaders/slang/_rename.py index fe16d519..5b6e61d1 100644 --- a/shaders/slang/_rename.py +++ b/shaders/slang/_rename.py @@ -13,5 +13,11 @@ def checkRenameFiles(samplename): "raytracingbasic.rmiss.spv": "miss.rmiss.spv", "raytracingbasic.rgen.spv": "raygen.rgen.spv", } + case "raytracingreflections": + mappings = { + "raytracingreflections.rchit.spv": "closesthit.rchit.spv", + "raytracingreflections.rmiss.spv": "miss.rmiss.spv", + "raytracingreflections.rgen.spv": "raygen.rgen.spv", + } for x, y in mappings.items(): move(samplename + "\\" + x, samplename + "\\" + y) diff --git a/shaders/slang/compileshaders.py b/shaders/slang/compileshaders.py index 104ca2ff..9582c1a9 100644 --- a/shaders/slang/compileshaders.py +++ b/shaders/slang/compileshaders.py @@ -70,10 +70,10 @@ if args.sample != None: dir_path = os.path.dirname(os.path.realpath(__file__)) dir_path = dir_path.replace('\\', '/') for root, dirs, files in os.walk(dir_path): + folder_name = os.path.basename(root) + if (compile_single_sample != "" and folder_name != compile_single_sample): + continue for file in files: - folder_name = os.path.basename(root) - if (compile_single_sample != "" and folder_name != compile_single_sample): - continue if file.endswith(".slang"): input_file = os.path.join(root, file) # Slang can store multiple shader stages in a single file, we need to split into separate SPIR-V files for the sample framework diff --git a/shaders/slang/raytracingreflections/raytracingreflections.slang b/shaders/slang/raytracingreflections/raytracingreflections.slang new file mode 100644 index 00000000..2e9260a9 --- /dev/null +++ b/shaders/slang/raytracingreflections/raytracingreflections.slang @@ -0,0 +1,144 @@ +/* Copyright (c) 2025, Sascha Willems + * + * SPDX-License-Identifier: MIT + * + */ + +RaytracingAccelerationStructure accelStruct; +RWTexture2D image; +struct CameraProperties +{ + float4x4 viewInverse; + float4x4 projInverse; + float4 lightPos; + int vertexSize; +}; +ConstantBuffer ubo; +StructuredBuffer vertices; +StructuredBuffer indices; + +// Max. number of recursion is passed via a specialization constant +[SpecializationConstant] const int MAX_RECURSION = 0; + +struct Attributes +{ + float2 bary; +}; + +struct RayPayload +{ + float3 color; + float distance; + float3 normal; + float reflector; +}; + +struct Vertex +{ + float3 pos; + float3 normal; + float2 uv; + float4 color; + float4 _pad0; + float4 _pad1; +}; + +Vertex unpack(uint index) +{ + // Unpack the vertices from the SSBO using the glTF vertex structure + // The multiplier is the size of the vertex divided by four float components (=16 bytes) + const int m = ubo.vertexSize / 16; + + float4 d0 = vertices[m * index + 0]; + float4 d1 = vertices[m * index + 1]; + float4 d2 = vertices[m * index + 2]; + + Vertex v; + v.pos = d0.xyz; + v.normal = float3(d0.w, d1.x, d1.y); + v.color = float4(d2.x, d2.y, d2.z, 1.0); + + return v; +} + +[shader("raygeneration")] +void raygenerationMain() +{ + uint3 LaunchID = DispatchRaysIndex(); + uint3 LaunchSize = DispatchRaysDimensions(); + + const float2 pixelCenter = float2(LaunchID.xy) + float2(0.5, 0.5); + const float2 inUV = pixelCenter / float2(LaunchSize.xy); + float2 d = inUV * 2.0 - 1.0; + float4 target = mul(ubo.projInverse, float4(d.x, d.y, 1, 1)); + + RayDesc rayDesc; + rayDesc.Origin = mul(ubo.viewInverse, float4(0, 0, 0, 1)).xyz; + rayDesc.Direction = mul(ubo.viewInverse, float4(normalize(target.xyz), 0)).xyz; + rayDesc.TMin = 0.001; + rayDesc.TMax = 10000.0; + + float3 color = float3(0.0, 0.0, 0.0); + + for (int i = 0; i < MAX_RECURSION; i++) { + RayPayload rayPayload; + TraceRay(accelStruct, RAY_FLAG_FORCE_OPAQUE, 0xff, 0, 0, 0, rayDesc, rayPayload); + float3 hitColor = rayPayload.color; + + if (rayPayload.distance < 0.0f) { + color += hitColor; + break; + } else if (rayPayload.reflector == 1.0f) { + const float3 hitPos = rayDesc.Origin + rayDesc.Direction * rayPayload.distance; + rayDesc.Origin = hitPos + rayPayload.normal * 0.001f; + rayDesc.Direction = reflect(rayDesc.Direction, rayPayload.normal); + } else { + color += hitColor; + break; + } + } + + image[int2(LaunchID.xy)] = float4(color, 0.0); +} + +[shader("closesthit")] +void closesthitMain(inout RayPayload rayPayload, in Attributes attribs) +{ + uint PrimitiveID = PrimitiveIndex(); + int3 index = int3(indices[3 * PrimitiveID], indices[3 * PrimitiveID + 1], indices[3 * PrimitiveID + 2]); + + Vertex v0 = unpack(index.x); + Vertex v1 = unpack(index.y); + Vertex v2 = unpack(index.z); + + // Interpolate normal + const float3 barycentricCoords = float3(1.0f - attribs.bary.x - attribs.bary.y, attribs.bary.x, attribs.bary.y); + float3 normal = normalize(v0.normal * barycentricCoords.x + v1.normal * barycentricCoords.y + v2.normal * barycentricCoords.z); + + // Basic lighting + float3 lightVector = normalize(ubo.lightPos.xyz); + float dot_product = max(dot(lightVector, normal), 0.6); + rayPayload.color.rgb = v0.color.rgb * dot_product; + rayPayload.distance = RayTCurrent(); + rayPayload.normal = normal; + + // Objects with full white vertex color are treated as reflectors + rayPayload.reflector = ((v0.color.r == 1.0f) && (v0.color.g == 1.0f) && (v0.color.b == 1.0f)) ? 1.0f : 0.0f; +} + +[shader("miss")] +void missMain(inout RayPayload rayPayload) +{ + float3 worldRayDirection = WorldRayDirection(); + + // View-independent background gradient to simulate a basic sky background + const float3 gradientStart = float3(0.5, 0.6, 1.0); + const float3 gradientEnd = float3(1.0, 1.0, 1.0); + float3 unitDir = normalize(worldRayDirection); + float t = 0.5 * (unitDir.y + 1.0); + rayPayload.color = (1.0 - t) * gradientStart + t * gradientEnd; + + rayPayload.distance = -1.0f; + rayPayload.normal = float3(0, 0, 0); + rayPayload.reflector = 0.0f; +} \ No newline at end of file