Skip to content

Commit fd1ccb2

Browse files
authored
cornell: Add reflections to raytracer (#245)
And also fix a couple of misc things.
1 parent e485401 commit fd1ccb2

File tree

6 files changed

+59
-27
lines changed

6 files changed

+59
-27
lines changed

src/sample/cornell/common.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,16 +82,21 @@ export default class Common {
8282
}
8383

8484
/** Updates the uniform buffer data */
85-
update(args: { rotateCamera: boolean }) {
85+
update(params: { rotateCamera: boolean; aspect: number }) {
8686
const viewMatrix = mat4.create();
8787
const mvp = mat4.create();
8888
const invMVP = mat4.create();
8989

90-
const aspect = 1; // canvas.width / canvas.height;
9190
const projectionMatrix = mat4.create();
92-
mat4.perspective(projectionMatrix, (2 * Math.PI) / 8, aspect, 0.5, 100);
91+
mat4.perspective(
92+
projectionMatrix,
93+
(2 * Math.PI) / 8,
94+
params.aspect,
95+
0.5,
96+
100
97+
);
9398

94-
const viewRotation = args.rotateCamera ? this.frame / 1000 : 0;
99+
const viewRotation = params.rotateCamera ? this.frame / 1000 : 0;
95100

96101
mat4.lookAt(
97102
viewMatrix,

src/sample/cornell/common.wgsl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,8 @@ fn rand() -> f32 {
107107
11279 * 2539 * 23,
108108
7919 * 631 * 5 * 3);
109109

110-
rnd = (rnd * C) ^ (rnd.yzx >> vec3(2u));
111-
return f32(rnd.x) / f32(0xffffffff);
110+
rnd = (rnd * C) ^ (rnd.yzx >> vec3(4u));
111+
return f32(rnd.x ^ rnd.y) / f32(0xffffffff);
112112
}
113113

114114
// Returns a random point within a unit sphere centered at (0,0,0).

src/sample/cornell/main.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ const init: SampleInit = async ({ canvas, pageState, gui }) => {
8484

8585
common.update({
8686
rotateCamera: params.rotateCamera,
87+
aspect: canvas.width / canvas.height,
8788
});
8889
radiosity.run(commandEncoder);
8990

src/sample/cornell/rasterizer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ export default class Rasterizer {
112112
fragment: {
113113
module: mod,
114114
entryPoint: 'fs_main',
115-
targets: [{ format: 'rgba16float' }],
115+
targets: [{ format: framebuffer.format }],
116116
},
117117
primitive: {
118118
topology: 'triangle-list',

src/sample/cornell/raytracer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export default class Raytracer {
4949
visibility: GPUShaderStage.COMPUTE,
5050
storageTexture: {
5151
access: 'write-only',
52-
format: 'rgba16float',
52+
format: framebuffer.format,
5353
viewDimension: '2d',
5454
},
5555
},

src/sample/cornell/raytracer.wgsl

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,27 +10,53 @@
1010
override WorkgroupSizeX : u32;
1111
override WorkgroupSizeY : u32;
1212

13+
const NumReflectionRays = 5;
14+
1315
@compute @workgroup_size(WorkgroupSizeX, WorkgroupSizeY)
1416
fn main(@builtin(global_invocation_id) invocation_id : vec3u) {
15-
// Calculate the fragment's NDC coordinates for the intersection of the near
16-
// clip plane and far clip plane
17-
let uv = vec2f(invocation_id.xy) / vec2f(textureDimensions(framebuffer).xy);
18-
let ndcXY = (uv - 0.5) * vec2(2, -2);
19-
20-
// Transform the coordinates back into world space
21-
var near = common_uniforms.inv_mvp * vec4f(ndcXY, 0.0, 1);
22-
var far = common_uniforms.inv_mvp * vec4f(ndcXY, 1, 1);
23-
near /= near.w;
24-
far /= far.w;
25-
26-
// Create a ray that starts at the near clip plane, heading in the fragment's
27-
// z-direction, and raytrace to find the nearest quad that the ray intersects.
28-
let ray = Ray(near.xyz, normalize(far.xyz - near.xyz));
29-
let hit = raytrace(ray);
30-
let quad = quads[hit.quad];
17+
if (all(invocation_id.xy < textureDimensions(framebuffer))) {
18+
init_rand(invocation_id);
19+
20+
// Calculate the fragment's NDC coordinates for the intersection of the near
21+
// clip plane and far clip plane
22+
let uv = vec2f(invocation_id.xy) / vec2f(textureDimensions(framebuffer).xy);
23+
let ndcXY = (uv - 0.5) * vec2(2, -2);
24+
25+
// Transform the coordinates back into world space
26+
var near = common_uniforms.inv_mvp * vec4f(ndcXY, 0.0, 1);
27+
var far = common_uniforms.inv_mvp * vec4f(ndcXY, 1, 1);
28+
near /= near.w;
29+
far /= far.w;
30+
31+
// Create a ray that starts at the near clip plane, heading in the fragment's
32+
// z-direction, and raytrace to find the nearest quad that the ray intersects.
33+
let ray = Ray(near.xyz, normalize(far.xyz - near.xyz));
34+
let hit = raytrace(ray);
35+
36+
let hit_color = sample_hit(hit);
37+
var normal = quads[hit.quad].plane.xyz;
3138

39+
// Fire a few rays off the surface to collect some reflections
40+
let bounce = reflect(ray.dir, normal);
41+
var reflection : vec3f;
42+
for (var i = 0; i < NumReflectionRays; i++) {
43+
let reflection_dir = normalize(bounce + rand_unit_sphere()*0.1);
44+
let reflection_ray = Ray(hit.pos + bounce * 1e-5, reflection_dir);
45+
let reflection_hit = raytrace(reflection_ray);
46+
reflection += sample_hit(reflection_hit);
47+
}
48+
let color = mix(reflection / NumReflectionRays, hit_color, 0.95);
49+
50+
textureStore(framebuffer, invocation_id.xy, vec4(color, 1));
51+
}
52+
}
53+
54+
55+
// Returns the sampled hit quad's lightmap at 'hit.uv', and adds the quad's
56+
// emissive value.
57+
fn sample_hit(hit : HitInfo) -> vec3f {
58+
let quad = quads[hit.quad];
3259
// Sample the quad's lightmap, and add emissive.
33-
let color = textureSampleLevel(lightmap, smpl, hit.uv, hit.quad, 0).rgb +
34-
quad.emissive * quad.color;
35-
textureStore(framebuffer, invocation_id.xy, vec4(color, 1));
60+
return textureSampleLevel(lightmap, smpl, hit.uv, hit.quad, 0).rgb +
61+
quad.emissive * quad.color;
3662
}

0 commit comments

Comments
 (0)