diff --git a/src/bin/minitracer/main.rs b/src/bin/minitracer/main.rs index faa3b8f..83c9c87 100644 --- a/src/bin/minitracer/main.rs +++ b/src/bin/minitracer/main.rs @@ -1,9 +1,9 @@ use std::error::Error; -use glam::{mat3, uvec2, vec2, vec3, Vec3}; +use glam::{mat3, uvec2, Vec3}; use image::ImageReader; use present::Presenter; -use trace::{Tracer, TracerData, TracerEnv, Vertex}; +use trace::{Tracer, TracerData, TracerEnv}; use winit::{ event::{Event, WindowEvent}, event_loop::EventLoop, @@ -22,25 +22,19 @@ struct CamLoc { right: Vec3, } -fn make_viewport(cam: CamLoc, w: u32, h: u32) -> [Vertex; 4] { +fn make_viewport(cam: CamLoc, w: u32, h: u32) -> trace::CameraLocation { let size = uvec2(w, h).as_vec2(); let size = size.normalize(); let (w, h, d) = (size.x, size.y, 1.); - let screen_coord = [vec2(-1., -1.), vec2(1., -1.), vec2(-1., 1.), vec2(1., 1.)]; - let eye = cam.eye; - let fwd = cam.forward.normalize(); - let up = cam.right.cross(fwd).normalize(); - let right = up.cross(fwd); + let fwd = d * cam.forward.normalize(); + let up = h * cam.right.cross(fwd).normalize(); + let right = w * up.cross(fwd).normalize(); - let m = mat3(fwd, right, up); - - let world_coord = [vec3(d, -w, -h), vec3(d, w, -h), vec3(d, -w, h), vec3(d, w, h)]; - [0, 1, 2, 3].map(|k| Vertex { - eye, - world: eye + m * world_coord[k], - screen: screen_coord[k], - }) + trace::CameraLocation { + eye: cam.eye, + view: mat3(fwd, right, up), + } } const N_SPHERES: u32 = 100; @@ -60,7 +54,7 @@ fn main() { let output_format = wgpu::TextureFormat::Bgra8UnormSrgb; let hdr_format = wgpu::TextureFormat::Rgba16Float; - let mut tracer = Tracer::new(&device, hdr_format); + let tracer = Tracer::new(&device, hdr_format); let mut rng = rand_pcg::Pcg32::new(42, 0); let sphere_params: Vec<_> = { let distr = anim::distr(); @@ -149,10 +143,7 @@ fn main() { let eye = camera_params.to_sphere(time).center; let right = camera_params.deriv(time); let forward = target_params.to_sphere(time).center - eye; - tracer.set_view( - &queue, - &make_viewport(CamLoc { eye, forward, right }, size.width, size.height), - ); + let view = make_viewport(CamLoc { eye, forward, right }, size.width, size.height); let spheres: Vec<_> = sphere_params.iter().map(|p| p.to_sphere(time)).collect(); let data = TracerData::new(&device, &tracer, &spheres); tracer.render( @@ -165,6 +156,7 @@ fn main() { sphere_count: N_SPHERES, seed: frame, }, + view, ); } } @@ -222,7 +214,7 @@ async fn init_gpu(wnd: &Window) -> Result<(wgpu::Device, wgpu::Queue, wgpu::Surf label: None, required_features: wgpu::Features::PUSH_CONSTANTS, required_limits: wgpu::Limits { - max_push_constant_size: 32, + max_push_constant_size: 128, ..Default::default() }, memory_hints: Default::default(), diff --git a/src/bin/minitracer/trace.rs b/src/bin/minitracer/trace.rs index db42ceb..9eef951 100644 --- a/src/bin/minitracer/trace.rs +++ b/src/bin/minitracer/trace.rs @@ -1,7 +1,7 @@ -use std::mem::{self, offset_of}; +use std::mem; use bytemuck::{bytes_of, cast_slice, Pod, Zeroable}; -use glam::{Vec2, Vec3}; +use glam::{vec2, Mat3, Vec2, Vec3}; use wgpu::util::DeviceExt; #[derive(Debug, Clone, Copy, Pod, Zeroable)] @@ -13,6 +13,47 @@ pub struct Params { pub seed: u32, } +#[derive(Debug, Clone, Copy)] +pub struct CameraLocation { + pub eye: Vec3, + pub view: Mat3, +} + +#[derive(Debug, Clone, Copy, Pod, Zeroable)] +#[repr(C)] +struct ParamsData { + params: Params, + camera: CameraData, +} + +#[derive(Debug, Clone, Copy, Pod, Zeroable)] +#[repr(C)] +struct CameraData { + u: Vec3, + pad1: f32, + v: Vec3, + pad2: f32, + w: Vec3, + pad3: f32, + eye: Vec3, + pad4: f32, +} + +impl From for CameraData { + fn from(value: CameraLocation) -> Self { + CameraData { + u: value.view.x_axis, + v: value.view.y_axis, + w: value.view.z_axis, + eye: value.eye, + pad1: 0., + pad2: 0., + pad3: 0., + pad4: 0., + } + } +} + #[derive(Debug, Clone, Copy)] pub struct Sphere { pub center: Vec3, @@ -24,9 +65,7 @@ pub struct Sphere { #[derive(Debug, Clone, Copy, Pod, Zeroable)] #[repr(C)] -pub struct Vertex { - pub eye: Vec3, - pub world: Vec3, +struct Vertex { pub screen: Vec2, } @@ -71,11 +110,11 @@ static SHADER: &str = include_str!("trace.wgsl"); impl Tracer { pub fn new(device: &wgpu::Device, format: wgpu::TextureFormat) -> Self { - let view_buf = device.create_buffer(&wgpu::BufferDescriptor { + let screen_coord = [vec2(-1., -1.), vec2(1., -1.), vec2(-1., 1.), vec2(1., 1.)]; + let view_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { label: None, - size: (4 * mem::size_of::()) as u64, - usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST, - mapped_at_creation: false, + contents: cast_slice(&screen_coord), + usage: wgpu::BufferUsages::VERTEX, }); let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { label: None, @@ -120,7 +159,7 @@ impl Tracer { bind_group_layouts: &[&spheres_bgl, &envmap_bgl], push_constant_ranges: &[wgpu::PushConstantRange { stages: wgpu::ShaderStages::FRAGMENT, - range: 0..16, + range: 0..mem::size_of::() as u32, }], }); let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { @@ -133,23 +172,11 @@ impl Tracer { buffers: &[wgpu::VertexBufferLayout { array_stride: size_of::() as u64, step_mode: wgpu::VertexStepMode::Vertex, - attributes: &[ - wgpu::VertexAttribute { - shader_location: 0, - offset: offset_of!(Vertex, eye) as u64, - format: wgpu::VertexFormat::Float32x3, - }, - wgpu::VertexAttribute { - shader_location: 1, - offset: offset_of!(Vertex, world) as u64, - format: wgpu::VertexFormat::Float32x3, - }, - wgpu::VertexAttribute { - shader_location: 2, - offset: offset_of!(Vertex, screen) as u64, - format: wgpu::VertexFormat::Float32x2, - }, - ], + attributes: &[wgpu::VertexAttribute { + shader_location: 0, + offset: 0, + format: wgpu::VertexFormat::Float32x2, + }], }], }, primitive: wgpu::PrimitiveState { @@ -189,13 +216,23 @@ impl Tracer { Self { view_buf, pipeline } } - pub fn set_view(&mut self, queue: &wgpu::Queue, vertices: &[Vertex; 4]) { - queue.write_buffer(&self.view_buf, 0, bytes_of(vertices)); - } - - pub fn render(&self, pass: &mut wgpu::RenderPass, data: &TracerData, env: &TracerEnv, params: Params) { + pub fn render( + &self, + pass: &mut wgpu::RenderPass, + data: &TracerData, + env: &TracerEnv, + params: Params, + camera: CameraLocation, + ) { pass.set_pipeline(&self.pipeline); - pass.set_push_constants(wgpu::ShaderStages::FRAGMENT, 0, bytes_of(¶ms)); + pass.set_push_constants( + wgpu::ShaderStages::FRAGMENT, + 0, + bytes_of(&ParamsData { + params, + camera: camera.into(), + }), + ); pass.set_vertex_buffer(0, self.view_buf.slice(..)); pass.set_bind_group(0, &data.bindings, &[]); pass.set_bind_group(1, &env.bindings, &[]); diff --git a/src/bin/minitracer/trace.wgsl b/src/bin/minitracer/trace.wgsl index 5f47d8e..33571cc 100644 --- a/src/bin/minitracer/trace.wgsl +++ b/src/bin/minitracer/trace.wgsl @@ -3,6 +3,8 @@ struct Params { min_strength: f32, sphere_count: i32, seed: u32, + view: mat3x3f, + eye: vec3f, } struct Sphere { @@ -14,9 +16,7 @@ struct Sphere { } struct Vertex { - @location(0) eye: vec3f, - @location(1) world: vec3f, - @location(2) screen: vec2f, + @location(0) screen: vec2f, } struct Varying { @@ -32,7 +32,7 @@ var params: Params; @vertex fn on_vertex(in: Vertex) -> Varying { - return Varying(in.eye, in.world, vec4(in.screen, 0.0, 1.0)); + return Varying(params.eye, params.eye + params.view * vec3(1.0, in.screen), vec4(in.screen, 0.0, 1.0)); } @fragment