Implemented better light rendering and made the sun a point light
This commit is contained in:
parent
2b73b0ddce
commit
b9729874e2
@ -49,9 +49,7 @@ pub async fn run() {
|
|||||||
let sim = simulator_clone.read().unwrap();
|
let sim = simulator_clone.read().unwrap();
|
||||||
let bodies = &sim.bodies;
|
let bodies = &sim.bodies;
|
||||||
|
|
||||||
let sun_pos = (bodies[0].position / 1.496e11);
|
let sun_pos = bodies[0].position / 1.496e11;
|
||||||
|
|
||||||
// let light_offset = Vector3::new(0.0, 0.0, 0.1);
|
|
||||||
|
|
||||||
state.light_manager.clear();
|
state.light_manager.clear();
|
||||||
state.light_manager.add_light(Light {
|
state.light_manager.add_light(Light {
|
||||||
@ -59,9 +57,9 @@ pub async fn run() {
|
|||||||
direction: Vector3::new(0.0, 0.0, 0.0),
|
direction: Vector3::new(0.0, 0.0, 0.0),
|
||||||
color: Vector3::from([1.0, 1.0, 0.8]),
|
color: Vector3::from([1.0, 1.0, 0.8]),
|
||||||
intensity: 5.0,
|
intensity: 5.0,
|
||||||
range: 0.0,
|
range: 1.0,
|
||||||
inner_cutoff: 0.0,
|
inner_cutoff: 0.0,
|
||||||
light_type: LightType::Directional,
|
light_type: LightType::Point,
|
||||||
outer_cutoff: 0.0,
|
outer_cutoff: 0.0,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -52,7 +52,14 @@ pub struct LightManager {
|
|||||||
pub lights: Vec<Light>,
|
pub lights: Vec<Light>,
|
||||||
pub buffer: wgpu::Buffer,
|
pub buffer: wgpu::Buffer,
|
||||||
pub bind_group: wgpu::BindGroup,
|
pub bind_group: wgpu::BindGroup,
|
||||||
pub layout: wgpu::BindGroupLayout,
|
pub count_buffer: wgpu::Buffer,
|
||||||
|
pub layout: wgpu::BindGroupLayout
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone, Copy, Pod, Zeroable, Debug)]
|
||||||
|
pub struct LightCount {
|
||||||
|
pub count: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LightManager {
|
impl LightManager {
|
||||||
@ -60,31 +67,58 @@ impl LightManager {
|
|||||||
let buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
let buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||||
label: Some("Light Buffer"),
|
label: Some("Light Buffer"),
|
||||||
size: (max_lights * size_of::<GpuLight>()) as wgpu::BufferAddress,
|
size: (max_lights * size_of::<GpuLight>()) as wgpu::BufferAddress,
|
||||||
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
|
||||||
mapped_at_creation: false,
|
mapped_at_creation: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
let layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
let layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||||
label: Some("Light Bind Group Layout"),
|
label: Some("Light Bind Group Layout"),
|
||||||
entries: &[wgpu::BindGroupLayoutEntry {
|
entries: &[
|
||||||
binding: 0,
|
// Binding 0: Storage buffer for lights
|
||||||
visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,
|
wgpu::BindGroupLayoutEntry {
|
||||||
ty: wgpu::BindingType::Buffer {
|
binding: 0,
|
||||||
ty: wgpu::BufferBindingType::Uniform,
|
visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,
|
||||||
has_dynamic_offset: false,
|
ty: wgpu::BindingType::Buffer {
|
||||||
min_binding_size: None,
|
ty: wgpu::BufferBindingType::Storage { read_only: true },
|
||||||
|
has_dynamic_offset: false,
|
||||||
|
min_binding_size: None,
|
||||||
|
},
|
||||||
|
count: None,
|
||||||
},
|
},
|
||||||
count: None,
|
// Binding 1: Uniform buffer for light count
|
||||||
}],
|
wgpu::BindGroupLayoutEntry {
|
||||||
|
binding: 1,
|
||||||
|
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||||
|
ty: wgpu::BindingType::Buffer {
|
||||||
|
ty: wgpu::BufferBindingType::Uniform,
|
||||||
|
has_dynamic_offset: false,
|
||||||
|
min_binding_size: None,
|
||||||
|
},
|
||||||
|
count: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
let count_buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||||
|
label: Some("Light Count Buffer"),
|
||||||
|
size: size_of::<LightCount>() as wgpu::BufferAddress,
|
||||||
|
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
||||||
|
mapped_at_creation: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||||
label: Some("Light Bind Group"),
|
label: Some("Light Bind Group"),
|
||||||
layout: &layout,
|
layout: &layout,
|
||||||
entries: &[wgpu::BindGroupEntry {
|
entries: &[
|
||||||
binding: 0,
|
wgpu::BindGroupEntry {
|
||||||
resource: buffer.as_entire_binding(),
|
binding: 0,
|
||||||
}],
|
resource: buffer.as_entire_binding(),
|
||||||
|
},
|
||||||
|
wgpu::BindGroupEntry {
|
||||||
|
binding: 1,
|
||||||
|
resource: count_buffer.as_entire_binding(),
|
||||||
|
},
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
@ -92,6 +126,7 @@ impl LightManager {
|
|||||||
buffer,
|
buffer,
|
||||||
bind_group,
|
bind_group,
|
||||||
layout,
|
layout,
|
||||||
|
count_buffer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,6 +137,11 @@ impl LightManager {
|
|||||||
pub fn update_gpu(&self, queue: &wgpu::Queue) {
|
pub fn update_gpu(&self, queue: &wgpu::Queue) {
|
||||||
let data: Vec<GpuLight> = self.lights.iter().map(|l| l.to_gpu()).collect();
|
let data: Vec<GpuLight> = self.lights.iter().map(|l| l.to_gpu()).collect();
|
||||||
queue.write_buffer(&self.buffer, 0, bytemuck::cast_slice(&data));
|
queue.write_buffer(&self.buffer, 0, bytemuck::cast_slice(&data));
|
||||||
|
|
||||||
|
let count = LightCount {
|
||||||
|
count: self.lights.len() as u32,
|
||||||
|
};
|
||||||
|
queue.write_buffer(&self.count_buffer, 0, bytemuck::bytes_of(&count));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bind_group(&self) -> &wgpu::BindGroup {
|
pub fn bind_group(&self) -> &wgpu::BindGroup {
|
||||||
|
|||||||
@ -21,6 +21,13 @@ struct VSOutput {
|
|||||||
@location(3) flags: u32,
|
@location(3) flags: u32,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct LightCount {
|
||||||
|
count: u32,
|
||||||
|
};
|
||||||
|
|
||||||
|
@group(1) @binding(1)
|
||||||
|
var<uniform> light_count: LightCount;
|
||||||
|
|
||||||
struct Globals {
|
struct Globals {
|
||||||
view_proj: mat4x4<f32>,
|
view_proj: mat4x4<f32>,
|
||||||
}
|
}
|
||||||
@ -30,12 +37,17 @@ var<uniform> globals: Globals;
|
|||||||
|
|
||||||
struct GpuLight {
|
struct GpuLight {
|
||||||
position: vec3<f32>,
|
position: vec3<f32>,
|
||||||
|
light_type: u32,
|
||||||
color: vec3<f32>,
|
color: vec3<f32>,
|
||||||
intensity: f32,
|
intensity: f32,
|
||||||
|
direction: vec3<f32>,
|
||||||
|
range: f32,
|
||||||
|
inner_cutoff: f32,
|
||||||
|
outer_cutoff: f32,
|
||||||
};
|
};
|
||||||
|
|
||||||
@group(1) @binding(0)
|
@group(1) @binding(0)
|
||||||
var<uniform> lights: array<GpuLight, 10>;
|
var<storage, read> all_lights: array<GpuLight>;
|
||||||
|
|
||||||
@vertex
|
@vertex
|
||||||
fn vs_main(vertex: VertexInput, instance: InstanceInput) -> VSOutput {
|
fn vs_main(vertex: VertexInput, instance: InstanceInput) -> VSOutput {
|
||||||
@ -66,22 +78,46 @@ fn vs_main(vertex: VertexInput, instance: InstanceInput) -> VSOutput {
|
|||||||
|
|
||||||
@fragment
|
@fragment
|
||||||
fn fs_main(input: VSOutput) -> @location(0) vec4<f32> {
|
fn fs_main(input: VSOutput) -> @location(0) vec4<f32> {
|
||||||
var lighting: vec3<f32>;
|
var lighting: vec3<f32> = vec3<f32>(0.0);
|
||||||
|
|
||||||
let always_lit = (input.flags & 0x1u) != 0u;
|
let always_lit = (input.flags & 0x1u) != 0u;
|
||||||
|
|
||||||
if (always_lit) {
|
if (always_lit) {
|
||||||
return vec4<f32>(input.frag_color * 2.0, 1.0);
|
return vec4<f32>(input.frag_color * 2.0, 1.0);
|
||||||
} else {
|
|
||||||
lighting = vec3<f32>(0.0);
|
|
||||||
for (var i = 0u; i < 10u; i = i + 1u) {
|
|
||||||
let light = lights[i];
|
|
||||||
let light_dir = normalize(light.position - input.world_pos);
|
|
||||||
let diff = max(dot(input.normal, light_dir), 0.0);
|
|
||||||
lighting += light.color * light.intensity * diff;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let final_color = input.frag_color * lighting;
|
for (var i = 0u; i < light_count.count; i = i + 1u) {
|
||||||
return vec4<f32>(final_color, 1.0);
|
let light = all_lights[i];
|
||||||
|
var light_contrib: vec3<f32> = vec3<f32>(0.0);
|
||||||
|
|
||||||
|
let light_dir = normalize(light.position - input.world_pos);
|
||||||
|
let diff = max(dot(input.normal, light_dir), 0.0);
|
||||||
|
|
||||||
|
switch light.light_type {
|
||||||
|
case 0u: { // Directional
|
||||||
|
light_contrib = light.color * light.intensity * diff;
|
||||||
|
}
|
||||||
|
case 1u: { // Point
|
||||||
|
let dist = distance(light.position, input.world_pos);
|
||||||
|
if (dist < light.range) {
|
||||||
|
let attenuation = 1.0 / (dist * dist);
|
||||||
|
light_contrib = light.color * light.intensity * diff * attenuation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 2u: { // Spot
|
||||||
|
let spot_dir = normalize(-light.direction);
|
||||||
|
let angle = dot(spot_dir, light_dir);
|
||||||
|
if (angle > light.outer_cutoff) {
|
||||||
|
let intensity = clamp((angle - light.outer_cutoff) / (light.inner_cutoff - light.outer_cutoff), 0.0, 1.0);
|
||||||
|
let dist = distance(light.position, input.world_pos);
|
||||||
|
let attenuation = 1.0 / (dist * dist);
|
||||||
|
light_contrib = light.color * light.intensity * diff * attenuation * intensity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default: {}
|
||||||
|
}
|
||||||
|
|
||||||
|
lighting += light_contrib;
|
||||||
|
}
|
||||||
|
|
||||||
|
return vec4<f32>(input.frag_color * lighting, 1.0);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user