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 bodies = &sim.bodies;
|
||||
|
||||
let sun_pos = (bodies[0].position / 1.496e11);
|
||||
|
||||
// let light_offset = Vector3::new(0.0, 0.0, 0.1);
|
||||
let sun_pos = bodies[0].position / 1.496e11;
|
||||
|
||||
state.light_manager.clear();
|
||||
state.light_manager.add_light(Light {
|
||||
@ -59,9 +57,9 @@ pub async fn run() {
|
||||
direction: Vector3::new(0.0, 0.0, 0.0),
|
||||
color: Vector3::from([1.0, 1.0, 0.8]),
|
||||
intensity: 5.0,
|
||||
range: 0.0,
|
||||
range: 1.0,
|
||||
inner_cutoff: 0.0,
|
||||
light_type: LightType::Directional,
|
||||
light_type: LightType::Point,
|
||||
outer_cutoff: 0.0,
|
||||
});
|
||||
|
||||
|
||||
@ -52,7 +52,14 @@ pub struct LightManager {
|
||||
pub lights: Vec<Light>,
|
||||
pub buffer: wgpu::Buffer,
|
||||
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 {
|
||||
@ -60,31 +67,58 @@ impl LightManager {
|
||||
let buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: Some("Light Buffer"),
|
||||
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,
|
||||
});
|
||||
|
||||
let layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
label: Some("Light Bind Group Layout"),
|
||||
entries: &[wgpu::BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,
|
||||
ty: wgpu::BindingType::Buffer {
|
||||
ty: wgpu::BufferBindingType::Uniform,
|
||||
has_dynamic_offset: false,
|
||||
min_binding_size: None,
|
||||
entries: &[
|
||||
// Binding 0: Storage buffer for lights
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
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,
|
||||
},
|
||||
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 {
|
||||
label: Some("Light Bind Group"),
|
||||
layout: &layout,
|
||||
entries: &[wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: buffer.as_entire_binding(),
|
||||
}],
|
||||
entries: &[
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: buffer.as_entire_binding(),
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 1,
|
||||
resource: count_buffer.as_entire_binding(),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
Self {
|
||||
@ -92,6 +126,7 @@ impl LightManager {
|
||||
buffer,
|
||||
bind_group,
|
||||
layout,
|
||||
count_buffer,
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,6 +137,11 @@ impl LightManager {
|
||||
pub fn update_gpu(&self, queue: &wgpu::Queue) {
|
||||
let data: Vec<GpuLight> = self.lights.iter().map(|l| l.to_gpu()).collect();
|
||||
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 {
|
||||
|
||||
@ -21,6 +21,13 @@ struct VSOutput {
|
||||
@location(3) flags: u32,
|
||||
};
|
||||
|
||||
struct LightCount {
|
||||
count: u32,
|
||||
};
|
||||
|
||||
@group(1) @binding(1)
|
||||
var<uniform> light_count: LightCount;
|
||||
|
||||
struct Globals {
|
||||
view_proj: mat4x4<f32>,
|
||||
}
|
||||
@ -30,12 +37,17 @@ var<uniform> globals: Globals;
|
||||
|
||||
struct GpuLight {
|
||||
position: vec3<f32>,
|
||||
light_type: u32,
|
||||
color: vec3<f32>,
|
||||
intensity: f32,
|
||||
direction: vec3<f32>,
|
||||
range: f32,
|
||||
inner_cutoff: f32,
|
||||
outer_cutoff: f32,
|
||||
};
|
||||
|
||||
@group(1) @binding(0)
|
||||
var<uniform> lights: array<GpuLight, 10>;
|
||||
var<storage, read> all_lights: array<GpuLight>;
|
||||
|
||||
@vertex
|
||||
fn vs_main(vertex: VertexInput, instance: InstanceInput) -> VSOutput {
|
||||
@ -66,22 +78,46 @@ fn vs_main(vertex: VertexInput, instance: InstanceInput) -> VSOutput {
|
||||
|
||||
@fragment
|
||||
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;
|
||||
|
||||
if (always_lit) {
|
||||
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;
|
||||
return vec4<f32>(final_color, 1.0);
|
||||
for (var i = 0u; i < light_count.count; i = i + 1u) {
|
||||
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