Skip to content

Commit afb6276

Browse files
committed
refraction? / glassy stuff
1 parent 0337f3b commit afb6276

File tree

4 files changed

+124
-39
lines changed

4 files changed

+124
-39
lines changed

assets/compute.wgsl

Lines changed: 62 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,15 @@ struct Params {
1212
accumulated_frames: u32,
1313
width: u32,
1414
height: u32,
15-
triangle_mesh_count: u32,
16-
sphere_count: u32,
1715
};
1816

1917
struct Material {
2018
diffuse_color: vec3f,
2119
smoothness: f32,
2220
emission_color: vec3f,
2321
emission_strength: f32,
22+
refractive_index: f32,
23+
flag: u32,
2424
};
2525

2626
struct Sphere {
@@ -51,6 +51,7 @@ struct RayHit {
5151
distance: f32,
5252
position: vec3f,
5353
normal: vec3f,
54+
is_backface: bool,
5455
material: Material,
5556
hit: bool,
5657
};
@@ -136,9 +137,17 @@ fn trace_single(ray: ptr<function, Ray>, state: ptr<function, u32>) -> vec3f {
136137
if hit.hit {
137138
(*ray).origin = hit.position;
138139
let diffuse = normalize(hit.normal + random_direction(state));
139-
let specular = reflect((*ray).direction, hit.normal);
140-
141-
(*ray).direction = mix(diffuse, specular, hit.material.smoothness);
140+
let specular = reflect((*ray).direction, hit.normal, 0.0);
141+
142+
if hit.material.flag == 1u {
143+
if hit.is_backface {
144+
let refracted = refract((*ray).direction, hit.normal, hit.material.refractive_index);
145+
let kr = pow(1.0 - max(dot(-(*ray).direction, hit.normal), 0.0), 5.0);
146+
(*ray).direction = normalize(mix(refracted, specular, kr));
147+
}
148+
} else {
149+
(*ray).direction = mix(diffuse, specular, hit.material.smoothness);
150+
}
142151

143152
let emitted = hit.material.emission_color * hit.material.emission_strength;
144153
color = color * hit.material.diffuse_color;
@@ -152,28 +161,46 @@ fn trace_single(ray: ptr<function, Ray>, state: ptr<function, u32>) -> vec3f {
152161
return light;
153162
}
154163

155-
fn reflect(I: vec3f, N: vec3f) -> vec3f {
164+
fn reflect(I: vec3f, N: vec3f, index: f32) -> vec3f {
156165
return I - 2.0 * dot(N, I) * N;
157166
}
158167

168+
fn refract(I: vec3f, N: vec3f, index: f32) -> vec3f {
169+
var cosi = clamp(dot(I, N), -1.0, 1.0);
170+
let etai = 1.0;
171+
let etat = index;
172+
var n = N;
173+
var eta = etai / etat;
174+
if cosi < 0.0 {
175+
cosi = -cosi;
176+
} else {
177+
n = -N;
178+
}
179+
let k = 1.0 - eta * eta * (1.0 - cosi * cosi);
180+
if k < 0.0 {
181+
return vec3f(0.0, 0.0, 0.0);
182+
} else {
183+
return eta * I + (eta * cosi - sqrt(k)) * n;
184+
}
185+
}
186+
159187
fn calculate_collision(ray: Ray) -> RayHit {
160188
var closest_hit: RayHit;
161-
for (var i: u32 = 0u; i < params.sphere_count; i = i + 1u) {
189+
for (var i: u32 = 0u; i < arrayLength(&spheres); i = i + 1u) {
162190
let hit = sphere_intersect(ray, spheres[i]);
163191
if hit.hit && (!closest_hit.hit || hit.distance < closest_hit.distance) {
164192
closest_hit = hit;
165193
}
166194
}
167-
for (var i: u32 = 0u; i < params.triangle_mesh_count; i = i + 1u) {
195+
for (var i: u32 = 0u; i < arrayLength(&triangle_meshes); i = i + 1u) {
168196
let tri_mesh = triangle_meshes[i];
169-
if !aabb_intersect(ray, tri_mesh.aabb) {
170-
continue;
171-
}
172-
for (var j: u32 = 0u; j < tri_mesh.vertex_count / 3u; j = j + 1u) {
173-
let hit = triangle_intersect(ray, tri_mesh.start_index + j * 3u);
174-
if hit.hit && (!closest_hit.hit || hit.distance < closest_hit.distance) {
175-
closest_hit = hit;
176-
closest_hit.material = tri_mesh.material;
197+
if aabb_intersect(ray, tri_mesh.aabb) {
198+
for (var j: u32 = 0u; j < tri_mesh.vertex_count / 3u; j = j + 1u) {
199+
let hit = triangle_intersect(ray, tri_mesh.start_index + j * 3u, tri_mesh.material.flag == 0u);
200+
if hit.hit && (!closest_hit.hit || hit.distance < closest_hit.distance) {
201+
closest_hit = hit;
202+
closest_hit.material = tri_mesh.material;
203+
}
177204
}
178205
}
179206
}
@@ -198,25 +225,22 @@ fn sphere_intersect(ray: Ray, sphere: Sphere) -> RayHit {
198225
let b = 2.0 * dot(oc, ray.direction);
199226
let c = dot(oc, oc) - sphere.radius * sphere.radius;
200227
let discriminant = b * b - 4.0 * a * c;
201-
if discriminant < 0.0 {
202-
return hit;
203-
} else {
228+
if discriminant >= 0.0 {
204229
let t = (-b - sqrt(discriminant)) / (2.0 * a);
205-
if t > 0.0 {
230+
if t > 1e-5 {
206231
hit.distance = t;
207232
hit.material = sphere.material;
208233
hit.position = ray.origin + t * ray.direction;
209234
hit.normal = normalize(hit.position - sphere.position);
235+
hit.is_backface = dot(ray.direction, hit.normal) < 0.0;
210236
hit.hit = true;
211-
return hit;
212-
} else {
213-
return hit;
214237
}
215238
}
239+
return hit;
216240
}
217241

218242
// moller-trumbore algorithm
219-
fn triangle_intersect(ray: Ray, v0_idx: u32) -> RayHit {
243+
fn triangle_intersect(ray: Ray, v0_idx: u32, detect_backface: bool) -> RayHit {
220244
var hit: RayHit;
221245
let v0 = triangle_vertices[v0_idx].xyz;
222246
let v1 = triangle_vertices[v0_idx + 1u].xyz;
@@ -246,15 +270,24 @@ fn triangle_intersect(ray: Ray, v0_idx: u32) -> RayHit {
246270
return hit;
247271
}
248272

273+
let w = 1.0 - u - v;
274+
249275
let t = f * dot(edge2, q);
250276

251-
if t > 0.0001 {
252-
hit.distance = t;
253-
hit.position = ray.origin + t * ray.direction;
254-
hit.normal = normalize(cross(edge1, edge2));
255-
hit.hit = true;
277+
let tri_face_vector = cross(edge1, edge2);
278+
let determinant = dot(tri_face_vector, ray.direction);
279+
var is_valid: bool;
280+
if detect_backface {
281+
is_valid = abs(determinant) >= 1e-8;
282+
} else {
283+
is_valid = determinant >= 1e-8;
256284
}
257285

286+
hit.hit = is_valid && t > 1e-5 && u >= 0.0 && v >= 0.0 && w >= 0.0;
287+
hit.normal = normalize(tri_face_vector) * -sign(determinant);
288+
hit.distance = t;
289+
hit.position = ray.origin + t * ray.direction;
290+
hit.is_backface = determinant > 0.0;
258291
return hit;
259292
}
260293

src/main.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -430,8 +430,7 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
430430
accumulated_frames,
431431
width: size.width,
432432
height: size.height,
433-
triangle_mesh_count: gpu_triangles.len() as u32,
434-
sphere_count: spheres.len() as u32,
433+
..Default::default()
435434
};
436435
queue.write_buffer(&config_dev, 0, bytemuck::bytes_of(&config_data));
437436
let mut encoder = device.create_command_encoder(&Default::default());

src/scenes.rs

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ pub fn spheres() -> (Vec<Sphere>, Vec<TriangleMesh>) {
1212
emission_color: Vec3::new(0.0, 0.0, 0.0),
1313
emission_strength: 0.0,
1414
smoothness: 0.0,
15+
refractive_index: 1.0,
16+
flag: 0,
17+
..Default::default()
1518
},
1619
},
1720
Sphere {
@@ -22,6 +25,9 @@ pub fn spheres() -> (Vec<Sphere>, Vec<TriangleMesh>) {
2225
emission_color: Vec3::new(0.0, 0.0, 0.0),
2326
emission_strength: 0.0,
2427
smoothness: 0.0,
28+
refractive_index: 1.0,
29+
flag: 0,
30+
..Default::default()
2531
},
2632
},
2733
Sphere {
@@ -32,6 +38,9 @@ pub fn spheres() -> (Vec<Sphere>, Vec<TriangleMesh>) {
3238
emission_color: Vec3::new(0.23, 1.0, 0.01),
3339
emission_strength: 0.0,
3440
smoothness: 0.0,
41+
refractive_index: 1.0,
42+
flag: 0,
43+
..Default::default()
3544
},
3645
},
3746
Sphere {
@@ -42,6 +51,9 @@ pub fn spheres() -> (Vec<Sphere>, Vec<TriangleMesh>) {
4251
emission_color: Vec3::new(0.0, 0.0, 0.0),
4352
emission_strength: 0.0,
4453
smoothness: 0.0,
54+
refractive_index: 1.0,
55+
flag: 0,
56+
..Default::default()
4557
},
4658
},
4759
Sphere {
@@ -52,6 +64,9 @@ pub fn spheres() -> (Vec<Sphere>, Vec<TriangleMesh>) {
5264
emission_color: Vec3::new(1.0, 1.0, 1.0),
5365
emission_strength: 0.0,
5466
smoothness: 0.0,
67+
refractive_index: 1.3,
68+
flag: 1,
69+
..Default::default()
5570
},
5671
},
5772
Sphere {
@@ -61,7 +76,10 @@ pub fn spheres() -> (Vec<Sphere>, Vec<TriangleMesh>) {
6176
diffuse_color: Vec3::new(0.38, 0.16, 0.81),
6277
emission_color: Vec3::new(0.38, 0.16, 0.81),
6378
emission_strength: 0.0,
64-
smoothness: 0.0,
79+
smoothness: 0.95,
80+
refractive_index: 1.0,
81+
flag: 0,
82+
..Default::default()
6583
},
6684
},
6785
];
@@ -77,10 +95,13 @@ pub fn spheres() -> (Vec<Sphere>, Vec<TriangleMesh>) {
7795
max: Vec3::new(-1.0, 2.0, -3.0).extend(0.0),
7896
},
7997
material: Material {
80-
diffuse_color: Vec3::new(1.0, 0.5, 0.0),
81-
emission_color: Vec3::new(1.0, 0.5, 0.0),
82-
emission_strength: 0.5,
83-
smoothness: 0.0,
98+
diffuse_color: Vec3::ONE,
99+
emission_color: Vec3::ONE,
100+
emission_strength: 0.0,
101+
smoothness: 1.0,
102+
refractive_index: 1.4,
103+
flag: 1,
104+
..Default::default()
84105
},
85106
}];
86107

@@ -97,6 +118,9 @@ pub fn cornell_box() -> (Vec<Sphere>, Vec<TriangleMesh>) {
97118
emission_color: Vec3::new(1.0, 1.0, 0.0),
98119
emission_strength: 0.2,
99120
smoothness: 0.2,
121+
refractive_index: 1.0,
122+
flag: 0,
123+
..Default::default()
100124
},
101125
},
102126
Sphere {
@@ -107,6 +131,9 @@ pub fn cornell_box() -> (Vec<Sphere>, Vec<TriangleMesh>) {
107131
emission_color: Vec3::new(1.0, 1.0, 1.0),
108132
emission_strength: 0.0,
109133
smoothness: 1.0,
134+
refractive_index: 1.0,
135+
flag: 1,
136+
..Default::default()
110137
},
111138
},
112139
Sphere {
@@ -117,6 +144,9 @@ pub fn cornell_box() -> (Vec<Sphere>, Vec<TriangleMesh>) {
117144
emission_color: Vec3::new(0.0, 1.0, 0.0),
118145
emission_strength: 0.2,
119146
smoothness: 0.1,
147+
refractive_index: 1.0,
148+
flag: 0,
149+
..Default::default()
120150
},
121151
},
122152
];
@@ -141,6 +171,9 @@ pub fn cornell_box() -> (Vec<Sphere>, Vec<TriangleMesh>) {
141171
emission_color: Vec3::new(0.0, 0.0, 0.0),
142172
emission_strength: 0.0,
143173
smoothness: 0.997,
174+
refractive_index: 1.0,
175+
flag: 0,
176+
..Default::default()
144177
},
145178
},
146179
// top
@@ -162,6 +195,9 @@ pub fn cornell_box() -> (Vec<Sphere>, Vec<TriangleMesh>) {
162195
emission_color: Vec3::new(0.0, 0.0, 0.0),
163196
emission_strength: 0.0,
164197
smoothness: 0.997,
198+
refractive_index: 1.0,
199+
flag: 0,
200+
..Default::default()
165201
},
166202
},
167203
// front
@@ -183,6 +219,9 @@ pub fn cornell_box() -> (Vec<Sphere>, Vec<TriangleMesh>) {
183219
emission_color: Vec3::new(0.0, 0.0, 0.0),
184220
emission_strength: 0.0,
185221
smoothness: 0.997,
222+
refractive_index: 1.0,
223+
flag: 0,
224+
..Default::default()
186225
},
187226
},
188227
// left (red)
@@ -204,6 +243,9 @@ pub fn cornell_box() -> (Vec<Sphere>, Vec<TriangleMesh>) {
204243
emission_color: Vec3::new(0.0, 0.0, 0.0),
205244
emission_strength: 0.0,
206245
smoothness: 0.997,
246+
refractive_index: 1.0,
247+
flag: 0,
248+
..Default::default()
207249
},
208250
},
209251
// right (green)
@@ -225,6 +267,9 @@ pub fn cornell_box() -> (Vec<Sphere>, Vec<TriangleMesh>) {
225267
emission_color: Vec3::new(0.0, 0.0, 0.0),
226268
emission_strength: 0.0,
227269
smoothness: 0.997,
270+
refractive_index: 1.0,
271+
flag: 0,
272+
..Default::default()
228273
},
229274
},
230275
// back
@@ -246,6 +291,9 @@ pub fn cornell_box() -> (Vec<Sphere>, Vec<TriangleMesh>) {
246291
emission_color: Vec3::new(0.0, 0.0, 0.0),
247292
emission_strength: 0.0,
248293
smoothness: 0.997,
294+
refractive_index: 1.0,
295+
flag: 0,
296+
..Default::default()
249297
},
250298
},
251299
// light
@@ -267,6 +315,9 @@ pub fn cornell_box() -> (Vec<Sphere>, Vec<TriangleMesh>) {
267315
emission_color: Vec3::new(1.0, 1.0, 1.0),
268316
emission_strength: 5.0,
269317
smoothness: 0.0,
318+
refractive_index: 1.0,
319+
flag: 0,
320+
..Default::default()
270321
},
271322
},
272323
];

src/utils.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use glam::*;
22

33
#[repr(C)]
4-
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
4+
#[derive(Default, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
55
pub struct IParams {
66
pub camera_pos: Vec3,
77
pub random_seed: f32,
@@ -10,8 +10,7 @@ pub struct IParams {
1010
pub accumulated_frames: u32,
1111
pub width: u32,
1212
pub height: u32,
13-
pub triangle_mesh_count: u32,
14-
pub sphere_count: u32,
13+
pub _pad: [u32; 2],
1514
}
1615

1716
#[repr(C)]
@@ -52,4 +51,7 @@ pub struct Material {
5251
pub smoothness: f32,
5352
pub emission_color: Vec3,
5453
pub emission_strength: f32,
54+
pub refractive_index: f32,
55+
pub flag: u32,
56+
pub _pad: [u32; 2],
5557
}

0 commit comments

Comments
 (0)