|
15 | 15 | // we are going to use raw Vulkan here to initialize VK_KHR_ray_tracing_position_fetch |
16 | 16 | #include <lvk/vulkan/VulkanUtils.h> |
17 | 17 |
|
| 18 | +const char* codeSlang = R"( |
| 19 | +[[vk::binding(2, 0)]] RWTexture2D<float4> kTextures2DInOut[]; |
| 20 | +
|
| 21 | +struct Camera { |
| 22 | + float4x4 viewInverse; |
| 23 | + float4x4 projInverse; |
| 24 | +}; |
| 25 | +
|
| 26 | +struct PushConstants { |
| 27 | + Camera* cam; |
| 28 | + float2 dim; |
| 29 | + uint outTexture; |
| 30 | + uint texBackground; |
| 31 | + uint texObject; |
| 32 | + uint tlas; |
| 33 | + float time; |
| 34 | +}; |
| 35 | +[[vk::push_constant]] PushConstants pc; |
| 36 | +
|
| 37 | +struct RayPayload { |
| 38 | + float3 color; |
| 39 | +}; |
| 40 | +
|
| 41 | +[shader("raygeneration")] |
| 42 | +void rayGenMain() { |
| 43 | + uint3 launchID = DispatchRaysIndex(); |
| 44 | + uint3 launchSize = DispatchRaysDimensions(); |
| 45 | +
|
| 46 | + float2 pixelCenter = float2(launchID.xy) + float2(0.5, 0.5); |
| 47 | + float2 d = 2.0 * (pixelCenter / float2(launchSize.xy)) - 1.0; |
| 48 | +
|
| 49 | + float4 origin = mul(float4(0, 0, 0, 1), pc.cam->viewInverse); |
| 50 | + float4 target = mul(float4(d, 1, 1), pc.cam->projInverse); |
| 51 | + float4 direction = mul(float4(normalize(target.xyz), 0), pc.cam->viewInverse); |
| 52 | +
|
| 53 | + RayDesc ray; |
| 54 | + ray.Origin = origin.xyz; |
| 55 | + ray.Direction = direction.xyz; |
| 56 | + ray.TMin = 0.1; |
| 57 | + ray.TMax = 500.0; |
| 58 | +
|
| 59 | + RayPayload payload = { float3(0.0, 0.0, 0.0) }; |
| 60 | +
|
| 61 | + TraceRay( |
| 62 | + kTLAS[NonUniformResourceIndex(pc.tlas)], |
| 63 | + RAY_FLAG_FORCE_OPAQUE, |
| 64 | + 0xff, |
| 65 | + 0, |
| 66 | + 0, |
| 67 | + 0, |
| 68 | + ray, |
| 69 | + payload |
| 70 | + ); |
| 71 | +
|
| 72 | + kTextures2DInOut[NonUniformResourceIndex(pc.outTexture)][launchID.xy] = float4(payload.color, 1.0); |
| 73 | +} |
| 74 | +
|
| 75 | +[shader("miss")] |
| 76 | +void missMain(inout RayPayload payload) { |
| 77 | + float2 uv = float2(DispatchRaysIndex().xy) / pc.dim; |
| 78 | + payload.color = textureBindless2D(pc.texBackground, 0, uv).rgb; |
| 79 | +} |
| 80 | +
|
| 81 | +float4 triplanar(uint tex, float3 worldPos, float3 normal) { |
| 82 | + // generate weights, show texture on both sides of the object (positive and negative) |
| 83 | + float3 weights = abs(normal); |
| 84 | + // make the transition sharper |
| 85 | + weights = pow(weights, float3(8.0, 8.0, 8.0)); |
| 86 | + // make sure the sum of all components is 1 |
| 87 | + weights = weights / (weights.x + weights.y + weights.z); |
| 88 | +
|
| 89 | + // sample the texture for 3 different projections |
| 90 | + float4 cXY = textureBindless2D(tex, 0, worldPos.xy); |
| 91 | + float4 cZY = textureBindless2D(tex, 0, worldPos.zy); |
| 92 | + float4 cXZ = textureBindless2D(tex, 0, worldPos.xz); |
| 93 | +
|
| 94 | + // combine the projected colors |
| 95 | + return cXY * weights.z + cZY * weights.x + cXZ * weights.y; |
| 96 | +} |
| 97 | +
|
| 98 | +[shader("closesthit")] |
| 99 | +void closestHitMain(inout RayPayload payload, in BuiltInTriangleIntersectionAttributes attribs) { |
| 100 | + float3 pos0 = HitTriangleVertexPosition(0); |
| 101 | + float3 pos1 = HitTriangleVertexPosition(1); |
| 102 | + float3 pos2 = HitTriangleVertexPosition(2); |
| 103 | +
|
| 104 | + float3 baryCoords = float3(1.0 - attribs.barycentrics.x - attribs.barycentrics.y, |
| 105 | + attribs.barycentrics.x, |
| 106 | + attribs.barycentrics.y); |
| 107 | + float3 pos = pos0 * baryCoords.x + pos1 * baryCoords.y + pos2 * baryCoords.z; |
| 108 | +
|
| 109 | + // triplanar mapping in object-space; for our icosahedron, object-space position and normal vectors are the same |
| 110 | + payload.color = triplanar(pc.texObject, pos, normalize(pos)).rgb; |
| 111 | +} |
| 112 | +)"; |
| 113 | + |
18 | 114 | const char* codeRayGen = R"( |
19 | 115 | #version 460 |
20 | 116 | #extension GL_EXT_ray_tracing : require |
@@ -337,9 +433,15 @@ VULKAN_APP_MAIN { |
337 | 433 | res.texBackground = createTextureFromFile(app, "src/bistro/BuildingTextures/wood_polished_01_diff.png"); |
338 | 434 | res.texObject = createTextureFromFile(app, "src/bistro/BuildingTextures/Cobble_02B_Diff.png"); |
339 | 435 |
|
| 436 | +#if defined(LVK_DEMO_WITH_SLANG) |
| 437 | + res.raygen_ = ctx_->createShaderModule({codeSlang, lvk::Stage_RayGen, "Shader Module: main (raygen)"}); |
| 438 | + res.miss_ = ctx_->createShaderModule({codeSlang, lvk::Stage_Miss, "Shader Module: main (miss)"}); |
| 439 | + res.hit_ = ctx_->createShaderModule({codeSlang, lvk::Stage_ClosestHit, "Shader Module: main (closesthit)"}); |
| 440 | +#else |
340 | 441 | res.raygen_ = ctx_->createShaderModule({codeRayGen, lvk::Stage_RayGen, "Shader Module: main (raygen)"}); |
341 | 442 | res.miss_ = ctx_->createShaderModule({codeMiss, lvk::Stage_Miss, "Shader Module: main (miss)"}); |
342 | 443 | res.hit_ = ctx_->createShaderModule({codeClosestHit, lvk::Stage_ClosestHit, "Shader Module: main (closesthit)"}); |
| 444 | +#endif // defined(LVK_DEMO_WITH_SLANG) |
343 | 445 |
|
344 | 446 | res.pipeline = ctx_->createRayTracingPipeline(lvk::RayTracingPipelineDesc{ |
345 | 447 | .smRayGen = {lvk::ShaderModuleHandle(res.raygen_)}, |
|
0 commit comments