diff --git a/examples/testbed/src/free_fly_camera.rs b/examples/testbed/src/free_fly_camera.rs index 1bbbea4..57b833a 100644 --- a/examples/testbed/src/free_fly_camera.rs +++ b/examples/testbed/src/free_fly_camera.rs @@ -12,6 +12,7 @@ use lyra_engine::{ #[derive(Clone, Component)] pub struct FreeFlyCamera { pub speed: f32, + pub slow_speed_factor: f32, pub look_speed: f32, pub mouse_sensitivity: f32, pub look_with_keys: bool, @@ -21,6 +22,7 @@ impl Default for FreeFlyCamera { fn default() -> Self { Self { speed: 4.0, + slow_speed_factor: 0.25, look_speed: 0.09, mouse_sensitivity: 0.4, look_with_keys: false, @@ -29,9 +31,10 @@ impl Default for FreeFlyCamera { } impl FreeFlyCamera { - pub fn new(speed: f32, look_speed: f32, mouse_sensitivity: f32, look_with_keys: bool) -> Self { + pub fn new(speed: f32, slow_speed_factor: f32, look_speed: f32, mouse_sensitivity: f32, look_with_keys: bool) -> Self { Self { speed, + slow_speed_factor, look_speed, mouse_sensitivity, look_with_keys, @@ -117,7 +120,13 @@ impl SimpleSystem for FreeFlyCameraPlugin { } if velocity != Vec3::ZERO { - cam.transform.translation += velocity.normalize() * fly.speed * delta_time; + let temp = if keys.is_pressed(KeyCode::E) { + fly.speed * delta_time * fly.slow_speed_factor + } else { + fly.speed * delta_time + }; + + cam.transform.translation += velocity.normalize() * temp; } } diff --git a/examples/testbed/src/main.rs b/examples/testbed/src/main.rs index 9c1d8a3..fec11c3 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}, light::PointLight}, 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, directional::DirectionalLight, SpotLight}}, change_tracker::Ct}; use lyra_engine::assets::{ResourceManager, Model}; mod free_fly_camera; @@ -77,65 +77,106 @@ async fn main() { let crate_model = resman.request::("assets/crate/crate.gltf").unwrap(); drop(resman); - /* world.spawn(( - ModelComponent(cube_model.clone()), - TransformComponent::from(Transform::from_xyz(3.0, 0.5, -2.2)), - )); */ - world.spawn(( ModelComponent(antique_camera_model), 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 mut cube_tran = Transform::from_xyz(-3.5, 0.0, -7.0); - cube_tran.rotate_y(math::Angle::Degrees(180.0)); - world.spawn(( - /* PointLight { - color: Vec3::new(1.0, 1.0, 1.0), - intensity: 1.0, - constant: 1.0, - linear: 0.045, - quadratic: 0.0075, - }, */ - TransformComponent::from(cube_tran), - ModelComponent(crate_model.clone()), - CubeFlag, - )); + { + let mut cube_tran = Transform::from_xyz(-3.5, 0.0, -8.0); + //cube_tran.rotate_y(math::Angle::Degrees(180.0)); + world.spawn(( + TransformComponent::from(cube_tran), + ModelComponent(crate_model.clone()), + CubeFlag, + )); + } - let mut light_tran = Transform::from_xyz(1.5, 2.5, -8.5); - light_tran.scale = Vec3::new(0.5, 0.5, 0.5); - world.spawn(( - PointLight { - color: Vec3::new(1.0, 1.0, 1.0), //Vec3::new(0.361, 0.984, 0.0), - intensity: 1.2, - /* constant: 1.0, - linear: 0.045, - quadratic: 0.0075, */ + { + 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.rotate_x(math::Angle::Degrees(-45.0)); + light_tran.rotate_y(math::Angle::Degrees(25.0)); + world.spawn(( + DirectionalLight { + color: Vec3::new(1.0, 1.0, 1.0), + ambient: 0.3, + diffuse: 1.0, + specular: 1.3, + }, + TransformComponent::from(light_tran), + ModelComponent(cube_model.clone()), + )); + } - constant: 1.0, - linear: 0.09, - quadratic: 0.032, - - ambient: 0.3, - diffuse: 1.0, - specular: 1.3, - }, - TransformComponent::from(light_tran), - ModelComponent(cube_model), - )); + { + 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(( + SpotLight { + color: Vec3::new(1.0, 0.2, 0.2), + cutoff: math::Angle::Degrees(12.5), + outer_cutoff: math::Angle::Degrees(17.5), + + constant: 1.0, + linear: 0.007, + quadratic: 0.0002, + + ambient: 0.0, + diffuse: 7.0, + specular: 1.0, + }, + TransformComponent::from(light_tran), + ModelComponent(cube_model.clone()), + )); + } + + /* { + let mut light_tran = Transform::from_xyz(-5.0, 2.5, -9.5); + light_tran.scale = Vec3::new(0.5, 0.5, 0.5); + world.spawn(( + PointLight { + color: Vec3::new(1.0, 1.0, 1.0), + + intensity: 1.0, + + constant: 1.0, + linear: 0.045, + quadratic: 0.0075, + + ambient: 0.1, + diffuse: 1.0, + specular: 1.3, + }, + TransformComponent::from(light_tran), + ModelComponent(cube_model.clone()), + )); + } */ + + { + let mut light_tran = Transform::from_xyz(2.0, 2.5, -9.5); + light_tran.scale = Vec3::new(0.5, 0.5, 0.5); + world.spawn(( + PointLight { + color: Vec3::new(0.0, 0.0, 1.0), + + intensity: 3.3, + + constant: 1.0, + linear: 0.09, + quadratic: 0.032, + + ambient: 0.2, + diffuse: 1.0, + specular: 1.3, + }, + TransformComponent::from(light_tran), + 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)); - //camera.transform.rotate_z(math::Angle::Degrees(-90.0)); + camera.transform.translation += math::Vec3::new(0.0, 0.0, 5.5); world.spawn(( camera, FreeFlyCamera::default() )); Ok(()) @@ -156,7 +197,7 @@ async fn main() { }; let spin_system = |world: &mut World| -> anyhow::Result<()> { - const SPEED: f32 = 7.0; + const SPEED: f32 = 4.0; let delta_time = **world.get_resource::().unwrap(); for (transform, _) in world.query_mut::<(&mut TransformComponent, &CubeFlag)>().iter_mut() { @@ -164,6 +205,11 @@ async fn main() { t.rotate_y(math::Angle::Degrees(SPEED * delta_time)); } + /* for (transform, s) in world.query_mut::<(&mut TransformComponent, &mut SpotLight)>().iter_mut() { + let t = &mut transform.transform; + t.rotate_x(math::Angle::Degrees(SPEED * delta_time)); + } */ + Ok(()) }; diff --git a/src/math/angle.rs b/src/math/angle.rs index 105aede..30d541c 100755 --- a/src/math/angle.rs +++ b/src/math/angle.rs @@ -10,7 +10,7 @@ pub fn radians_to_degrees(radians: f32) -> f32 { radians * 180.0 / PI } -#[derive(Clone)] +#[derive(Clone, Debug)] pub enum Angle { Degrees(f32), Radians(f32), @@ -34,4 +34,38 @@ impl Angle { Self::Radians(r) => radians_to_degrees(r), } } +} + +impl std::ops::Add for Angle { + type Output = Angle; + + fn add(self, rhs: Self) -> Self::Output { + Angle::Radians(self.to_radians() + rhs.to_radians()) + } +} + +impl std::ops::AddAssign for Angle { + fn add_assign(&mut self, rhs: Self) { + match self { + Angle::Degrees(d) => *d += rhs.to_degrees(), + Angle::Radians(r) => *r += rhs.to_radians(), + } + } +} + +impl std::ops::Sub for Angle { + type Output = Angle; + + fn sub(self, rhs: Self) -> Self::Output { + Angle::Radians(self.to_radians() - rhs.to_radians()) + } +} + +impl std::ops::SubAssign for Angle { + fn sub_assign(&mut self, rhs: Self) { + match self { + Angle::Degrees(d) => *d -= rhs.to_degrees(), + Angle::Radians(r) => *r -= rhs.to_radians(), + } + } } \ No newline at end of file diff --git a/src/render/light/directional.rs b/src/render/light/directional.rs index f5b2c30..3dadbdb 100644 --- a/src/render/light/directional.rs +++ b/src/render/light/directional.rs @@ -1,10 +1,9 @@ -#[repr(C)] -#[derive(Default, Debug, Copy, Clone, edict::Component)] +#[derive(Default, Debug, Clone, edict::Component)] pub struct DirectionalLight { - pub direction: glam::Quat, + //pub direction: glam::Quat, pub color: glam::Vec3, - pub ambient: glam::Vec3, - pub diffuse: glam::Vec3, - pub specular: glam::Vec3, + pub ambient: f32, + pub diffuse: f32, + pub specular: f32, } \ No newline at end of file diff --git a/src/render/light/mod.rs b/src/render/light/mod.rs index ae0ca55..10b640d 100644 --- a/src/render/light/mod.rs +++ b/src/render/light/mod.rs @@ -1,19 +1,27 @@ pub mod point; pub mod directional; +pub mod spotlight; + +pub use point::*; +pub use directional::*; +pub use spotlight::*; use std::{collections::{VecDeque, HashMap}, num::{NonZeroU64, NonZeroU32}, marker::PhantomData}; use edict::query::EpochOf; pub use point::*; -use tracing::debug; +use tracing::{debug, Instrument}; use wgpu::util::DeviceExt; use std::mem; use crate::{math::Transform, ecs::components::TransformComponent}; +use self::directional::DirectionalLight; + const MAX_LIGHT_COUNT: usize = 16; +/// A struct that stores a list of lights in a wgpu::Buffer. pub struct LightBuffer { _phantom: PhantomData, /// The max amount of light casters that could fit in this buffer. @@ -102,15 +110,16 @@ pub struct LightUniformBuffers { pub bindgroup: wgpu::BindGroup, pub lights_uniform: LightsUniform, pub point_lights: LightBuffer, + pub spot_lights: LightBuffer, } impl LightUniformBuffers { pub fn new(device: &wgpu::Device) -> Self { let buffer = device.create_buffer( &wgpu::BufferDescriptor { - label: Some("UB_Lights"), + label: Some("UBO_Lights"), usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, - size: (mem::size_of::() * MAX_LIGHT_COUNT) as u64, + size: mem::size_of::() as u64, mapped_at_creation: false, } ); @@ -149,6 +158,7 @@ impl LightUniformBuffers { }); let point_lights = LightBuffer::new(&bindgroup_layout, MAX_LIGHT_COUNT); + let spot_lights = LightBuffer::new(&bindgroup_layout, MAX_LIGHT_COUNT); Self { buffer, @@ -156,6 +166,7 @@ impl LightUniformBuffers { bindgroup, lights_uniform: LightsUniform::default(), point_lights, + spot_lights, } } @@ -166,10 +177,29 @@ impl LightUniformBuffers { if !self.point_lights.has_light(entity) || light_epoch == world_epoch || transform_epoch == world_epoch { let uniform = PointLightUniform::from_bundle(point_light, &transform.transform); self.point_lights.update_or_add(&mut self.lights_uniform.point_lights, entity, uniform); + debug!("Updated point light"); } } + for (entity, spot_light, transform, light_epoch, transform_epoch) + in world.query::<(edict::Entities, &SpotLight, &TransformComponent, EpochOf, EpochOf)>().iter() { + + if !self.spot_lights.has_light(entity) || light_epoch == world_epoch || transform_epoch == world_epoch { + let uniform = SpotLightUniform::from_bundle(spot_light, &transform.transform); + self.spot_lights.update_or_add(&mut self.lights_uniform.spot_lights, entity, uniform); + //debug!("Updated spot light"); + } + } + + if let Some((dir_light, transform)) = + world.query::<(&DirectionalLight, &TransformComponent)>().iter().next() { + + let uniform = DirectionalLightUniform::from_bundle(dir_light, &transform.transform); + self.lights_uniform.directional_light = uniform; + } + self.lights_uniform.point_light_count = self.point_lights.buffer_count as u32; + self.lights_uniform.spot_light_count = self.spot_lights.buffer_count as u32; queue.write_buffer(&self.buffer, 0, bytemuck::cast_slice(&[self.lights_uniform])); } } @@ -180,6 +210,10 @@ pub struct LightsUniform { point_lights: [PointLightUniform; MAX_LIGHT_COUNT], point_light_count: u32, _padding: [u32; 3], + spot_lights: [SpotLightUniform; MAX_LIGHT_COUNT], + spot_light_count: u32, + _padding2: [u32; 3], + directional_light: DirectionalLightUniform, } #[repr(C)] @@ -188,17 +222,22 @@ 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, @@ -229,4 +268,93 @@ impl PointLightUniform { _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)] +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, + } + } } \ No newline at end of file diff --git a/src/render/light/point.rs b/src/render/light/point.rs index dc59011..be9d8f4 100644 --- a/src/render/light/point.rs +++ b/src/render/light/point.rs @@ -1,5 +1,4 @@ -#[repr(C)] -#[derive(Default, Debug, Copy, Clone, edict::Component)] +#[derive(Default, Debug, Clone, edict::Component)] pub struct PointLight { pub color: glam::Vec3, pub intensity: f32, diff --git a/src/render/light/spotlight.rs b/src/render/light/spotlight.rs new file mode 100644 index 0000000..af3ea65 --- /dev/null +++ b/src/render/light/spotlight.rs @@ -0,0 +1,16 @@ +use crate::math; + +#[derive(Debug, Clone, edict::Component)] +pub struct SpotLight { + pub color: glam::Vec3, + pub cutoff: math::Angle, + pub outer_cutoff: math::Angle, + + pub constant: f32, + pub linear: f32, + pub quadratic: f32, + + pub ambient: f32, + pub diffuse: f32, + pub specular: f32, +} \ No newline at end of file diff --git a/src/render/shaders/base.wgsl b/src/render/shaders/base.wgsl index a18dd44..211d7e7 100755 --- a/src/render/shaders/base.wgsl +++ b/src/render/shaders/base.wgsl @@ -40,9 +40,38 @@ struct PointLight { specular: f32, }; +struct DirectionalLight { + direction: vec3, + color: vec3, + + ambient: f32, + diffuse: f32, + specular: f32, +}; + +struct SpotLight { + position: vec3, + direction: vec3, + color: vec3, + + cutoff: f32, + outer_cutoff: f32, + + constant: f32, + linear: f32, + quadratic: f32, + + ambient: f32, + diffuse: f32, + specular: f32, +}; + struct Lights { point_lights: array, point_light_count: u32, + spot_lights: array, + spot_light_count: u32, + directional_light: DirectionalLight, } @group(1) @binding(0) @@ -110,22 +139,59 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4 { let object_color: vec4 = textureSample(t_diffuse, s_diffuse, in.tex_coords); let specular_color: vec3 = textureSample(t_specular, s_specular, in.tex_coords).xyz; - var light_res = vec3(0.0); + // this needs to be 0.0 for the math + //u_lights.directional_light.direction.w = 0.0; + + var light_res = blinn_phong_dir_light(in.world_position, in.world_normal, u_lights.directional_light, u_material, specular_color); + for (var i = 0u; i < u_lights.point_light_count; i++) { light_res += blinn_phong_point_light(in.world_position, in.world_normal, u_lights.point_lights[i], u_material, specular_color); } + + for (var i = 0u; i < u_lights.spot_light_count; i++) { + light_res += blinn_phong_spot_light(in.world_position, in.world_normal, u_lights.spot_lights[i], u_material, specular_color); + } + let light_object_res = light_res * (object_color.xyz/* * u_material.diffuse.xyz*/); return vec4(light_object_res, object_color.a); } +fn blinn_phong_dir_light(world_pos: vec3, world_norm: vec3, dir_light: DirectionalLight, material: Material, specular_factor: vec3) -> vec3 { + let light_color = dir_light.color.xyz; + let camera_view_pos = u_camera.view_pos.xyz; + + //// Ambient light //// + var ambient_color = light_color * material.ambient.xyz * material.diffuse.xyz; + + //// diffuse //// + let light_dir = normalize(-dir_light.direction); + + 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 //// + + ambient_color *= dir_light.ambient; + diffuse_color *= dir_light.diffuse; + specular_color *= dir_light.specular; + + return ambient_color + diffuse_color + specular_color; +} + fn blinn_phong_point_light(world_pos: vec3, world_norm: vec3, point_light: PointLight, material: Material, specular_factor: vec3) -> vec3 { let light_color = point_light.color.xyz; let light_pos = point_light.position.xyz; let camera_view_pos = u_camera.view_pos.xyz; - // We don't need (or want) much ambient light, so 0.1 is fine - //let ambient_strength = 0.1; + //// Ambient light //// var ambient_color = light_color * material.ambient.xyz * material.diffuse.xyz; //// diffuse //// @@ -146,18 +212,69 @@ fn blinn_phong_point_light(world_pos: vec3, world_norm: vec3, point_li //// end of specular //// //// point light attenuation //// - /*let distance = length(light_pos - world_pos); + let distance = length(light_pos - world_pos); let attenuation = 1.0 / (point_light.constant + point_light.linear * distance + - point_light.quadratic * (distance * distance));*/ + point_light.quadratic * (distance * distance)); //ambient_color *= attenuation * point_light.intensity * point_light.ambient; //diffuse_color *= attenuation * point_light.intensity * point_light.diffuse; //specular_color *= attenuation * point_light.intensity * point_light.specular; //// end of point light attenuation //// - ambient_color *= point_light.ambient; - diffuse_color *= point_light.diffuse; - specular_color *= point_light.specular; + ambient_color *= point_light.ambient * attenuation; + diffuse_color *= point_light.diffuse * attenuation; + specular_color *= point_light.specular * attenuation; - return (ambient_color + diffuse_color + specular_color) * /*attenuation * */ point_light.intensity; + return (ambient_color + diffuse_color + specular_color) * point_light.intensity; +} + +fn blinn_phong_spot_light(world_pos: vec3, world_norm: vec3, spot_light: SpotLight, material: Material, specular_factor: vec3) -> vec3 { + let light_color = spot_light.color;//.xyz; + let light_pos = spot_light.position.xyz; + let camera_view_pos = u_camera.view_pos.xyz; + + let light_dir = normalize(spot_light.position - world_pos); + + + //if (theta > spot_light.cutoff) { + 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.cutoff - spot_light.outer_cutoff; + let intensity = clamp((theta - spot_light.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 = 1.0 / (spot_light.constant + spot_light.linear * distance + + spot_light.quadratic * (distance * distance)); + + ambient_color *= attenuation * intensity * spot_light.ambient; + diffuse_color *= attenuation * intensity * spot_light.diffuse; + specular_color *= attenuation * intensity * spot_light.specular; + //// end of spot light attenuation //// + + + return /*ambient_color +*/ diffuse_color + specular_color; + /*} else { + return vec3(0.0); + }*/ } \ No newline at end of file