Skip to content

Commit 70624a7

Browse files
committed
Merge branch 'nee'
2 parents d5905ad + 6be090e commit 70624a7

File tree

2 files changed

+110
-14
lines changed

2 files changed

+110
-14
lines changed

src/pt/main.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ int main(int argc, char** argv)
114114
float skyTurbidity = 1.0f;
115115
std::array<float, 3> skyAlbedo = {1.0f, 1.0f, 1.0f};
116116
// tonemapping
117-
int exposureStops = 4;
117+
int exposureStops = 3;
118118
int tonemapFn = 1;
119119
// timestep
120120
auto lastTime = std::chrono::steady_clock::now();
@@ -182,11 +182,11 @@ int main(int argc, char** argv)
182182

183183
ImGui::Text("num bounces:");
184184
ImGui::SameLine();
185+
ImGui::RadioButton("2", &numBounces, 2);
186+
ImGui::SameLine();
185187
ImGui::RadioButton("4", &numBounces, 4);
186188
ImGui::SameLine();
187189
ImGui::RadioButton("8", &numBounces, 8);
188-
ImGui::SameLine();
189-
ImGui::RadioButton("16", &numBounces, 16);
190190

191191
ImGui::SliderFloat("sun zenith", &sunZenithDegrees, 0.0f, 90.0f, "%.2f");
192192
ImGui::SliderFloat("sun azimuth", &sunAzimuthDegrees, 0.0f, 360.0f, "%.2f");

src/pt/raytracer.wgsl

Lines changed: 107 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,12 @@ const CHANNEL_R = 0u;
9191
const CHANNEL_G = 1u;
9292
const CHANNEL_B = 2u;
9393

94+
const DEGREES_TO_RADIANS = PI / 180f;
95+
const TERRESTRIAL_SOLAR_RADIUS = 0.255f * DEGREES_TO_RADIANS;
96+
97+
const SOLAR_COS_THETA_MAX = cos(TERRESTRIAL_SOLAR_RADIUS);
98+
const SOLAR_INV_PDF = 2f * PI * (1f - SOLAR_COS_THETA_MAX);
99+
94100
struct RenderParams {
95101
frameData: FrameData,
96102
camera: Camera,
@@ -186,12 +192,26 @@ fn rayColor(primaryRay: Ray, rngState: ptr<function, u32>) -> vec3f {
186192
var radiance = vec3(0f);
187193
var throughput = vec3(1f);
188194

195+
var bounce = 1u;
189196
let numBounces = renderParams.samplingState.numBounces;
190-
for (var bounces = 0u; bounces < numBounces; bounces += 1u) {
191-
var intersection: Intersection;
192-
if rayIntersectBvh(ray, T_MAX, &intersection) {
193-
let p = intersection.p;
194-
let scatter = evalImplicitLambertian(intersection, rngState);
197+
loop {
198+
var hit: Intersection;
199+
if rayIntersectBvh(ray, T_MAX, &hit) {
200+
let albedo = evalTexture(hit.textureDescriptorIdx, hit.uv);
201+
let p = hit.p;
202+
203+
let lightDirection = sampleSolarDiskDirection(SOLAR_COS_THETA_MAX, skyState.sunDirection, rngState);
204+
let lightIntensity = vec3f(1000000f, 1000000f, 1000000f); // TODO: replace with more plausible solar intensity
205+
let brdf = albedo * FRAC_1_PI;
206+
let reflectance = brdf * dot(hit.n, lightDirection);
207+
let lightVisibility = shadowRay(Ray(p, lightDirection), T_MAX);
208+
radiance += throughput * lightIntensity * reflectance * lightVisibility * SOLAR_INV_PDF;
209+
210+
if bounce == numBounces {
211+
break;
212+
}
213+
214+
let scatter = evalImplicitLambertian(hit.n, albedo, rngState);
195215
ray = Ray(p, scatter.wi);
196216
throughput *= scatter.throughput;
197217
} else {
@@ -211,6 +231,8 @@ fn rayColor(primaryRay: Ray, rngState: ptr<function, u32>) -> vec3f {
211231

212232
break;
213233
}
234+
235+
bounce += 1u;
214236
}
215237

216238
return radiance;
@@ -276,18 +298,27 @@ fn acesFilmic(x: vec3f) -> vec3f {
276298
return saturate((x * (a * x + b)) / (x * (c * x + d) + e));
277299
}
278300

279-
fn evalImplicitLambertian(hit: Intersection, rngState: ptr<function, u32>) -> Scatter {
301+
@must_use
302+
fn sampleSolarDiskDirection(cosThetaMax: f32, direction: vec3f, state: ptr<function, u32>) -> vec3f {
303+
let v = rngNextInCone(state, cosThetaMax);
304+
let onb = pixarOnb(direction);
305+
return onb * v;
306+
}
307+
308+
@must_use
309+
fn evalImplicitLambertian(n: vec3f, albedo: vec3f, rngState: ptr<function, u32>) -> Scatter {
280310
let v = rngNextInCosineWeightedHemisphere(rngState);
281-
let onb = pixarOnb(hit.n);
311+
let onb = pixarOnb(n);
282312
let wi = onb * v;
283313

284-
let textureDesc = textureDescriptors[hit.textureDescriptorIdx];
285-
let uv = hit.uv;
286-
let albedo = textureLookup(textureDesc, uv);
287-
288314
return Scatter(wi, albedo);
289315
}
290316

317+
fn evalTexture(textureDescriptorIdx: u32, uv: vec2f) -> vec3f {
318+
let textureDesc = textureDescriptors[textureDescriptorIdx];
319+
return textureLookup(textureDesc, uv);
320+
}
321+
291322
fn pixarOnb(n: vec3f) -> mat3x3f {
292323
// https://www.jcgt.org/published/0006/01/01/paper-lowres.pdf
293324
let s = select(-1f, 1f, n.z >= 0f);
@@ -299,6 +330,55 @@ fn pixarOnb(n: vec3f) -> mat3x3f {
299330
return mat3x3(u, v, n);
300331
}
301332

333+
// Returns 1.0 if no forward intersections, 0.0 otherwise.
334+
@must_use
335+
fn shadowRay(ray: Ray, rayTMax: f32) -> f32 {
336+
let intersector = rayAabbIntersector(ray);
337+
var toVisitOffset = 0u;
338+
var currentNodeIdx = 0u;
339+
var nodesToVisit: array<u32, 32u>;
340+
341+
loop {
342+
let node: BvhNode = bvhNodes[currentNodeIdx];
343+
344+
if rayIntersectAabb(intersector, node.aabb, rayTMax) {
345+
if node.triangleCount > 0u {
346+
for (var idx = 0u; idx < node.triangleCount; idx = idx + 1u) {
347+
let triangle: Positions = positionAttributes[node.trianglesOffset + idx];
348+
// TODO: trihit not actually used. A different code path could be used?
349+
var trihit: TriangleHit;
350+
if rayIntersectTriangle(ray, triangle, rayTMax, &trihit) {
351+
return 0f;
352+
}
353+
}
354+
if toVisitOffset == 0u {
355+
break;
356+
}
357+
toVisitOffset -= 1u;
358+
currentNodeIdx = nodesToVisit[toVisitOffset];
359+
} else {
360+
// Is intersector.invDir[node.splitAxis] < 0f? If so, visit second child first.
361+
if intersector.dirNeg[node.splitAxis] == 1u {
362+
nodesToVisit[toVisitOffset] = currentNodeIdx + 1u;
363+
currentNodeIdx = node.secondChildOffset;
364+
} else {
365+
nodesToVisit[toVisitOffset] = node.secondChildOffset;
366+
currentNodeIdx = currentNodeIdx + 1u;
367+
}
368+
toVisitOffset += 1u;
369+
}
370+
} else {
371+
if toVisitOffset == 0u {
372+
break;
373+
}
374+
toVisitOffset -= 1u;
375+
currentNodeIdx = nodesToVisit[toVisitOffset];
376+
}
377+
}
378+
379+
return 1f;
380+
}
381+
302382
fn rayIntersectBvh(ray: Ray, rayTMax: f32, hit: ptr<function, Intersection>) -> bool {
303383
let intersector = rayAabbIntersector(ray);
304384
var toVisitOffset = 0u;
@@ -489,6 +569,22 @@ fn textureLookup(desc: TextureDescriptor, uv: vec2f) -> vec3f {
489569
return vec3f(f32(rgba & 0xffu), f32((rgba >> 8u) & 0xffu), f32((rgba >> 16u) & 0xffu)) / 255f;
490570
}
491571

572+
@must_use
573+
fn rngNextInCone(state: ptr<function, u32>, cosThetaMax: f32) -> vec3f {
574+
let u1 = rngNextFloat(state);
575+
let u2 = rngNextFloat(state);
576+
577+
let cosTheta = 1f - u1 * (1f - cosThetaMax);
578+
let sinTheta = sqrt(1f - cosTheta * cosTheta);
579+
let phi = 2f * PI * u2;
580+
581+
let x = cos(phi) * sinTheta;
582+
let y = sin(phi) * sinTheta;
583+
let z = cosTheta;
584+
585+
return vec3(x, y, z);
586+
}
587+
492588
@must_use
493589
fn rngNextInCosineWeightedHemisphere(state: ptr<function, u32>) -> vec3f {
494590
let u1 = rngNextFloat(state);

0 commit comments

Comments
 (0)