From 378511bedf83fb32490af29c3b6a084eae34bf07 Mon Sep 17 00:00:00 2001 From: numzero Date: Sun, 29 Dec 2024 18:26:45 +0300 Subject: [PATCH] Add environment --- README.md | 2 +- src/bin/minitracer/main.rs | 85 +++++++++++++++++++++++++++++++++-- src/bin/minitracer/trace.rs | 32 +++++++++++-- src/bin/minitracer/trace.wgsl | 4 ++ 4 files changed, 115 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 2750a77..9563742 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # 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! ![Screenshot](screenshot.jpg) diff --git a/src/bin/minitracer/main.rs b/src/bin/minitracer/main.rs index 8121d8b..eccaf59 100644 --- a/src/bin/minitracer/main.rs +++ b/src/bin/minitracer/main.rs @@ -1,7 +1,8 @@ use std::error::Error; use glam::{vec2, vec3}; -use trace::{Tracer, TracerData, Vertex}; +use image::ImageReader; +use trace::{Tracer, TracerData, TracerEnv, Vertex}; use winit::{ event::{Event, WindowEvent}, event_loop::EventLoop, @@ -44,8 +45,11 @@ fn main() { .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( &queue, trace::Params { @@ -59,6 +63,7 @@ fn main() { let distr = anim::SphereParamsDistribution::default(); (0..N_SPHERES).map(|_| distr.make_params(&mut rng)).collect() }; + let tracer_env = TracerEnv::new(&device, &tracer, &envmap); let mut time = 0.0; @@ -73,7 +78,7 @@ fn main() { &device, &wgpu::SurfaceConfiguration { usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_DST, - format: wgpu::TextureFormat::Bgra8Unorm, + format, width: physical_size.width, height: physical_size.height, present_mode: wgpu::PresentMode::Fifo, @@ -111,7 +116,7 @@ fn main() { occlusion_query_set: None, timestamp_writes: None, }); - tracer.render(&mut render_pass, &data); + tracer.render(&mut render_pass, &data, &tracer_env); drop(render_pass); queue.submit(std::iter::once(encoder.finish())); output.present(); @@ -151,3 +156,75 @@ async fn init_gpu(wnd: &Window) -> Result<(wgpu::Device, wgpu::Queue, wgpu::Surf .unwrap(); 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, + }) +} diff --git a/src/bin/minitracer/trace.rs b/src/bin/minitracer/trace.rs index 177436a..8066eee 100644 --- a/src/bin/minitracer/trace.rs +++ b/src/bin/minitracer/trace.rs @@ -50,10 +50,14 @@ pub struct TracerData { bindings: wgpu::BindGroup, } +pub struct TracerEnv { + bindings: wgpu::BindGroup, +} + static SHADER: &str = include_str!("trace.wgsl"); 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 { label: None, size: (4 * mem::size_of::()) as u64, @@ -114,7 +118,7 @@ impl Tracer { entry_point: None, compilation_options: wgpu::PipelineCompilationOptions::default(), targets: &[Some(wgpu::ColorTargetState { - format: wgpu::TextureFormat::Bgra8Unorm, + format, blend: Some(wgpu::BlendState::REPLACE), write_mask: wgpu::ColorWrites::ALL, })], @@ -137,10 +141,11 @@ impl Tracer { 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_vertex_buffer(0, self.view_buf.slice(..)); pass.set_bind_group(0, &data.bindings, &[]); + pass.set_bind_group(1, &env.bindings, &[]); pass.draw(0..4, 0..1); } } @@ -180,3 +185,24 @@ impl TracerData { 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 } + } +} diff --git a/src/bin/minitracer/trace.wgsl b/src/bin/minitracer/trace.wgsl index 1275f3e..1f64b63 100644 --- a/src/bin/minitracer/trace.wgsl +++ b/src/bin/minitracer/trace.wgsl @@ -26,6 +26,8 @@ struct Varying { @group(0) @binding(0) var params: Params; @group(0) @binding(1) var spheres: array; +@group(1) @binding(0) var env_sampler: sampler; +@group(1) @binding(1) var env_texture: texture_cube; @vertex fn on_vertex(in: Vertex) -> Varying { @@ -79,6 +81,8 @@ fn trace_fragment(in: Varying) -> vec4f { } } if (sphere == -1) { + let env = textureSampleLevel(env_texture, env_sampler, ray, 0.0); + result += vec4(3.0 * color * env.xyz, 0.0); break; } let s = spheres[sphere];