1+ struct VSInput {
2+ float3 inPosition;
3+ float3 inColor;
4+ float2 inTexCoord;
5+ float3 inNormal;
6+ };
7+
8+ struct UniformBuffer {
9+ float4x4 model;
10+ float4x4 view;
11+ float4x4 proj;
12+ float3 cameraPos;
13+ };
14+ [[vk::binding(0 ,0 )]]
15+ ConstantBuffer < UniformBuffer> ubo;
16+
17+ // TASK05: Acceleration structure binding
18+ [[vk::binding(1 ,0 )]]
19+ RaytracingAccelerationStructure accelerationStructure;
20+
21+ [[vk::binding(2 ,0 )]]
22+ StructuredBuffer < uint > indexBuffer;
23+
24+ [[vk::binding(3 ,0 )]]
25+ StructuredBuffer < float2 > uvBuffer;
26+
27+ // TASK09: Instance look-up table
28+ struct InstanceLUT {
29+ uint materialID;
30+ uint indexBufferOffset;
31+ };
32+ [[vk::binding(4 ,0 )]]
33+ StructuredBuffer < InstanceLUT> instanceLUTBuffer;
34+
35+ struct VSOutput
36+ {
37+ float4 pos : SV_Position;
38+ float3 fragColor;
39+ float2 fragTexCoord;
40+ float3 fragNormal;
41+ float3 worldPos;
42+ };
43+
44+ [shader(" vertex" )]
45+ VSOutput vertMain(VSInput input) {
46+ VSOutput output;
47+ output .pos = mul(ubo .proj , mul(ubo .view , mul(ubo .model , float4(input .inPosition , 1 . 0 ))));
48+ output .fragColor = input .inColor ;
49+ output .fragTexCoord = input .inTexCoord ;
50+ output .fragNormal = input .inNormal ;
51+ output .worldPos = mul(ubo .model , float4(input .inPosition , 1 . 0 )).xyz ;
52+ return output;
53+ }
54+
55+ // TASK09: Bindless resources
56+ [[vk::binding(0 ,1 )]]
57+ SamplerState textureSampler;
58+
59+ [[vk::binding(1 ,1 )]]
60+ Texture2D < float4 > textures[] ;
61+
62+ // TASK11
63+ struct PushConstant {
64+ uint materialIndex;
65+ uint reflective;
66+ };
67+ [push_constant]
68+ PushConstant pc;
69+
70+ static const float3 lightDir = float3 (- 6 . 0 , 0 . 0 , 6 . 0 );
71+
72+ // Small epsilon to avoid self-intersection
73+ static const float EPSILON = 0 . 01 ;
74+
75+ float2 intersection_uv(uint instanceID, uint primIndex, float2 barycentrics) {
76+ uint indexOffset = instanceLUTBuffer [NonUniformResourceIndex(instanceID)].indexBufferOffset ;
77+
78+ uint i0 = indexBuffer [indexOffset + (primIndex * 3 + 0 )];
79+ uint i1 = indexBuffer [indexOffset + (primIndex * 3 + 1 )];
80+ uint i2 = indexBuffer [indexOffset + (primIndex * 3 + 2 )];
81+
82+ float2 uv0 = uvBuffer [i0];
83+ float2 uv1 = uvBuffer [i1];
84+ float2 uv2 = uvBuffer [i2];
85+
86+ float w0 = 1 . 0 - barycentrics .x - barycentrics .y ;
87+ float w1 = barycentrics .x ;
88+ float w2 = barycentrics .y ;
89+
90+ return w0 * uv0 + w1 * uv1 + w2 * uv2;
91+ }
92+
93+ void apply_reflection(float3 P, float3 N, inout float4 baseColor) {
94+ // Build the reflections ray
95+ float3 V = normalize(ubo .cameraPos - P);
96+ float3 R = reflect(- V, N);
97+
98+ RayDesc reflectionRayDesc;
99+ reflectionRayDesc .Origin = P;
100+ reflectionRayDesc .Direction = R;
101+ reflectionRayDesc .TMin = EPSILON;
102+ reflectionRayDesc .TMax = 1 e 4 ;
103+
104+ // Initialize a ray query for reflections
105+ RayQuery< RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES> rq;
106+ let rayFlags = RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES;
107+
108+ rq .TraceRayInline (accelerationStructure, rayFlags, 0x FF , reflectionRayDesc);
109+
110+ while (rq .Proceed ())
111+ {
112+ uint instanceID = rq .CandidateRayInstanceCustomIndex ();
113+ uint primIndex = rq .CandidatePrimitiveIndex ();
114+
115+ float2 uv = intersection_uv(instanceID, primIndex, rq .CandidateTriangleBarycentrics ());
116+
117+ uint materialID = instanceLUTBuffer [NonUniformResourceIndex(instanceID)].materialID ;
118+ float4 intersectionColor = textures [NonUniformResourceIndex(materialID)].SampleLevel (textureSampler, uv, 0 );
119+
120+ if (intersectionColor .a < 0 . 5 ) {
121+ // If the triangle is transparent, we continue to trace
122+ // to find the next opaque triangle.
123+ } else {
124+ // If we hit an opaque triangle, we stop tracing.
125+ rq .CommitNonOpaqueTriangleHit ();
126+ }
127+ }
128+
129+ bool hit = (rq .CommittedStatus () == COMMITTED_TRIANGLE_HIT);
130+
131+ if (hit)
132+ {
133+ uint instanceID = rq .CommittedRayInstanceCustomIndex ();
134+ uint primIndex = rq .CommittedPrimitiveIndex ();
135+
136+ float2 uv = intersection_uv(instanceID, primIndex, rq .CommittedTriangleBarycentrics ());
137+
138+ uint materialID = instanceLUTBuffer [NonUniformResourceIndex(instanceID)].materialID ;
139+ float4 intersectionColor = textures [NonUniformResourceIndex(materialID)].SampleLevel (textureSampler, uv, 0 );
140+
141+ baseColor .rgb = lerp(baseColor .rgb , intersectionColor .rgb , 0 . 7 );
142+ }
143+ }
144+
145+ // TASK05: Implement ray query shadows
146+ bool in_shadow(float3 P)
147+ {
148+ // Build the shadow ray from the world position toward the light
149+ RayDesc shadowRayDesc;
150+ shadowRayDesc .Origin = P;
151+ shadowRayDesc .Direction = normalize(lightDir);
152+ shadowRayDesc .TMin = EPSILON;
153+ shadowRayDesc .TMax = 1 e 4 ;
154+
155+ // Initialize a ray query for shadows
156+ RayQuery< RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES |
157+ RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH> sq;
158+ let rayFlags = RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES |
159+ RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH;
160+
161+ sq .TraceRayInline (accelerationStructure, rayFlags, 0x FF , shadowRayDesc);
162+
163+ while (sq .Proceed ())
164+ {
165+ uint instanceID = sq .CandidateRayInstanceCustomIndex ();
166+ uint primIndex = sq .CandidatePrimitiveIndex ();
167+
168+ float2 uv = intersection_uv(instanceID, primIndex, sq .CandidateTriangleBarycentrics ());
169+
170+ uint materialID = instanceLUTBuffer [NonUniformResourceIndex(instanceID)].materialID ;
171+ float4 intersectionColor = textures [NonUniformResourceIndex(materialID)].SampleLevel (textureSampler, uv, 0 );
172+
173+ if (intersectionColor .a < 0 . 5 ) {
174+ // If the triangle is transparent, we continue to trace
175+ // to find the next opaque triangle.
176+ } else {
177+ // If we hit an opaque triangle, we stop tracing.
178+ sq .CommitNonOpaqueTriangleHit ();
179+ }
180+ }
181+
182+ // If the shadow ray intersects an opaque triangle, we consider the pixel in shadow
183+ bool hit = (sq .CommittedStatus () == COMMITTED_TRIANGLE_HIT);
184+
185+ return hit;
186+ }
187+
188+ [shader(" fragment" )]
189+ float4 fragMain(VSOutput vertIn) : SV_TARGET {
190+ float4 baseColor = textures [pc .materialIndex ].Sample (textureSampler, vertIn .fragTexCoord );
191+
192+ // Alpha test
193+ if (baseColor .a < 0 . 5 ) discard ;
194+
195+ float3 P = vertIn .worldPos ;
196+ float3 N = vertIn .fragNormal ;
197+
198+ if (pc .reflective > 0 ) {
199+ apply_reflection(P, N, baseColor);
200+ }
201+
202+ bool inShadow = in_shadow(P);
203+
204+ // Darken if in shadow
205+ if (inShadow) {
206+ baseColor .rgb *= 0 . 2 ;
207+ }
208+
209+ return baseColor;
210+ }
0 commit comments