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