diff --git a/simulator/src/main.rs b/simulator/src/main.rs index 5032b39..269a491 100644 --- a/simulator/src/main.rs +++ b/simulator/src/main.rs @@ -22,6 +22,12 @@ pub async fn run() { let _ = event_loop.run_app(&mut window_state); } +#[repr(C)] +#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] +struct Globals { + aspect_ratio: f32, +} + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] enum Shape { Polygon, @@ -64,7 +70,7 @@ struct InstanceRaw { impl InstanceRaw { fn desc() -> wgpu::VertexBufferLayout<'static> { wgpu::VertexBufferLayout { - array_stride: std::mem::size_of::() as wgpu::BufferAddress, + array_stride: size_of::() as wgpu::BufferAddress, step_mode: wgpu::VertexStepMode::Instance, attributes: &[ wgpu::VertexAttribute { offset: 0, shader_location: 5, format: wgpu::VertexFormat::Float32x4 }, @@ -183,6 +189,8 @@ struct State<'a> { instance_buffer: wgpu::Buffer, geometries: HashMap, + global_bind_group: wgpu::BindGroup, + global_buffer: wgpu::Buffer, simulator: Arc>, } @@ -199,7 +207,37 @@ impl<'a> State<'a> { let config = Self::create_surface_config(size, surface_caps); surface.configure(&device, &config); - let render_pipeline = Self::create_render_pipeline(&device, &config); + let globals = Globals { + aspect_ratio: config.width as f32 / config.height as f32, + }; + let global_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("Global Uniform Buffer"), + contents: bytemuck::cast_slice(&[globals]), + usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, + }); + let global_bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("Global Bind Group Layout"), + entries: &[wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::VERTEX, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }], + }); + let global_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &global_bind_group_layout, + entries: &[wgpu::BindGroupEntry { + binding: 0, + resource: global_buffer.as_entire_binding(), + }], + label: Some("Global Bind Group"), + }); + + let render_pipeline = Self::create_render_pipeline(&device, &config, &global_bind_group_layout); let mut geometries = HashMap::new(); let polygon_vertices = vec![ @@ -306,6 +344,9 @@ impl<'a> State<'a> { config, size, window: window_arc, + + global_bind_group, + global_buffer, render_pipeline, geometries, @@ -342,7 +383,7 @@ impl<'a> State<'a> { self.instances = updated_instances; } - fn create_render_pipeline(device: &Device, config: &wgpu::SurfaceConfiguration) -> wgpu::RenderPipeline { + fn create_render_pipeline(device: &Device, config: &wgpu::SurfaceConfiguration, global_bind_group_layout: &wgpu::BindGroupLayout) -> wgpu::RenderPipeline { let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { label: Some("Shader"), source: wgpu::ShaderSource::Wgsl(include_str!("shader.wgsl").into()), @@ -351,7 +392,7 @@ impl<'a> State<'a> { let render_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("Render Pipeline Layout"), - bind_group_layouts: &[], + bind_group_layouts: &[&global_bind_group_layout], push_constant_ranges: &[], }); @@ -451,6 +492,11 @@ impl<'a> State<'a> { self.surface.configure(&self.device, &self.config); + let new_globals = Globals { + aspect_ratio: self.config.width as f32 / self.config.height as f32, + }; + self.queue.write_buffer(&self.global_buffer, 0, bytemuck::cast_slice(&[new_globals])); + println!("Resized to {:?} from state!", new_size); } @@ -484,6 +530,7 @@ impl<'a> State<'a> { }); render_pass.set_pipeline(&self.render_pipeline); + render_pass.set_bind_group(0, &self.global_bind_group, &[]); for shape in [Shape::Polygon, Shape::Circle] { let geometry = &self.geometries[&shape]; diff --git a/simulator/src/shader.wgsl b/simulator/src/shader.wgsl index 5c2fb18..b552f3b 100644 --- a/simulator/src/shader.wgsl +++ b/simulator/src/shader.wgsl @@ -16,6 +16,13 @@ struct VSOutput { @location(0) color: vec3, }; +struct Globals { + aspect_ratio: f32, +} + +@group(0) @binding(0) +var globals: Globals; + @vertex fn vs_main(vertex: VertexInput, instance: InstanceInput) -> VSOutput { var out: VSOutput; @@ -25,7 +32,14 @@ fn vs_main(vertex: VertexInput, instance: InstanceInput) -> VSOutput { instance.model_row2, instance.model_row3 ); - out.position = model * vec4(vertex.position, 1.0); + + let projection = mat4x4( + vec4(1.0 / globals.aspect_ratio, 0.0, 0.0, 0.0), + vec4(0.0, 1.0, 0.0, 0.0), + vec4(0.0, 0.0, 1.0, 0.0), + vec4(0.0, 0.0, 0.0, 1.0), + ); + out.position = projection * model * vec4(vertex.position, 1.0); out.color = instance.color; return out; }