Basic point lights

This commit is contained in:
marceline-cramer 2022-02-01 23:36:48 -07:00
parent a3cdf9ef2a
commit 70336446ac
4 changed files with 130 additions and 19 deletions

View File

@ -229,8 +229,27 @@ fn main() {
// let mut state: Box<dyn WorldState> = Box::new(Planets::new(&mut ren));
let mut state: Box<dyn WorldState> = 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,

View File

@ -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<MeshInstance>,
point_lights: &Vec<PointLight>,
) -> 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<PointLightUniform> = 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(),
}
}
}

View File

@ -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,
}

View File

@ -10,6 +10,16 @@ struct MeshData {
instances: array<MeshInstance>;
};
struct PointLight {
center: vec4<f32>;
intensity: vec4<f32>;
};
struct PointLightData {
num: i32;
lights: array<PointLight>;
};
struct VertexInput {
[[location(0)]] position: vec3<f32>;
[[location(1)]] tex_coords: vec2<f32>;
@ -17,12 +27,16 @@ struct VertexInput {
struct VertexOutput {
[[builtin(position)]] clip_position: vec4<f32>;
[[location(0)]] tex_coords: vec2<f32>;
[[location(0)]] position: vec3<f32>;
[[location(1)]] tex_coords: vec2<f32>;
};
[[group(0), binding(0)]]
var<uniform> camera: CameraUniform;
[[group(0), binding(1)]]
var<storage,read> point_lights: PointLightData;
[[group(1), binding(0)]]
var<storage,read> meshes: MeshData;
@ -35,8 +49,11 @@ fn vs_main(
vertex: VertexInput,
) -> VertexOutput {
let transform = meshes.instances[mesh_idx].transform;
let world_pos = transform * vec4<f32>(vertex.position, 1.0);
var out: VertexOutput;
out.clip_position = camera.vp * transform * vec4<f32>(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<f32> {
return textureSample(t_albedo, s_albedo, frag.tex_coords);
let albedo = textureSample(t_albedo, s_albedo, frag.tex_coords).rgb;
var lum = vec3<f32>(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<f32>(lum, 1.0);
}