From 70336446ac5adf899e6edd158706b68e262400f0 Mon Sep 17 00:00:00 2001 From: marceline-cramer Date: Tue, 1 Feb 2022 23:36:48 -0700 Subject: [PATCH] Basic point lights --- src/main.rs | 21 +++++++++++- src/renderer.rs | 89 ++++++++++++++++++++++++++++++++++++++++--------- src/scene.rs | 6 ++++ src/shader.wgsl | 33 ++++++++++++++++-- 4 files changed, 130 insertions(+), 19 deletions(-) diff --git a/src/main.rs b/src/main.rs index 21fcfd8..8278897 100644 --- a/src/main.rs +++ b/src/main.rs @@ -229,8 +229,27 @@ fn main() { // let mut state: Box = Box::new(Planets::new(&mut ren)); let mut state: Box = Box::new(Grid::new(&mut ren)); + let lights = vec![ + PointLight { + center: glam::Vec3A::new(0.0, 5.0, 0.0), + intensity: glam::Vec3A::new(100.0, 100.0, 100.0), + }, + PointLight { + center: glam::Vec3A::new(-7.0, 5.0, 7.0), + intensity: glam::Vec3A::new(100.0, 0.0, 0.0), + }, + PointLight { + center: glam::Vec3A::new(7.0, 5.0, 7.0), + intensity: glam::Vec3A::new(0.0, 100.0, 0.0), + }, + PointLight { + center: glam::Vec3A::new(0.0, 5.0, -7.0), + intensity: glam::Vec3A::new(0.0, 0.0, 100.0), + }, + ]; + event_loop.run(move |event, _, control_flow| match event { - Event::RedrawRequested(_) => match ren.render(&camera, &state.render()) { + Event::RedrawRequested(_) => match ren.render(&camera, &state.render(), &lights) { Ok(_) => {} Err(wgpu::SurfaceError::Lost) => ren.resize(ren.size), Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit, diff --git a/src/renderer.rs b/src/renderer.rs index b331f56..3f229e9 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -1,8 +1,8 @@ use super::camera::Camera; -use super::commands::{CommandSet, Command}; +use super::commands::{Command, CommandSet}; use super::mesh::Vertex; use super::pool::{MeshGroup, MeshPool, TexturePool}; -use super::scene::MeshInstance; +use super::scene::{MeshInstance, PointLight}; use wgpu::util::DeviceExt; pub struct Renderer { @@ -17,6 +17,7 @@ pub struct Renderer { depth_texture_view: wgpu::TextureView, camera_uniform: CameraUniform, camera_buffer: wgpu::Buffer, + point_lights_buffer: wgpu::Buffer, camera_bind_group: wgpu::BindGroup, meshes_buffer: wgpu::Buffer, meshes_bind_group: wgpu::BindGroup, @@ -44,27 +45,52 @@ impl Renderer { usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, }); + let point_lights_buffer = device.create_buffer(&wgpu::BufferDescriptor { + label: Some("Point Lights Buffer"), + size: 65536, // TODO buffer resizing + usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST, + mapped_at_creation: false, + }); + let camera_bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - 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, + 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, }, - count: None, - }], + wgpu::BindGroupLayoutEntry { + binding: 1, + visibility: wgpu::ShaderStages::VERTEX_FRAGMENT, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Storage { read_only: true }, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }, + ], label: Some("Camera Bind Group Layout"), }); let camera_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { layout: &camera_bind_group_layout, - entries: &[wgpu::BindGroupEntry { - binding: 0, - resource: camera_buffer.as_entire_binding(), - }], + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: camera_buffer.as_entire_binding(), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: point_lights_buffer.as_entire_binding(), + }, + ], label: Some("Camera Bind Group"), }); @@ -165,6 +191,7 @@ impl Renderer { depth_texture_view, camera_uniform, camera_buffer, + point_lights_buffer, camera_bind_group, meshes_buffer, meshes_bind_group, @@ -217,6 +244,7 @@ impl Renderer { &mut self, camera: &impl Camera, meshes: &Vec, + point_lights: &Vec, ) -> Result<(), wgpu::SurfaceError> { self.camera_uniform.update(camera); self.queue.write_buffer( @@ -231,6 +259,21 @@ impl Renderer { self.queue .write_buffer(&self.meshes_buffer, 0, mesh_commands.get_storage()); + let point_lights: Vec = point_lights.iter().map(|p| p.into()).collect(); + + // TODO make a function to ease arranging header + array data (this is really ugly) + // researching proper structure alignment will be necessary + self.queue.write_buffer( + &self.point_lights_buffer, + 0, + bytemuck::cast_slice(&[point_lights.len() as u32]), + ); + self.queue.write_buffer( + &self.point_lights_buffer, + 16, + bytemuck::cast_slice(&point_lights), + ); + let output = self.surface.get_current_texture()?; let view = output .texture @@ -320,3 +363,19 @@ impl CameraUniform { self.vp = camera.get_vp(); } } + +#[repr(C)] +#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] +struct PointLightUniform { + center: [f32; 4], + intensity: [f32; 4], +} + +impl From<&PointLight> for PointLightUniform { + fn from(p: &PointLight) -> Self { + Self { + center: p.center.extend(0.0).to_array(), + intensity: p.intensity.extend(0.0).to_array(), + } + } +} diff --git a/src/scene.rs b/src/scene.rs index 9ba2021..e594c24 100644 --- a/src/scene.rs +++ b/src/scene.rs @@ -6,3 +6,9 @@ pub struct MeshInstance { pub albedo: TextureHandle, pub transform: glam::Mat4, } + +#[derive(Copy, Clone, PartialEq)] +pub struct PointLight { + pub center: glam::Vec3A, + pub intensity: glam::Vec3A, +} diff --git a/src/shader.wgsl b/src/shader.wgsl index 3507734..a714970 100644 --- a/src/shader.wgsl +++ b/src/shader.wgsl @@ -10,6 +10,16 @@ struct MeshData { instances: array; }; +struct PointLight { + center: vec4; + intensity: vec4; +}; + +struct PointLightData { + num: i32; + lights: array; +}; + struct VertexInput { [[location(0)]] position: vec3; [[location(1)]] tex_coords: vec2; @@ -17,12 +27,16 @@ struct VertexInput { struct VertexOutput { [[builtin(position)]] clip_position: vec4; - [[location(0)]] tex_coords: vec2; + [[location(0)]] position: vec3; + [[location(1)]] tex_coords: vec2; }; [[group(0), binding(0)]] var camera: CameraUniform; +[[group(0), binding(1)]] +var point_lights: PointLightData; + [[group(1), binding(0)]] var meshes: MeshData; @@ -35,8 +49,11 @@ fn vs_main( vertex: VertexInput, ) -> VertexOutput { let transform = meshes.instances[mesh_idx].transform; + let world_pos = transform * vec4(vertex.position, 1.0); + var out: VertexOutput; - out.clip_position = camera.vp * transform * vec4(vertex.position, 1.0); + out.clip_position = camera.vp * world_pos; + out.position = world_pos.xyz; out.tex_coords = vertex.tex_coords; return out; } @@ -45,5 +62,15 @@ fn vs_main( fn fs_main( frag: VertexOutput, ) -> [[location(0)]] vec4 { - return textureSample(t_albedo, s_albedo, frag.tex_coords); + let albedo = textureSample(t_albedo, s_albedo, frag.tex_coords).rgb; + + var lum = vec3(0.0); + for(var i = 0; i < 4; i = i + 1) { + let light = point_lights.lights[i]; + let light_relative = frag.position - light.center.xyz; + let diffuse = albedo / dot(light_relative, light_relative); + lum = lum + (diffuse * light.intensity.rgb); + } + + return vec4(lum, 1.0); }