Compare commits

..

No commits in common. "f0b413d9aeb93087b7504cb5b4eed76e532918c1" and "f63a7ae86a2df6d73af315017a3a30761393ab2d" have entirely different histories.

9 changed files with 291 additions and 313 deletions

View File

@ -120,6 +120,21 @@ async fn main() {
Transform::from_xyz(0.0, 0.0, 0.0), Transform::from_xyz(0.0, 0.0, 0.0),
)); ));
/* world.spawn((
separate_scene.clone(),
Transform::from_xyz(0.0, -5.0, -10.0),
)); */
/* {
let cube_tran = Transform::from_xyz(-5.9026427, -1.8953488, -10.0);
//cube_tran.rotate_y(math::Angle::Degrees(180.0));
world.spawn((
cube_tran,
crate_mesh.clone(),
CubeFlag,
));
} */
{ {
let mut light_tran = Transform::from_xyz(1.5, 2.5, 0.0); let mut light_tran = Transform::from_xyz(1.5, 2.5, 0.0);
light_tran.scale = Vec3::new(0.5, 0.5, 0.5); light_tran.scale = Vec3::new(0.5, 0.5, 0.5);
@ -127,27 +142,36 @@ async fn main() {
light_tran.rotate_y(math::Angle::Degrees(25.0)); light_tran.rotate_y(math::Angle::Degrees(25.0));
world.spawn(( world.spawn((
DirectionalLight { DirectionalLight {
enabled: false, color: Vec3::new(1.0, 1.0, 1.0),
color: Vec3::ONE, ambient: 0.3,
intensity: 0.35 diffuse: 1.0,
//..Default::default() specular: 1.3,
}, },
light_tran, light_tran,
//cube_mesh.clone(),
)); ));
} }
{ {
//let mut light_tran = Transform::from_xyz(-3.5, 0.2, -4.5);
//light_tran.scale = Vec3::new(0.5, 0.5, 0.5);
world.spawn(( world.spawn((
PointLight { PointLight {
enabled: true,
color: Vec3::new(0.0, 0.0, 1.0), color: Vec3::new(0.0, 0.0, 1.0),
intensity: 1.0,
range: 2.0, intensity: 3.3,
..Default::default()
constant: 1.0,
linear: 0.09,
quadratic: 0.032,
ambient: 0.2,
diffuse: 1.0,
specular: 1.3,
}, },
Transform::new( Transform::new(
//Vec3::new(-5.0, 1.0, -1.28), //Vec3::new(-5.0, 1.0, -1.28),
Vec3::new(-5.0, 1.0, -0.0), Vec3::new(-5.0, 1.0, -0.28),
//Vec3::new(-10.0, 0.94, -0.28), //Vec3::new(-10.0, 0.94, -0.28),
Quat::IDENTITY, Quat::IDENTITY,
@ -155,44 +179,6 @@ async fn main() {
), ),
cube_mesh.clone(), cube_mesh.clone(),
)); ));
world.spawn((
PointLight {
enabled: true,
color: Vec3::new(0.0, 0.5, 1.0),
intensity: 1.0,
range: 1.0,
..Default::default()
},
Transform::new(
Vec3::new(-3.0, 0.2, -1.5),
//Vec3::new(-5.0, 1.0, -0.28),
//Vec3::new(-10.0, 0.94, -0.28),
Quat::IDENTITY,
Vec3::new(0.15, 0.15, 0.15),
),
cube_mesh.clone(),
));
/* world.spawn((
SpotLight {
enabled: true,
color: Vec3::new(1.0, 0.0, 0.0),
intensity: 1.0,
range: 1.5,
..Default::default()
},
Transform::new(
Vec3::new(0.0, 0.2, -1.5),
//Vec3::new(-5.0, 1.0, -0.28),
//Vec3::new(-10.0, 0.94, -0.28),
Quat::IDENTITY,
Vec3::new(0.15, 0.15, 0.15),
),
cube_mesh.clone(),
)); */
} }
/* { /* {

View File

@ -1,18 +1,11 @@
use lyra_ecs::Component; use lyra_ecs::Component;
#[derive(Debug, Clone, Component)] #[derive(Default, Debug, Clone, Component)]
pub struct DirectionalLight { pub struct DirectionalLight {
pub enabled: bool, //pub direction: glam::Quat,
pub color: glam::Vec3, pub color: glam::Vec3,
pub intensity: f32,
}
impl Default for DirectionalLight { pub ambient: f32,
fn default() -> Self { pub diffuse: f32,
Self { pub specular: f32,
enabled: true,
color: glam::Vec3::new(1.0, 1.0, 1.0),
intensity: 1.0,
}
}
} }

View File

@ -6,7 +6,7 @@ use lyra_ecs::{Entity, Tick, World, query::{Entities, TickOf}};
pub use point::*; pub use point::*;
pub use spotlight::*; pub use spotlight::*;
use std::{collections::{HashMap, VecDeque}, marker::PhantomData, mem}; use std::{collections::{HashMap, VecDeque}, marker::PhantomData};
use crate::math::Transform; use crate::math::Transform;
@ -103,14 +103,13 @@ pub(crate) struct LightUniformBuffers {
pub buffer: wgpu::Buffer, pub buffer: wgpu::Buffer,
pub bind_group_pair: BindGroupPair, pub bind_group_pair: BindGroupPair,
pub light_indexes: HashMap<Entity, u32>, pub light_indexes: HashMap<Entity, u32>,
dead_indices: VecDeque<u32>,
pub current_light_idx: u32, pub current_light_idx: u32,
} }
impl LightUniformBuffers { impl LightUniformBuffers {
pub fn new(device: &wgpu::Device) -> Self { pub fn new(device: &wgpu::Device) -> Self {
let limits = device.limits(); let limits = device.limits();
// TODO: ensure we dont write over this limit // TODO: check this limit somehow
let max_buffer_sizes = (limits.max_uniform_buffer_binding_size as u64) / 2; let max_buffer_sizes = (limits.max_uniform_buffer_binding_size as u64) / 2;
let buffer = device.create_buffer( let buffer = device.create_buffer(
@ -162,88 +161,45 @@ impl LightUniformBuffers {
bind_group_pair: BindGroupPair::new(bindgroup, bindgroup_layout), bind_group_pair: BindGroupPair::new(bindgroup, bindgroup_layout),
light_indexes: Default::default(), light_indexes: Default::default(),
current_light_idx: 0, current_light_idx: 0,
dead_indices: VecDeque::new(),
} }
} }
/// Returns the index for the entity, and if this index is new
fn get_index_for(&mut self, missed: &mut HashMap<Entity, u32>, entity: Entity) -> (bool, u32) {
let idx = missed.remove(&entity)
.map(|v| (false, v))
.or_else(||
self.dead_indices.pop_front()
.map(|v| (true, v))
)
.unwrap_or_else(|| {
let t = self.current_light_idx;
self.current_light_idx += 1;
(true, t)
});
idx
}
pub fn update_lights(&mut self, queue: &wgpu::Queue, world_tick: Tick, world: &World) { pub fn update_lights(&mut self, queue: &wgpu::Queue, world_tick: Tick, world: &World) {
// used to detect what lights were removed let mut lights = LightsUniform::default();
let mut missed_lights: HashMap<Entity, u32> = self.light_indexes.drain().collect();
for (entity, point_light, transform, light_epoch, transform_epoch) for (entity, point_light, transform, light_epoch, transform_epoch)
in world.view_iter::<(Entities, &PointLight, &Transform, TickOf<PointLight>, TickOf<Transform>)>() { in world.view_iter::<(Entities, &PointLight, &Transform, TickOf<PointLight>, TickOf<Transform>)>() {
let (new, idx) = self.get_index_for(&mut missed_lights, entity); // TODO: dont update light every frame
self.light_indexes.insert(entity, idx); let idx = *self.light_indexes.entry(entity)
.or_insert_with(|| {
let t = self.current_light_idx;
self.current_light_idx += 1;
t
}) as usize;
if new || light_epoch == world_tick || transform_epoch == world_tick {
let uniform = LightUniform::from_point_light_bundle(&point_light, &transform); let uniform = LightUniform::from_point_light_bundle(&point_light, &transform);
lights.data[idx] = uniform;
let offset = mem::size_of::<u32>() * 4 + mem::size_of::<LightUniform>() * idx as usize;
queue.write_buffer(&self.buffer, offset as _, bytemuck::cast_slice(&[uniform]));
}
} }
for (entity, spot_light, transform, light_epoch, transform_epoch) if let Some((entity, dir_light, transform)) =
in world.view_iter::<(Entities, &SpotLight, &Transform, TickOf<SpotLight>, TickOf<Transform>)>() { world.view_iter::<(Entities, &DirectionalLight, &Transform)>().next() {
let (new, idx) = self.get_index_for(&mut missed_lights, entity); let idx = *self.light_indexes.entry(entity)
self.light_indexes.insert(entity, idx); .or_insert_with(|| {
let t = self.current_light_idx;
self.current_light_idx += 1;
t
}) as usize;
if new || light_epoch == world_tick || transform_epoch == world_tick {
let uniform = LightUniform::from_spot_light_bundle(&spot_light, &transform);
let offset = mem::size_of::<u32>() * 4 + mem::size_of::<LightUniform>() * idx as usize;
queue.write_buffer(&self.buffer, offset as _, bytemuck::cast_slice(&[uniform]));
}
}
for (entity, dir_light, transform, light_epoch, transform_epoch)
in world.view_iter::<(Entities, &DirectionalLight, &Transform, TickOf<DirectionalLight>, TickOf<Transform>)>() {
let (new, idx) = self.get_index_for(&mut missed_lights, entity);
self.light_indexes.insert(entity, idx);
if new || light_epoch == world_tick || transform_epoch == world_tick {
let uniform = LightUniform::from_directional_bundle(&dir_light, &transform); let uniform = LightUniform::from_directional_bundle(&dir_light, &transform);
let offset = mem::size_of::<u32>() * 4 + mem::size_of::<LightUniform>() * idx as usize; lights.data[idx] = uniform;
queue.write_buffer(&self.buffer, offset as _, bytemuck::cast_slice(&[uniform]));
}
} }
// anything left in missed_lights were lights that were deleted lights.light_count = self.light_indexes.len() as u32;
let len = missed_lights.len();
self.dead_indices.reserve(len);
for (_, v) in missed_lights.drain() { // update the light count in the struct
// write zeros in place of this now dead light, the enabled boolean will be set to false queue.write_buffer(&self.buffer, 0, bytemuck::cast_slice(&[lights]));
let mut zeros = Vec::new();
zeros.resize(mem::size_of::<LightUniform>(), 0u32);
let offset = mem::size_of::<u32>() * 4 + mem::size_of::<LightUniform>() * v as usize;
queue.write_buffer(&self.buffer, offset as _, bytemuck::cast_slice(zeros.as_slice()));
self.dead_indices.push_back(v);
}
// update the amount of lights, then the array of lights
queue.write_buffer(&self.buffer, 0, bytemuck::cast_slice(&[self.current_light_idx as u32]));
} }
} }
@ -260,7 +216,7 @@ pub(crate) enum LightType {
#[derive(Default, Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] #[derive(Default, Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
pub(crate) struct LightUniform { pub(crate) struct LightUniform {
pub position: glam::Vec3, pub position: glam::Vec3,
pub light_type: u32, // enum LightType pub light_type: u32, // LightType
pub direction: glam::Vec3, pub direction: glam::Vec3,
pub enabled: u32, // bool pub enabled: u32, // bool
pub color: glam::Vec3, pub color: glam::Vec3,
@ -269,64 +225,229 @@ pub(crate) struct LightUniform {
pub range: f32, pub range: f32,
pub intensity: f32, pub intensity: f32,
pub smoothness: f32,
pub spot_cutoff_rad: f32, pub spot_cutoff: f32,
pub spot_outer_cutoff_rad: f32, pub spot_outer_cutoff: f32,
pub _padding4: u32,
} }
impl LightUniform { impl LightUniform {
pub fn from_point_light_bundle(light: &PointLight, transform: &Transform) -> Self { pub fn from_point_light_bundle(light: &PointLight, transform: &Transform) -> Self {
Self { Self {
light_type: LightType::Point as u32, light_type: LightType::Point as u32,
enabled: light.enabled as u32, enabled: true as u32, // TODO
position: transform.translation, position: transform.translation,
direction: transform.forward(), direction: transform.forward(),
color: light.color, color: light.color,
range: light.range, range: 1.5,
intensity: light.intensity, intensity: 1.0,
smoothness: light.smoothness,
spot_cutoff_rad: 0.0, spot_cutoff: 0.0,
spot_outer_cutoff_rad: 0.0, spot_outer_cutoff: 0.0,
_padding4: 0,
} }
} }
pub fn from_directional_bundle(light: &DirectionalLight, transform: &Transform) -> Self { pub fn from_directional_bundle(light: &DirectionalLight, transform: &Transform) -> Self {
Self { Self {
light_type: LightType::Directional as u32, light_type: LightType::Directional as u32,
enabled: light.enabled as u32, enabled: true as u32, // TODO: take from component
position: transform.translation, position: transform.translation,
direction: transform.forward(), direction: transform.forward(),
color: light.color, color: light.color,
range: 0.0, range: 0.0,
intensity: light.intensity, intensity: 0.0,
smoothness: 0.0,
spot_cutoff_rad: 0.0, spot_cutoff: 0.0,
spot_outer_cutoff_rad: 0.0, spot_outer_cutoff: 0.0,
_padding4: 0,
} }
} }
// Create the SpotLightUniform from an ECS bundle // Create the SpotLightUniform from an ECS bundle
pub fn from_spot_light_bundle(light: &SpotLight, transform: &Transform) -> Self { /* pub fn from_bundle(light: &SpotLight, transform: &Transform) -> Self {
Self { Self {
light_type: LightType::Spotlight as u32,
enabled: light.enabled as u32,
position: transform.translation, position: transform.translation,
_padding: 0,
direction: transform.forward(), direction: transform.forward(),
_padding2: 0,
color: light.color, color: light.color,
cutoff: light.cutoff.to_radians().cos(),
outer_cutoff: light.outer_cutoff.to_radians().cos(),
constant: light.constant,
linear: light.linear,
quadratic: light.quadratic,
ambient: light.ambient,
diffuse: light.diffuse,
specular: light.specular,
_padding3: 0,
}
} */
}
range: light.range, #[repr(C)]
#[derive(Default, Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
pub struct LightsUniform {
light_count: u32,
_padding: [u32; 3],
data: [LightUniform; 10], // TODO: make this a dynamic length
}
/* #[repr(C)]
#[derive(Default, Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
pub struct LightsUniform {
light_count: u32,
_padding: [u32; 3],
spot_lights: [SpotLightUniform; MAX_LIGHT_COUNT],
spot_light_count: u32,
_padding2: [u32; 3],
directional_light: DirectionalLightUniform,
}
#[repr(C)]
#[derive(Default, Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
pub struct PointLightUniform {
/// The position of the light
/// vec4 is used here for gpu padding, w is ignored in the shader
pub position: glam::Vec4,
/// The color of the light
/// vec4 is used here for gpu padding, w is ignored in the shader
pub color: glam::Vec4,
/// The intensity of the light
/// This works by just multiplying the result of the lighting
/// calculations by this scalar
pub intensity: f32,
/// The constant used in the quadratic attenuation calculation. Its best to leave this at 1.0
pub constant: f32,
/// The linear factor used in the quadratic attenuation calculation.
pub linear: f32,
/// The quadratic factor used in the quadratic attenuation calculation.
pub quadratic: f32,
pub ambient: f32,
pub diffuse: f32,
pub specular: f32,
pub _padding: u32,
}
impl PointLightUniform {
/// Create the PointLightUniform from an ECS bundle
pub fn from_bundle(light: &PointLight, transform: &Transform) -> Self {
Self {
position: glam::Vec4::new(transform.translation.x, transform.translation.y, transform.translation.z, 0.0),
//_padding: 0,
color: glam::Vec4::new(light.color.x, light.color.y, light.color.z, 0.0),
//_padding2: 0,
intensity: light.intensity, intensity: light.intensity,
smoothness: light.smoothness, constant: light.constant,
linear: light.linear,
quadratic: light.quadratic,
spot_cutoff_rad: light.cutoff.to_radians(), ambient: light.ambient,
spot_outer_cutoff_rad: light.outer_cutoff.to_radians(), diffuse: light.diffuse,
specular: light.specular,
_padding: 0,
} }
} }
} }
#[repr(C)]
#[derive(Default, Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
pub struct DirectionalLightUniform {
/// The direction of the light
pub direction: glam::Vec3,
// gpu padding
pub _padding: u32,
/// The color of the light
pub color: glam::Vec3,
// no padding is needed here since ambient acts as the padding
// that would usually be needed for the vec3
/// The scalar of the ambient light created by this caster.
pub ambient: f32,
/// The scalar of the diffuse light created by this caster.
pub diffuse: f32,
/// The scalar of the specular reflections created by this caster.
pub specular: f32,
pub _padding2: [u32; 2],
}
impl DirectionalLightUniform {
/// Create the DirectionalLightUniform from an ECS bundle
pub fn from_bundle(light: &DirectionalLight, transform: &Transform) -> Self {
//transform.forward()
Self {
direction: transform.forward(),
_padding: 0,
color: light.color,
ambient: light.ambient,
diffuse: light.diffuse,
specular: light.specular,
_padding2: [0; 2],
}
}
}
#[repr(C)]
#[derive(Default, Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
pub(crate) struct SpotLightUniform {
pub position: glam::Vec3,
pub _padding: u32,
pub direction: glam::Vec3,
pub _padding2: u32,
pub color: glam::Vec3,
// no padding is needed here since cutoff acts as the padding
// that would usually be needed for the vec3
pub cutoff: f32,
pub outer_cutoff: f32,
/// The constant used in the quadratic attenuation calculation. Its best to leave this at 1.0
pub constant: f32,
/// The linear factor used in the quadratic attenuation calculation.
pub linear: f32,
/// The quadratic factor used in the quadratic attenuation calculation.
pub quadratic: f32,
pub ambient: f32,
pub diffuse: f32,
pub specular: f32,
pub _padding3: u32,
}
impl SpotLightUniform {
/// Create the SpotLightUniform from an ECS bundle
pub fn from_bundle(light: &SpotLight, transform: &Transform) -> Self {
Self {
position: transform.translation,
_padding: 0,
direction: transform.forward(),
_padding2: 0,
color: light.color,
cutoff: light.cutoff.to_radians().cos(),
outer_cutoff: light.outer_cutoff.to_radians().cos(),
constant: light.constant,
linear: light.linear,
quadratic: light.quadratic,
ambient: light.ambient,
diffuse: light.diffuse,
specular: light.specular,
_padding3: 0,
}
}
} */

View File

@ -1,22 +1,13 @@
use lyra_ecs::Component; use lyra_ecs::Component;
#[derive(Debug, Clone, Component)] #[derive(Default, Debug, Clone, Component)]
pub struct PointLight { pub struct PointLight {
pub enabled: bool,
pub color: glam::Vec3, pub color: glam::Vec3,
pub range: f32,
pub intensity: f32, pub intensity: f32,
pub smoothness: f32, pub constant: f32,
} pub linear: f32,
pub quadratic: f32,
impl Default for PointLight { pub ambient: f32,
fn default() -> Self { pub diffuse: f32,
Self { pub specular: f32,
enabled: true,
color: glam::Vec3::new(1.0, 1.0, 1.0),
range: 1.0,
intensity: 1.0,
smoothness: 0.75,
}
}
} }

View File

@ -4,26 +4,15 @@ use crate::math;
#[derive(Debug, Clone, Component)] #[derive(Debug, Clone, Component)]
pub struct SpotLight { pub struct SpotLight {
pub enabled: bool,
pub color: glam::Vec3, pub color: glam::Vec3,
pub range: f32,
pub intensity: f32,
pub smoothness: f32,
pub cutoff: math::Angle, pub cutoff: math::Angle,
pub outer_cutoff: math::Angle, pub outer_cutoff: math::Angle,
}
impl Default for SpotLight { pub constant: f32,
fn default() -> Self { pub linear: f32,
Self { pub quadratic: f32,
enabled: true,
color: glam::Vec3::new(1.0, 1.0, 1.0),
range: 1.0,
intensity: 1.0,
smoothness: 0.75,
cutoff: math::Angle::Degrees(45.0), pub ambient: f32,
outer_cutoff: math::Angle::Degrees(45.0), pub diffuse: f32,
} pub specular: f32,
}
} }

View File

@ -6,7 +6,6 @@ use winit::dpi::PhysicalSize;
use super::{light::LightUniformBuffers, render_buffer::{BindGroupPair, BufferWrapper}, texture::RenderTexture}; use super::{light::LightUniformBuffers, render_buffer::{BindGroupPair, BufferWrapper}, texture::RenderTexture};
#[allow(dead_code)]
pub(crate) struct LightIndicesGridBuffer { pub(crate) struct LightIndicesGridBuffer {
index_counter_buffer: wgpu::Buffer, index_counter_buffer: wgpu::Buffer,
indices_buffer: wgpu::Buffer, indices_buffer: wgpu::Buffer,
@ -83,6 +82,7 @@ impl LightCullCompute {
label: Some("BGL_LightIndicesGrid"), label: Some("BGL_LightIndicesGrid"),
}); });
// TODO: resize texture when screen is resized
let size = wgpu::Extent3d { let size = wgpu::Extent3d {
width: workgroup_size.x, width: workgroup_size.x,
height: workgroup_size.y, height: workgroup_size.y,
@ -167,8 +167,7 @@ impl LightCullCompute {
source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(shader_src)), source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(shader_src)),
}); });
let workgroup_size = glam::UVec2::new((screen_size.width as f32 / 16.0).ceil() as u32, let workgroup_size = glam::UVec2::new((screen_size.width as f32 / 16.0).ceil() as u32, (screen_size.height as f32 / 16.0).ceil() as u32);
(screen_size.height as f32 / 16.0).ceil() as u32);
let light_grid = Self::create_grid(&device, workgroup_size); let light_grid = Self::create_grid(&device, workgroup_size);
let depth_tex_pair = depth_texture.create_bind_group(&device); let depth_tex_pair = depth_texture.create_bind_group(&device);
@ -205,11 +204,7 @@ impl LightCullCompute {
pub fn update_screen_size(&mut self, size: PhysicalSize<u32>) { pub fn update_screen_size(&mut self, size: PhysicalSize<u32>) {
self.screen_size_buffer.write_buffer(&self.queue, 0, self.screen_size_buffer.write_buffer(&self.queue, 0,
&[UVec2::new(size.width, size.height)]); &[UVec2::new(size.width, size.height)]);
self.workgroup_size = glam::UVec2::new((size.width as f32 / 16.0).ceil() as u32, self.workgroup_size = glam::UVec2::new((size.width as f32 / 16.0).ceil() as u32, (size.height as f32 / 16.0).ceil() as u32);
(size.height as f32 / 16.0).ceil() as u32);
// I hate that the entire bind group is recreated on a resize but its the only way :(
self.light_indices_grid = Self::create_grid(&self.device, self.workgroup_size);
} }
pub fn compute(&mut self, camera_buffers: &BufferWrapper, lights_buffers: &LightUniformBuffers, depth_texture: &RenderTexture) { pub fn compute(&mut self, camera_buffers: &BufferWrapper, lights_buffers: &LightUniformBuffers, depth_texture: &RenderTexture) {
@ -232,7 +227,6 @@ impl LightCullCompute {
pass.dispatch_workgroups(self.workgroup_size.x, self.workgroup_size.y, 1); pass.dispatch_workgroups(self.workgroup_size.x, self.workgroup_size.y, 1);
} }
self.queue.submit(std::iter::once(encoder.finish())); self.queue.submit(std::iter::once(encoder.finish()));
self.device.poll(wgpu::Maintain::Wait); self.device.poll(wgpu::Maintain::Wait);
self.cleanup(); self.cleanup();

View File

@ -35,7 +35,6 @@ struct Light {
range: f32, range: f32,
intensity: f32, intensity: f32,
smoothness: f32,
spot_cutoff: f32, spot_cutoff: f32,
spot_outer_cutoff: f32, spot_outer_cutoff: f32,
@ -201,7 +200,7 @@ fn blinn_phong_dir_light(world_pos: vec3<f32>, world_norm: vec3<f32>, dir_light:
diffuse_color *= dir_light.diffuse; diffuse_color *= dir_light.diffuse;
specular_color *= dir_light.specular;*/ specular_color *= dir_light.specular;*/
return (ambient_color + diffuse_color + specular_color) * dir_light.intensity; return ambient_color + diffuse_color + specular_color;
} }
fn blinn_phong_point_light(world_pos: vec3<f32>, world_norm: vec3<f32>, point_light: Light, material: Material, specular_factor: vec3<f32>) -> vec3<f32> { fn blinn_phong_point_light(world_pos: vec3<f32>, world_norm: vec3<f32>, point_light: Light, material: Material, specular_factor: vec3<f32>) -> vec3<f32> {
@ -227,8 +226,22 @@ fn blinn_phong_point_light(world_pos: vec3<f32>, world_norm: vec3<f32>, point_li
var specular_color = specular_strength * (light_color * specular_factor); var specular_color = specular_strength * (light_color * specular_factor);
//// end of specular //// //// end of specular ////
// TODO: Point light range
let distance = length(light_pos - world_pos); let distance = length(light_pos - world_pos);
let attenuation = 1.0 - smoothstep(point_light.range * point_light.smoothness, point_light.range, distance); // TODO: make smoothness in this a configurable value
// 0.75 is the smoothness or falloff
let attenuation = 1.0 - smoothstep(point_light.range * 0.75, point_light.range, distance);
//// point light attenuation ////
/*let distance = length(light_pos - world_pos);
let attenuation = 1.0 / (point_light.constant + point_light.linear * distance +
point_light.quadratic * (distance * distance));
//// end of point light attenuation ////
ambient_color *= point_light.ambient * attenuation;
diffuse_color *= point_light.diffuse * attenuation;
specular_color *= point_light.specular * attenuation;*/
ambient_color *= attenuation; ambient_color *= attenuation;
diffuse_color *= attenuation; diffuse_color *= attenuation;
@ -238,50 +251,5 @@ fn blinn_phong_point_light(world_pos: vec3<f32>, world_norm: vec3<f32>, point_li
} }
fn blinn_phong_spot_light(world_pos: vec3<f32>, world_norm: vec3<f32>, spot_light: Light, material: Material, specular_factor: vec3<f32>) -> vec3<f32> { fn blinn_phong_spot_light(world_pos: vec3<f32>, world_norm: vec3<f32>, spot_light: Light, material: Material, specular_factor: vec3<f32>) -> vec3<f32> {
let light_color = spot_light.color; return vec3<f32>(0.0); // TODO
let light_pos = spot_light.position;
let camera_view_pos = u_camera.position;
let light_dir = normalize(spot_light.position - world_pos);
var ambient_color = light_color * material.ambient.xyz * material.diffuse.xyz;
//// diffuse ////
//let light_dir = normalize(light_pos - world_pos);
let diffuse_strength = max(dot(world_norm, light_dir), 0.0);
var diffuse_color = light_color * (diffuse_strength * material.diffuse.xyz);
//// end of diffuse ////
//// specular ////
let view_dir = normalize(camera_view_pos - world_pos);
let half_dir = normalize(view_dir + light_dir);
let specular_strength = pow(max(dot(world_norm, half_dir), 0.0), material.shininess);
var specular_color = specular_strength * (light_color * specular_factor);
//// end of specular ////
//// spot light soft edges ////
let theta = dot(light_dir, normalize(-spot_light.direction));
let epsilon = spot_light.spot_cutoff - spot_light.spot_outer_cutoff;
let intensity = clamp((theta - spot_light.spot_outer_cutoff) / epsilon, 0.0, 1.0);
//diffuse_color *= intensity;
//specular_color *= intensity;
//// end of spot light soft edges ////
//// spot light attenuation ////
let distance = length(light_pos - world_pos);
let attenuation = calc_attenuation(spot_light, distance);
ambient_color *= attenuation * intensity;
diffuse_color *= attenuation * intensity;
specular_color *= attenuation * intensity;
//// end of spot light attenuation ////
return /*ambient_color +*/ diffuse_color + specular_color;
}
fn calc_attenuation(light: Light, distance: f32) -> f32 {
return 1.0 - smoothstep(light.range * light.smoothness, light.range, distance);
} }

View File

@ -22,7 +22,6 @@ struct Light {
range: f32, range: f32,
intensity: f32, intensity: f32,
smoothness: f32,
spot_cutoff: f32, spot_cutoff: f32,
spot_outer_cutoff: f32, spot_outer_cutoff: f32,
@ -33,13 +32,6 @@ struct Lights {
data: array<Light>, data: array<Light>,
}; };
struct Cone {
tip: vec3<f32>,
height: f32,
direction: vec3<f32>,
radius: f32,
}
var<workgroup> wg_min_depth: atomic<u32>; var<workgroup> wg_min_depth: atomic<u32>;
var<workgroup> wg_max_depth: atomic<u32>; var<workgroup> wg_max_depth: atomic<u32>;
var<workgroup> wg_light_index_start: atomic<u32>; var<workgroup> wg_light_index_start: atomic<u32>;
@ -167,22 +159,13 @@ fn cs_main(
&& sphere_inside_frustrum(wg_frustum_planes, position, radius)) { && sphere_inside_frustrum(wg_frustum_planes, position, radius)) {
// TODO: add the light to the transparent geometry list // TODO: add the light to the transparent geometry list
add_light(light_index);
if (!sphere_inside_plane(position, radius, wg_frustum_planes[4])) { if (!sphere_inside_plane(position, radius, wg_frustum_planes[4])) {
add_light(light_index);
}
} else if (light.light_ty == LIGHT_TY_SPOT) {
let dir_vs = u_camera.view * vec4<f32>(light.direction, 1.0);
let cone_radius = tan(light.spot_cutoff) * light.range;
let cone = Cone(position, radius, dir_vs.xyz, cone_radius);
if (cone_inside_frustum(cone, wg_frustum_planes)) {
// TODO: add the light to the transparent geometry list
if (!cone_inside_plane(cone, wg_frustum_planes[4])) {
add_light(light_index);
}
} }
} }
// TODO: spotlights
} }
} }
@ -275,44 +258,3 @@ fn compute_plane(p0: vec3<f32>, p1: vec3<f32>, p2: vec3<f32>) -> vec4<f32> {
return plane; return plane;
} }
fn point_inside_plane(point: vec3<f32>, plane: vec4<f32>) -> bool {
return dot(plane.xyz, point) - plane.w < 0.0;
}
/// Check to see if a cone if fully behind (inside the negative halfspace of) a plane.
///
/// Source: Real-time collision detection, Christer Ericson (2005)
/// (https://www.3dgep.com/forward-plus/#light-culling-compute-shader)
fn cone_inside_plane(cone: Cone, plane: vec4<f32>) -> bool {
// Compute the farthest point on the end of the cone to the positive space of the plane.
let m = cross(cross(plane.xyz, cone.direction), cone.direction);
let farthest = cone.tip + cone.direction * cone.height - m * cone.radius;
// The cone is in the negative halfspace of the plane if the tip of the cone,
// and the farthest point on the end of the cone are inside the negative halfspace
// of the plane.
return point_inside_plane(cone.tip, plane) && point_inside_plane(farthest, plane);
}
fn cone_inside_frustum(cone: Cone, frustum: array<vec4<f32>, 6>) -> bool {
//let near_plane = frustum[4];
//let far_plane = frustum[5];
// check near and far clipping planes first
//if (cone_inside_plane(cone, near_plane) || cone_inside_plane(cone, far_plane)) {
// return false;
//}
// to be able to index this array with a non-const value,
// it must be defined as a var
var frustum_v = frustum;
for (var i = 0u; i < 4u; i++) {
if (cone_inside_plane(cone, frustum_v[i])) {
return false;
}
}
return true;
}

View File

@ -15,19 +15,13 @@ in
mold mold
udev udev
lua5_4_compat lua5_4_compat
((nixpkgs.rustChannelOf { rustToolchain = ./rust-toolchain.toml; }).rust.override { (nixpkgs.rustChannelOf { rustToolchain = ./rust-toolchain.toml; }).rust
extensions = [
"rust-src"
"rust-analysis"
];
})
]; ];
buildInputs = [ buildInputs = [
udev alsa-lib libGL gcc udev alsa-lib libGL gcc
vulkan-loader vulkan-headers vulkan-tools vulkan-loader vulkan-headers vulkan-tools
xorg.libX11 xorg.libXcursor xorg.libXi xorg.libXrandr # To use the x11 feature xorg.libX11 xorg.libXcursor xorg.libXi xorg.libXrandr # To use the x11 feature
libxkbcommon wayland # To use the wayland feature libxkbcommon wayland # To use the wayland feature
]; ];
LD_LIBRARY_PATH = lib.makeLibraryPath buildInputs; LD_LIBRARY_PATH = lib.makeLibraryPath buildInputs;
} }