Skip to content

Commit bc6d7f7

Browse files
New structure and re-build methodology
1 parent 11ecec3 commit bc6d7f7

24 files changed

+1787
-306
lines changed

attachments/38_ray_tracing.cpp

Lines changed: 293 additions & 184 deletions
Large diffs are not rendered by default.

attachments/38_ray_tracing.slang

Lines changed: 10 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ struct UniformBuffer {
1414
[[vk::binding(0,0)]]
1515
ConstantBuffer<UniformBuffer> ubo;
1616

17+
// TASK04: Acceleration structure binding
1718
[[vk::binding(1,0)]]
1819
RaytracingAccelerationStructure accelerationStructure;
1920

@@ -23,6 +24,7 @@ StructuredBuffer<uint> indexBuffer;
2324
[[vk::binding(3,0)]]
2425
StructuredBuffer<float2> uvBuffer;
2526

27+
// TASK09: Instance look-up table
2628
struct InstanceLUT {
2729
uint materialID;
2830
uint indexBufferOffset;
@@ -50,6 +52,7 @@ VSOutput vertMain(VSInput input) {
5052
return output;
5153
}
5254

55+
// TASK09: Bindless resources
5356
[[vk::binding(0,1)]]
5457
SamplerState textureSampler;
5558

@@ -58,7 +61,6 @@ Texture2D<float4> textures[];
5861

5962
struct PushConstant {
6063
uint materialIndex;
61-
uint reflective;
6264
};
6365
[push_constant]
6466
PushConstant pc;
@@ -69,139 +71,25 @@ static const float3 lightDir = float3(-6.0, 0.0, 6.0);
6971
static const float EPSILON = 0.01;
7072

7173
float2 intersection_uv(uint instanceID, uint primIndex, float2 barycentrics) {
72-
uint indexOffset = instanceLUTBuffer[instanceID].indexBufferOffset;
73-
74-
uint i0 = indexBuffer[indexOffset + (primIndex * 3 + 0)];
75-
uint i1 = indexBuffer[indexOffset + (primIndex * 3 + 1)];
76-
uint i2 = indexBuffer[indexOffset + (primIndex * 3 + 2)];
77-
78-
float2 uv0 = uvBuffer[i0];
79-
float2 uv1 = uvBuffer[i1];
80-
float2 uv2 = uvBuffer[i2];
81-
82-
float w0 = 1.0 - barycentrics.x - barycentrics.y;
83-
float w1 = barycentrics.x;
84-
float w2 = barycentrics.y;
74+
// TASK10
75+
return float2(0.0, 0.0);
76+
}
8577

86-
return w0 * uv0 + w1 * uv1 + w2 * uv2;
78+
void apply_reflection(float3 P, float3 N, inout float4 baseColor) {
79+
// TASK11
8780
}
8881

82+
// TASK05: Implement ray query shadows
8983
bool in_shadow(float3 P)
9084
{
91-
// Build the shadow ray from the world position toward the light
92-
RayDesc shadowRayDesc;
93-
shadowRayDesc.Origin = P;
94-
shadowRayDesc.Direction = normalize(lightDir);
95-
shadowRayDesc.TMin = EPSILON;
96-
shadowRayDesc.TMax = 1e4;
97-
98-
// Initialize a ray-query for shadows
99-
RayQuery<RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES |
100-
RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH> sq;
101-
let rayFlags = RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES |
102-
RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH;
103-
104-
sq.TraceRayInline(accelerationStructure, rayFlags, 0xFF, shadowRayDesc);
105-
106-
while (sq.Proceed())
107-
{
108-
uint instanceID = sq.CandidateInstanceID();
109-
uint primIndex = sq.CandidatePrimitiveIndex();
110-
111-
float2 uv = intersection_uv(instanceID, primIndex, sq.CandidateTriangleBarycentrics());
112-
113-
uint materialID = instanceLUTBuffer[instanceID].materialID;
114-
float4 intersection_color = textures[materialID].Sample(textureSampler, uv);
115-
116-
if (intersection_color.a < 0.5) {
117-
// If the triangle is transparent, we continue to trace
118-
// to find the next opaque triangle.
119-
} else {
120-
// If we hit an opaque triangle, we stop tracing.
121-
sq.CommitNonOpaqueTriangleHit();
122-
}
123-
124-
}
125-
126-
// If the shadow ray intersects an opaque triangle, we consider the pixel in shadow
127-
bool hit = (sq.CommittedStatus() == COMMITTED_TRIANGLE_HIT);
85+
bool hit = false;
12886

12987
return hit;
13088
}
13189

132-
void apply_reflection(float3 P, float3 N, inout float4 baseColor) {
133-
// Build the reflections ray
134-
float3 V = normalize(ubo.cameraPos - P);
135-
float3 R = reflect(-V, N);
136-
137-
RayDesc reflectionRayDesc;
138-
reflectionRayDesc.Origin = P;
139-
reflectionRayDesc.Direction = R;
140-
reflectionRayDesc.TMin = EPSILON;
141-
reflectionRayDesc.TMax = 1e4;
142-
143-
// Initialize a ray-query for reflections
144-
RayQuery<RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES> rq;
145-
let rayFlags = RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES;
146-
147-
rq.TraceRayInline(accelerationStructure, rayFlags, 0xFF, reflectionRayDesc);
148-
149-
while (rq.Proceed())
150-
{
151-
uint instanceID = rq.CandidateInstanceID();
152-
uint primIndex = rq.CandidatePrimitiveIndex();
153-
154-
float2 uv = intersection_uv(instanceID, primIndex, rq.CandidateTriangleBarycentrics());
155-
156-
uint materialID = instanceLUTBuffer[instanceID].materialID;
157-
float4 intersection_color = textures[materialID].Sample(textureSampler, uv);
158-
159-
if (intersection_color.a < 0.5) {
160-
// If the triangle is transparent, we continue to trace
161-
// to find the next opaque triangle.
162-
} else {
163-
// If we hit an opaque triangle, we stop tracing.
164-
rq.CommitNonOpaqueTriangleHit();
165-
}
166-
167-
}
168-
169-
bool hit = (rq.CommittedStatus() == COMMITTED_TRIANGLE_HIT);
170-
171-
if (hit)
172-
{
173-
uint instanceID = rq.CommittedInstanceID();
174-
uint primIndex = rq.CommittedPrimitiveIndex();
175-
176-
float2 uv = intersection_uv(instanceID, primIndex, rq.CommittedTriangleBarycentrics());
177-
178-
uint materialID = instanceLUTBuffer[instanceID].materialID;
179-
float4 intersectionColor = textures[materialID].Sample(textureSampler, uv);
180-
181-
baseColor.rgb = lerp(baseColor.rgb, intersectionColor.rgb, 0.7);
182-
}
183-
}
184-
18590
[shader("fragment")]
18691
float4 fragMain(VSOutput vertIn) : SV_TARGET {
18792
float4 baseColor = textures[pc.materialIndex].Sample(textureSampler, vertIn.fragTexCoord);
18893

189-
// Alpha test
190-
if (baseColor.a < 0.5) discard;
191-
192-
float3 P = vertIn.worldPos;
193-
float3 N = vertIn.fragNormal;
194-
195-
if (pc.reflective > 0) {
196-
apply_reflection(P, N, baseColor);
197-
}
198-
199-
bool inShadow = in_shadow(P);
200-
201-
// Darken if in shadow
202-
if (inShadow) {
203-
baseColor.rgb *= 0.2;
204-
}
205-
20694
return baseColor;
20795
}
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
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 = 1e4;
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, 0xFF, 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 = 1e4;
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, 0xFF, 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

Comments
 (0)