diff --git a/examples/testbed/src/main.rs b/examples/testbed/src/main.rs index 710d01d..8014ee8 100644 --- a/examples/testbed/src/main.rs +++ b/examples/testbed/src/main.rs @@ -1,4 +1,4 @@ -use lyra_engine::{math::{self, Vec3}, ecs::{World, components::{transform::TransformComponent, camera::CameraComponent, model::ModelComponent, DeltaTime}, EventQueue, SimpleSystem, Component, Criteria, CriteriaSchedule, BatchedSystem}, math::Transform, input::{KeyCode, InputButtons, MouseMotion, ActionHandler, Layout, Action, ActionKind, LayoutId, ActionMapping, Binding, ActionSource, ActionMappingId, InputActionPlugin, ActionState}, game::Game, plugin::Plugin, render::window::{CursorGrabMode, WindowOptions}, change_tracker::Ct}; +use lyra_engine::{math::{self, Vec3}, ecs::{World, components::{transform::TransformComponent, camera::CameraComponent, model::ModelComponent, DeltaTime}, EventQueue, SimpleSystem, Component, Criteria, CriteriaSchedule, BatchedSystem}, math::Transform, input::{KeyCode, InputButtons, MouseMotion, ActionHandler, Layout, Action, ActionKind, LayoutId, ActionMapping, Binding, ActionSource, ActionMappingId, InputActionPlugin, ActionState}, game::Game, plugin::Plugin, render::{window::{CursorGrabMode, WindowOptions}, light::PointLight}, change_tracker::Ct}; use lyra_engine::assets::{ResourceManager, Model}; mod free_fly_camera; @@ -69,7 +69,7 @@ async fn main() { let mut resman = world.get_resource_mut::().unwrap(); //let diffuse_texture = resman.request::("assets/happy-tree.png").unwrap(); let antique_camera_model = resman.request::("assets/AntiqueCamera.glb").unwrap(); - //let cube_model = resman.request::("assets/texture-sep/texture-sep.gltf").unwrap(); + let cube_model = resman.request::("assets/cube-texture-bin.glb").unwrap(); drop(resman); /* world.spawn(( @@ -82,6 +82,27 @@ async fn main() { TransformComponent::from(Transform::from_xyz(0.0, -5.0, -10.0)), )); + /* let light = PointLight { + color: Vec3::new(1.0, 1.0, 1.0), + position: Vec3::new(0.0, -5.0, -8.0), + constant: 1.0, + linear: 0.09, + quadratic: 0.032, + }; + world.spawn((light,)); */ + let pos = Vec3::new(0.0, 0.0, -10.0); + world.spawn(( + PointLight { + color: Vec3::new(1.0, 1.0, 1.0), + intensity: 2.0, + constant: 1.0, + linear: 0.045, + quadratic: 0.0075, + }, + TransformComponent::from(Transform::from_xyz(pos.x, pos.y, pos.z)), + ModelComponent(cube_model), + )); + let mut camera = CameraComponent::new_3d(); camera.transform.translation += math::Vec3::new(0.0, 0.0, 7.5); //camera.transform.rotate_y(Angle::Degrees(-25.0)); diff --git a/src/render/light/mod.rs b/src/render/light/mod.rs index 178c632..dc9fa9c 100644 --- a/src/render/light/mod.rs +++ b/src/render/light/mod.rs @@ -1,6 +1,8 @@ pub mod point; pub use point::*; +use crate::math::Transform; + #[repr(C)] #[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] pub struct LightUniform { @@ -10,4 +12,41 @@ pub struct LightUniform { pub color: glam::Vec3, // Due to uniforms requiring 16 byte (4 float) spacing, we need to use a padding field here pub(crate) _padding2: u32, +} + +#[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, +} + +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, + constant: light.constant, + linear: light.linear, + quadratic: light.quadratic, + } + } } \ No newline at end of file diff --git a/src/render/light/point.rs b/src/render/light/point.rs index e7b99a4..a2b1f2c 100644 --- a/src/render/light/point.rs +++ b/src/render/light/point.rs @@ -1,6 +1,9 @@ #[repr(C)] -#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] +#[derive(Default, Debug, Copy, Clone, edict::Component)] pub struct PointLight { - position: glam::Vec3, - color: glam::Vec3, + pub color: glam::Vec3, + pub intensity: f32, + pub constant: f32, + pub linear: f32, + pub quadratic: f32, } \ No newline at end of file diff --git a/src/render/renderer.rs b/src/render/renderer.rs index 1afffd0..9d86b1e 100755 --- a/src/render/renderer.rs +++ b/src/render/renderer.rs @@ -18,10 +18,11 @@ use crate::ecs::components::camera::CameraComponent; use crate::ecs::components::model::ModelComponent; use crate::ecs::components::transform::TransformComponent; use crate::math::{Transform, self}; +use crate::render::light::PointLightUniform; use super::camera::{RenderCamera, CameraUniform}; use super::desc_buf_lay::DescVertexBufferLayout; -use super::light::LightUniform; +use super::light::{LightUniform, PointLight}; use super::texture::RenderTexture; use super::transform_buffer_storage::{TransformBufferIndices, TransformBuffers}; use super::vertex::Vertex; @@ -90,7 +91,6 @@ pub struct BasicRenderer { default_texture_bind_group: BindGroup, depth_buffer_texture: RenderTexture, - point_light_uniform: LightUniform, point_light_buffer: wgpu::Buffer, point_light_bind_group_layout: BindGroupLayout, point_light_bind_group: BindGroup, @@ -243,16 +243,10 @@ impl BasicRenderer { next_indices: TransformBufferIndices { buffer_index: 0, transform_index: 0 }, }; - let point_light_uniform = LightUniform { - position: glam::Vec3::new(0.0, -2.0, -13.0), - _padding: 0, - color: glam::Vec3::new(1.0, 1.0, 1.0), - _padding2: 0, - }; let point_light_buffer = device.create_buffer_init( &wgpu::util::BufferInitDescriptor { label: Some("Point Light Buffer"), - contents: bytemuck::cast_slice(&[glam::Mat4::IDENTITY]), + contents: bytemuck::cast_slice(&[PointLightUniform::default()]), usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, } ); @@ -372,7 +366,6 @@ impl BasicRenderer { depth_buffer_texture: depth_texture, entity_last_transforms: HashMap::new(), - point_light_uniform, point_light_buffer, point_light_bind_group_layout, point_light_bind_group, @@ -654,11 +647,9 @@ impl Renderer for BasicRenderer { warn!("Missing camera!"); } - { - let old_pos = self.point_light_uniform.position; - self.point_light_uniform.position = glam::Quat::from_axis_angle(glam::Vec3::Z, - math::Angle::Degrees(1.0).to_radians()) * old_pos; - self.queue.write_buffer(&self.point_light_buffer, 0, bytemuck::cast_slice(&[self.point_light_uniform])); + for (point_light, transform) in main_world.query::<(&PointLight, &TransformComponent)>().iter() { + let uniform = PointLightUniform::from_bundle(point_light, &transform.transform); + self.queue.write_buffer(&self.point_light_buffer, 0, bytemuck::cast_slice(&[uniform])); } } diff --git a/src/render/shaders/base.wgsl b/src/render/shaders/base.wgsl index fc9d227..2123c59 100755 --- a/src/render/shaders/base.wgsl +++ b/src/render/shaders/base.wgsl @@ -19,8 +19,12 @@ struct CameraUniform { }; struct PointLight { - position: vec3, - color: vec3, + position: vec4, + color: vec4, + intensity: f32, + constant: f32, + linear: f32, + quadratic: f32, }; @group(1) @binding(0) @@ -32,7 +36,6 @@ var camera: CameraUniform; @group(3) @binding(0) var point_light: PointLight; - @vertex fn vs_main( model: VertexInput, @@ -63,29 +66,41 @@ var s_diffuse: sampler; @fragment fn fs_main(in: VertexOutput) -> @location(0) vec4 { - //return textureSample(t_diffuse, s_diffuse, in.tex_coords); + let light_color = point_light.color.xyz; + let light_pos = point_light.position.xyz; + let camera_view_pos = camera.view_pos.xyz; let object_color: vec4 = textureSample(t_diffuse, s_diffuse, in.tex_coords); - + // We don't need (or want) much ambient light, so 0.1 is fine let ambient_strength = 0.1; - let ambient_color = point_light.color * ambient_strength; + var ambient_color = light_color * ambient_strength; //// diffuse //// - let light_dir = normalize(point_light.position - in.world_position); + let light_dir = normalize(light_pos - in.world_position); let diffuse_strength = max(dot(in.world_normal, light_dir), 0.0); - let diffuse_color = point_light.color * diffuse_strength; + var diffuse_color = light_color * diffuse_strength; //// end of diffuse //// //// specular //// - let view_dir = normalize(camera.view_pos.xyz - in.world_position); + let view_dir = normalize(camera_view_pos - in.world_position); let half_dir = normalize(view_dir + light_dir); let specular_strength = pow(max(dot(in.world_normal, half_dir), 0.0), 32.0); - let specular_color = specular_strength * point_light.color; + var specular_color = specular_strength * light_color; //// end of specular //// + //// point light attenuation //// + let distance = length(light_pos - in.world_position); + let attenuation = 1.0 / (point_light.constant + point_light.linear * distance + + point_light.quadratic * (distance * distance)); + + ambient_color *= attenuation * point_light.intensity; + diffuse_color *= attenuation * point_light.intensity; + specular_color *= attenuation * point_light.intensity; + //// end of point light attenuation //// + let result = (ambient_color + diffuse_color + specular_color) * object_color.xyz; return vec4(result, object_color.a);