Add environment
This commit is contained in:
parent
786f1d6050
commit
378511bedf
|
|
@ -1,5 +1,5 @@
|
||||||
# Ray tracing example
|
# Ray tracing example
|
||||||
|
|
||||||
Basic GPU-side ray tracing example. `cargo run` to see it moving!
|
Basic GPU-side ray tracing example. `cargo run --bin envmap` to prepare the sky, then `cargo run` to see it moving!
|
||||||
|
|
||||||

|

|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
use glam::{vec2, vec3};
|
use glam::{vec2, vec3};
|
||||||
use trace::{Tracer, TracerData, Vertex};
|
use image::ImageReader;
|
||||||
|
use trace::{Tracer, TracerData, TracerEnv, Vertex};
|
||||||
use winit::{
|
use winit::{
|
||||||
event::{Event, WindowEvent},
|
event::{Event, WindowEvent},
|
||||||
event_loop::EventLoop,
|
event_loop::EventLoop,
|
||||||
|
|
@ -44,8 +45,11 @@ fn main() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let (device, queue, surface) = pollster::block_on(init_gpu(window)).unwrap();
|
let (device, queue, surface) = pollster::block_on(init_gpu(window)).unwrap();
|
||||||
|
let envmap = load_envmap(&device, &queue);
|
||||||
|
queue.submit([]);
|
||||||
|
|
||||||
let mut tracer = Tracer::new(&device);
|
let format = wgpu::TextureFormat::Bgra8UnormSrgb;
|
||||||
|
let mut tracer = Tracer::new(&device, format);
|
||||||
tracer.set_params(
|
tracer.set_params(
|
||||||
&queue,
|
&queue,
|
||||||
trace::Params {
|
trace::Params {
|
||||||
|
|
@ -59,6 +63,7 @@ fn main() {
|
||||||
let distr = anim::SphereParamsDistribution::default();
|
let distr = anim::SphereParamsDistribution::default();
|
||||||
(0..N_SPHERES).map(|_| distr.make_params(&mut rng)).collect()
|
(0..N_SPHERES).map(|_| distr.make_params(&mut rng)).collect()
|
||||||
};
|
};
|
||||||
|
let tracer_env = TracerEnv::new(&device, &tracer, &envmap);
|
||||||
|
|
||||||
let mut time = 0.0;
|
let mut time = 0.0;
|
||||||
|
|
||||||
|
|
@ -73,7 +78,7 @@ fn main() {
|
||||||
&device,
|
&device,
|
||||||
&wgpu::SurfaceConfiguration {
|
&wgpu::SurfaceConfiguration {
|
||||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_DST,
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_DST,
|
||||||
format: wgpu::TextureFormat::Bgra8Unorm,
|
format,
|
||||||
width: physical_size.width,
|
width: physical_size.width,
|
||||||
height: physical_size.height,
|
height: physical_size.height,
|
||||||
present_mode: wgpu::PresentMode::Fifo,
|
present_mode: wgpu::PresentMode::Fifo,
|
||||||
|
|
@ -111,7 +116,7 @@ fn main() {
|
||||||
occlusion_query_set: None,
|
occlusion_query_set: None,
|
||||||
timestamp_writes: None,
|
timestamp_writes: None,
|
||||||
});
|
});
|
||||||
tracer.render(&mut render_pass, &data);
|
tracer.render(&mut render_pass, &data, &tracer_env);
|
||||||
drop(render_pass);
|
drop(render_pass);
|
||||||
queue.submit(std::iter::once(encoder.finish()));
|
queue.submit(std::iter::once(encoder.finish()));
|
||||||
output.present();
|
output.present();
|
||||||
|
|
@ -151,3 +156,75 @@ async fn init_gpu(wnd: &Window) -> Result<(wgpu::Device, wgpu::Queue, wgpu::Surf
|
||||||
.unwrap();
|
.unwrap();
|
||||||
Ok((device, queue, surface))
|
Ok((device, queue, surface))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn load_envmap(device: &wgpu::Device, queue: &wgpu::Queue) -> wgpu::TextureView {
|
||||||
|
let imgs = std::thread::scope(|s| {
|
||||||
|
[0, 1, 2, 3, 4, 5]
|
||||||
|
.map(|face| {
|
||||||
|
s.spawn(move || {
|
||||||
|
let img = ImageReader::open(format!("textures/env{face}.jpeg"))
|
||||||
|
.unwrap()
|
||||||
|
.with_guessed_format()
|
||||||
|
.unwrap()
|
||||||
|
.decode()
|
||||||
|
.unwrap();
|
||||||
|
img.to_rgba8()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.map(|t| t.join().unwrap())
|
||||||
|
});
|
||||||
|
let size = imgs[0].width();
|
||||||
|
for img in &imgs {
|
||||||
|
assert!(img.width() == size);
|
||||||
|
assert!(img.height() == size);
|
||||||
|
}
|
||||||
|
let texture = device.create_texture(&wgpu::TextureDescriptor {
|
||||||
|
label: None,
|
||||||
|
size: wgpu::Extent3d {
|
||||||
|
width: size,
|
||||||
|
height: size,
|
||||||
|
depth_or_array_layers: 6,
|
||||||
|
},
|
||||||
|
mip_level_count: 1,
|
||||||
|
sample_count: 1,
|
||||||
|
dimension: wgpu::TextureDimension::D2,
|
||||||
|
format: wgpu::TextureFormat::Rgba8UnormSrgb,
|
||||||
|
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
|
||||||
|
view_formats: &[],
|
||||||
|
});
|
||||||
|
for (face, img) in imgs.iter().enumerate() {
|
||||||
|
queue.write_texture(
|
||||||
|
wgpu::ImageCopyTexture {
|
||||||
|
texture: &texture,
|
||||||
|
mip_level: 0,
|
||||||
|
origin: wgpu::Origin3d {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
z: face as u32,
|
||||||
|
},
|
||||||
|
aspect: wgpu::TextureAspect::All,
|
||||||
|
},
|
||||||
|
img.as_raw(),
|
||||||
|
wgpu::ImageDataLayout {
|
||||||
|
offset: 0,
|
||||||
|
bytes_per_row: Some(4 * size),
|
||||||
|
rows_per_image: Some(size),
|
||||||
|
},
|
||||||
|
wgpu::Extent3d {
|
||||||
|
width: size,
|
||||||
|
height: size,
|
||||||
|
depth_or_array_layers: 1,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
texture.create_view(&wgpu::TextureViewDescriptor {
|
||||||
|
label: None,
|
||||||
|
format: None,
|
||||||
|
dimension: Some(wgpu::TextureViewDimension::Cube),
|
||||||
|
aspect: wgpu::TextureAspect::All,
|
||||||
|
base_mip_level: 0,
|
||||||
|
mip_level_count: None,
|
||||||
|
base_array_layer: 0,
|
||||||
|
array_layer_count: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,10 +50,14 @@ pub struct TracerData {
|
||||||
bindings: wgpu::BindGroup,
|
bindings: wgpu::BindGroup,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct TracerEnv {
|
||||||
|
bindings: wgpu::BindGroup,
|
||||||
|
}
|
||||||
|
|
||||||
static SHADER: &str = include_str!("trace.wgsl");
|
static SHADER: &str = include_str!("trace.wgsl");
|
||||||
|
|
||||||
impl Tracer {
|
impl Tracer {
|
||||||
pub fn new(device: &wgpu::Device) -> Self {
|
pub fn new(device: &wgpu::Device, format: wgpu::TextureFormat) -> Self {
|
||||||
let view_buf = device.create_buffer(&wgpu::BufferDescriptor {
|
let view_buf = device.create_buffer(&wgpu::BufferDescriptor {
|
||||||
label: None,
|
label: None,
|
||||||
size: (4 * mem::size_of::<Vertex>()) as u64,
|
size: (4 * mem::size_of::<Vertex>()) as u64,
|
||||||
|
|
@ -114,7 +118,7 @@ impl Tracer {
|
||||||
entry_point: None,
|
entry_point: None,
|
||||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||||
targets: &[Some(wgpu::ColorTargetState {
|
targets: &[Some(wgpu::ColorTargetState {
|
||||||
format: wgpu::TextureFormat::Bgra8Unorm,
|
format,
|
||||||
blend: Some(wgpu::BlendState::REPLACE),
|
blend: Some(wgpu::BlendState::REPLACE),
|
||||||
write_mask: wgpu::ColorWrites::ALL,
|
write_mask: wgpu::ColorWrites::ALL,
|
||||||
})],
|
})],
|
||||||
|
|
@ -137,10 +141,11 @@ impl Tracer {
|
||||||
queue.write_buffer(&self.view_buf, 0, bytes_of(vertices));
|
queue.write_buffer(&self.view_buf, 0, bytes_of(vertices));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(&self, pass: &mut wgpu::RenderPass, data: &TracerData) {
|
pub fn render(&self, pass: &mut wgpu::RenderPass, data: &TracerData, env: &TracerEnv) {
|
||||||
pass.set_pipeline(&self.pipeline);
|
pass.set_pipeline(&self.pipeline);
|
||||||
pass.set_vertex_buffer(0, self.view_buf.slice(..));
|
pass.set_vertex_buffer(0, self.view_buf.slice(..));
|
||||||
pass.set_bind_group(0, &data.bindings, &[]);
|
pass.set_bind_group(0, &data.bindings, &[]);
|
||||||
|
pass.set_bind_group(1, &env.bindings, &[]);
|
||||||
pass.draw(0..4, 0..1);
|
pass.draw(0..4, 0..1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -180,3 +185,24 @@ impl TracerData {
|
||||||
Self { bindings }
|
Self { bindings }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TracerEnv {
|
||||||
|
pub fn new(device: &wgpu::Device, tracer: &Tracer, view: &wgpu::TextureView) -> Self {
|
||||||
|
let sampler = device.create_sampler(&wgpu::SamplerDescriptor::default());
|
||||||
|
let bindings = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||||
|
label: None,
|
||||||
|
layout: &tracer.pipeline.get_bind_group_layout(1),
|
||||||
|
entries: &[
|
||||||
|
wgpu::BindGroupEntry {
|
||||||
|
binding: 0,
|
||||||
|
resource: wgpu::BindingResource::Sampler(&sampler),
|
||||||
|
},
|
||||||
|
wgpu::BindGroupEntry {
|
||||||
|
binding: 1,
|
||||||
|
resource: wgpu::BindingResource::TextureView(view),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
Self { bindings }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,8 @@ struct Varying {
|
||||||
|
|
||||||
@group(0) @binding(0) var<uniform> params: Params;
|
@group(0) @binding(0) var<uniform> params: Params;
|
||||||
@group(0) @binding(1) var<storage, read> spheres: array<Sphere>;
|
@group(0) @binding(1) var<storage, read> spheres: array<Sphere>;
|
||||||
|
@group(1) @binding(0) var env_sampler: sampler;
|
||||||
|
@group(1) @binding(1) var env_texture: texture_cube<f32>;
|
||||||
|
|
||||||
@vertex
|
@vertex
|
||||||
fn on_vertex(in: Vertex) -> Varying {
|
fn on_vertex(in: Vertex) -> Varying {
|
||||||
|
|
@ -79,6 +81,8 @@ fn trace_fragment(in: Varying) -> vec4f {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (sphere == -1) {
|
if (sphere == -1) {
|
||||||
|
let env = textureSampleLevel(env_texture, env_sampler, ray, 0.0);
|
||||||
|
result += vec4(3.0 * color * env.xyz, 0.0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
let s = spheres[sphere];
|
let s = spheres[sphere];
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user