Skip to content

Commit db0b019

Browse files
committed
scene
1 parent 0b9f112 commit db0b019

File tree

2 files changed

+124
-49
lines changed

2 files changed

+124
-49
lines changed

assets/compute.wgsl

Lines changed: 54 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
11
struct Params {
22
camera_pos: vec3f,
33
_pad1: u32,
4+
light_dir: vec3f,
5+
_pad2: u32,
46
width: u32,
57
height: u32,
68
iTime: f32,
7-
_pad2: u32,
9+
sphere_count: u32,
810
};
911

1012
struct Material {
1113
diffuse_color: vec3f,
12-
_pad: f32,
14+
smoothness: f32,
1315
emission_color: vec3f,
1416
emission_strength: f32,
1517
};
1618

1719
struct Sphere {
18-
center: vec3f,
20+
position: vec3f,
1921
radius: f32,
2022
material: Material,
2123
};
@@ -27,6 +29,7 @@ struct Sphere {
2729
const PI: f32 = 3.141592;
2830

2931
const MAX_BOUNCES: u32 = 5u;
32+
const RAYS_PER_PIXEL: u32 = 5u;
3033

3134
struct Ray {
3235
origin: vec3f,
@@ -71,46 +74,74 @@ fn random_direction(state: ptr<function, u32>) -> vec3f {
7174
let z = random_normal_distribution(state);
7275
return normalize(vec3f(x, y, z));
7376
}
77+
const GROUND_COLOR: vec3f = vec3f(0.35, 0.3, 0.35);
78+
const SKY_COLOR_HORIZON: vec3f = vec3f(1.0, 1.0, 1.0);
79+
const SKY_COLOR_ZENITH: vec3f = vec3f(0.8, 0.8, 0.8);
7480

75-
fn random_hemisphere_dir(normal: vec3f, state: ptr<function, u32>) -> vec3f {
76-
let dir = random_direction(state);
77-
if dot(dir, normal) < 0.0 {
78-
return -dir;
79-
} else {
80-
return dir;
81-
}
81+
const SUN_INTENSITY: f32 = 10.0;
82+
const SUN_FOCUS: f32 = 500.0;
83+
const SUN_COLOR: vec3f = vec3f(1.0, 0.9, 0.6);
84+
85+
fn get_environment_light(ray: Ray, light_dir: vec3f) -> vec3f {
86+
let sky_gradient = mix(SKY_COLOR_HORIZON,
87+
SKY_COLOR_ZENITH,
88+
pow(smoothstep(0.0, 0.4, ray.direction.y), 0.35));
89+
90+
let sun = pow(max(dot(ray.direction, light_dir), 0.0), SUN_FOCUS) * SUN_INTENSITY;
91+
92+
let ground_to_sky = smoothstep(-0.01, 0.0, ray.direction.y);
93+
let sun_mask = ground_to_sky >= 1.0;
94+
95+
return mix(GROUND_COLOR, sky_gradient, ground_to_sky) + sun * SUN_COLOR * f32(u32(sun_mask));
96+
}
97+
98+
fn smoothstep(edge0: f32, edge1: f32, x: f32) -> f32 {
99+
let t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
100+
return t * t * (3.0 - t * 2.0);
82101
}
83102

84103
fn trace(ray: ptr<function, Ray>, state: ptr<function, u32>) -> vec3f {
104+
var total_light = vec3f(0.0);
105+
for (var i = 0u; i < RAYS_PER_PIXEL; i = i + 1u) {
106+
var r = *ray;
107+
total_light = total_light + trace_single(&r, state);
108+
}
109+
110+
return total_light / f32(RAYS_PER_PIXEL);
111+
}
112+
113+
fn trace_single(ray: ptr<function, Ray>, state: ptr<function, u32>) -> vec3f {
85114
var light = vec3f(0.0, 0.0, 0.0);
86115
var color = vec3f(1.0, 1.0, 1.0);
87116

88117
for (var bounce: u32 = 0u; bounce < MAX_BOUNCES; bounce = bounce + 1u) {
89118
let hit = calculate_collision(*ray);
90119
if hit.hit {
91120
(*ray).origin = hit.position + hit.normal * 0.001;
92-
(*ray).direction = random_hemisphere_dir(hit.normal, state);
121+
let diffuse = normalize(hit.normal + random_direction(state));
122+
let specular = reflect((*ray).direction, hit.normal);
123+
124+
(*ray).direction = mix(diffuse, specular, hit.material.smoothness);
93125

94126
let emitted = hit.material.emission_color * hit.material.emission_strength;
95-
light = light + color * emitted;
96127
color = color * hit.material.diffuse_color;
128+
light = light + color * emitted;
97129
} else {
130+
light = light + get_environment_light(*ray, params.light_dir) * color;
98131
break;
99132
}
100133
}
101134

102135
return light;
103136
}
104137

138+
fn reflect(I: vec3f, N: vec3f) -> vec3f {
139+
return I - 2.0 * dot(N, I) * N;
140+
}
141+
105142
fn calculate_collision(ray: Ray) -> RayHit {
106-
var closest_hit = RayHit(
107-
0.0,
108-
vec3f(0.0),
109-
vec3f(0.0),
110-
Material(vec3f(0.0), 0.0, vec3f(0.0), 0.0),
111-
false
112-
);
113-
for (var i: u32 = 0u; i < params._pad2; i = i + 1u) {
143+
var closest_hit: RayHit;
144+
for (var i: u32 = 0u; i < params.sphere_count; i = i + 1u) {
114145
let hit = sphere_intersect(ray, spheres[i]);
115146
if hit.hit && (!closest_hit.hit || hit.distance < closest_hit.distance) {
116147
closest_hit = hit;
@@ -120,14 +151,8 @@ fn calculate_collision(ray: Ray) -> RayHit {
120151
}
121152

122153
fn sphere_intersect(ray: Ray, sphere: Sphere) -> RayHit {
123-
var hit = RayHit(
124-
0.0,
125-
vec3f(0.0),
126-
vec3f(0.0),
127-
Material(vec3f(0.0), 0.0, vec3f(0.0), 0.0),
128-
false
129-
);
130-
let oc = ray.origin - sphere.center;
154+
var hit: RayHit;
155+
let oc = ray.origin - sphere.position;
131156
let a = dot(ray.direction, ray.direction);
132157
let b = 2.0 * dot(oc, ray.direction);
133158
let c = dot(oc, oc) - sphere.radius * sphere.radius;
@@ -140,7 +165,7 @@ fn sphere_intersect(ray: Ray, sphere: Sphere) -> RayHit {
140165
hit.distance = t;
141166
hit.material = sphere.material;
142167
hit.position = ray.origin + t * ray.direction;
143-
hit.normal = normalize(hit.position - sphere.center);
168+
hit.normal = normalize(hit.position - sphere.position);
144169
hit.hit = true;
145170
return hit;
146171
} else {

src/main.rs

Lines changed: 70 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ use winit::{
1212
#[repr(C)]
1313
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
1414
struct IParams {
15-
camera_pos: [f32; 3],
15+
camera_pos: Vec3,
1616
_pad1: u32,
17+
light_dir: Vec3,
18+
_pad2: u32,
1719
width: u32,
1820
height: u32,
1921
i_time: f32,
@@ -23,17 +25,17 @@ struct IParams {
2325
#[repr(C)]
2426
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
2527
struct Sphere {
26-
center: [f32; 3],
28+
position: Vec3,
2729
radius: f32,
2830
material: Material,
2931
}
3032

3133
#[repr(C)]
3234
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
3335
struct Material {
34-
diffuse_color: [f32; 3],
35-
_pad: f32,
36-
emission_color: [f32; 3],
36+
diffuse_color: Vec3,
37+
smoothness: f32,
38+
emission_color: Vec3,
3739
emission_strength: f32,
3840
}
3941

@@ -62,8 +64,8 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
6264
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
6365
format,
6466
width: size.width,
65-
height: size.height,
6667
present_mode: wgpu::PresentMode::AutoVsync,
68+
height: size.height,
6769
alpha_mode: swapchain_capabilities.alpha_modes[0],
6870
view_formats: vec![],
6971
desired_maximum_frame_latency: 2,
@@ -153,22 +155,68 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
153155
});
154156
let config_resource = config_dev.as_entire_binding();
155157

156-
let spheres = (0..2)
157-
.map(|i| Sphere {
158-
center: if i == 0 {
159-
Vec3::NEG_Y.into()
160-
} else {
161-
Vec3::Y.into()
158+
let spheres = vec![
159+
Sphere {
160+
position: Vec3::new(-4.0, 0.4, -0.4),
161+
radius: 0.4,
162+
material: Material {
163+
diffuse_color: Vec3::new(0.2, 0.2, 0.2),
164+
emission_color: Vec3::new(0.0, 0.0, 0.0),
165+
emission_strength: 0.0,
166+
smoothness: 0.0,
162167
},
168+
},
169+
Sphere {
170+
position: Vec3::new(-2.5, 0.75, -0.2),
171+
radius: 0.75,
172+
material: Material {
173+
diffuse_color: Vec3::new(0.13, 0.51, 0.95),
174+
emission_color: Vec3::new(0.0, 0.0, 0.0),
175+
emission_strength: 0.0,
176+
smoothness: 0.0,
177+
},
178+
},
179+
Sphere {
180+
position: Vec3::new(-0.5, 1.0, 0.0),
163181
radius: 1.0,
164182
material: Material {
165-
diffuse_color: Vec3::new(1.0, 0.0, 0.0).into(),
166-
_pad: 0.0,
167-
emission_color: Vec3::new(1.0, 1.0, 1.0).into(),
168-
emission_strength: if i == 0 { 1.0 } else { 0.0 },
183+
diffuse_color: Vec3::new(0.28, 0.94, 0.07),
184+
emission_color: Vec3::new(0.23, 1.0, 0.01),
185+
emission_strength: 0.0,
186+
smoothness: 0.95,
169187
},
170-
})
171-
.collect::<Vec<_>>();
188+
},
189+
Sphere {
190+
position: Vec3::new(2.0, 1.25, -0.2),
191+
radius: 1.25,
192+
material: Material {
193+
diffuse_color: Vec3::new(1.0, 0.06, 0.06),
194+
emission_color: Vec3::new(0.0, 0.0, 0.0),
195+
emission_strength: 0.0,
196+
smoothness: 0.0,
197+
},
198+
},
199+
Sphere {
200+
position: Vec3::new(5.5, 2.0, -0.4),
201+
radius: 2.0,
202+
material: Material {
203+
diffuse_color: Vec3::new(1.0, 1.0, 1.0),
204+
emission_color: Vec3::new(1.0, 1.0, 1.0),
205+
emission_strength: 0.0,
206+
smoothness: 0.0,
207+
},
208+
},
209+
Sphere {
210+
position: Vec3::new(0.0, -100.0, 0.0),
211+
radius: 100.0,
212+
material: Material {
213+
diffuse_color: Vec3::new(0.38, 0.16, 0.81),
214+
emission_color: Vec3::new(0.38, 0.16, 0.81),
215+
emission_strength: 0.0,
216+
smoothness: 0.0,
217+
},
218+
},
219+
];
172220

173221
let sphere_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
174222
label: Some("Sphere Buffer"),
@@ -292,12 +340,14 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
292340

293341
let i_time: f32 = 0.5 + start_time.elapsed().as_micros() as f32 * 1e-6;
294342
let config_data = IParams {
295-
camera_pos: Vec3::new(0.0, 0.0, 5.0).into(),
343+
camera_pos: Vec3::new(0.0, 0.0, 5.0),
296344
_pad1: 0,
345+
light_dir: Vec3::new(0.2, 1.0, 0.05).normalize(),
346+
_pad2: 0,
297347
width: size.width,
298348
height: size.height,
299349
i_time,
300-
sphere_count: 2,
350+
sphere_count: spheres.len() as u32,
301351
};
302352
let config_host =
303353
device.create_buffer_init(&wgpu::util::BufferInitDescriptor {

0 commit comments

Comments
 (0)