From 36886e343781bf0ddf7458d5c6db5b5724c918e4 Mon Sep 17 00:00:00 2001 From: HampusM Date: Thu, 23 May 2024 22:47:30 +0200 Subject: feat(engine): add directional light --- engine/fragment.glsl | 51 ++++++++++++-- engine/light.glsl | 36 ++++++---- engine/src/lighting.rs | 21 ++++++ engine/src/renderer/opengl.rs | 159 +++++++++++++++++++++++++++++++++--------- 4 files changed, 212 insertions(+), 55 deletions(-) diff --git a/engine/fragment.glsl b/engine/fragment.glsl index cc46f36..5bf5ff2 100644 --- a/engine/fragment.glsl +++ b/engine/fragment.glsl @@ -3,7 +3,7 @@ #preinclude "light.glsl" #preinclude "vertex_data.glsl" -#define MAX_POINT_LIGHT_CNT 64 +#define MAX_LIGHT_CNT 64 out vec4 FragColor; @@ -12,23 +12,62 @@ in VertexData vertex_data; uniform vec3 view_pos; uniform sampler2D input_texture; uniform Material material; -uniform PointLight point_lights[MAX_POINT_LIGHT_CNT]; + +uniform PointLight point_lights[MAX_LIGHT_CNT]; uniform int point_light_cnt; +uniform DirectionalLight directional_lights[MAX_LIGHT_CNT]; +uniform int directional_light_cnt; + void main() { vec3 ambient_light = calc_ambient_light(material, vertex_data.texture_coords); + vec3 directional_light_sum = vec3(0.0, 0.0, 0.0); + + for (int dl_index = 0; dl_index < directional_light_cnt; dl_index++) { + CalculatedLight calculated_dir_light; + + calc_light( + // Negated since we want the light to point from the light direction + normalize(-directional_lights[dl_index].direction), + directional_lights[dl_index].phong, + vertex_data, + view_pos, + material, + calculated_dir_light + ); + + directional_light_sum += + calculated_dir_light.diffuse + calculated_dir_light.specular; + } + vec3 point_light_sum = vec3(0.0, 0.0, 0.0); for (int pl_index = 0; pl_index < point_light_cnt; pl_index++) { - point_light_sum += calc_point_light( - point_lights[pl_index], + vec3 light_direction = + normalize(point_lights[pl_index].position - vertex_data.world_space_pos); + + CalculatedLight calculated_point_light; + + calc_light( + light_direction, + point_lights[pl_index].phong, vertex_data, view_pos, - material + material, + calculated_point_light ); + + float attenuation = + calc_attenuation(point_lights[pl_index], vertex_data.world_space_pos); + + calculated_point_light.diffuse *= attenuation; + calculated_point_light.specular *= attenuation; + + point_light_sum += + calculated_point_light.diffuse + calculated_point_light.specular; } - FragColor = vec4((ambient_light + point_light_sum), 1.0); + FragColor = vec4((ambient_light + directional_light_sum + point_light_sum), 1.0); } diff --git a/engine/light.glsl b/engine/light.glsl index 92d3ec3..1bc23a4 100644 --- a/engine/light.glsl +++ b/engine/light.glsl @@ -36,6 +36,18 @@ struct PointLight AttenuationProperties attenuation_props; }; +struct DirectionalLight +{ + LightPhong phong; + vec3 direction; +}; + +struct CalculatedLight +{ + vec3 diffuse; + vec3 specular; +}; + vec3 calc_ambient_light(in Material material, in vec2 texture_coords) { return vec3(texture(material.ambient_map, texture_coords)) * material.ambient; @@ -88,40 +100,34 @@ float calc_attenuation(in PointLight point_light, in vec3 position) * pow(light_distance, 2)); } -vec3 calc_point_light( - in PointLight light, +void calc_light( + in vec3 light_direction, + in LightPhong light_phong, in VertexData vertex_data, in vec3 view_pos, - in Material material + in Material material, + out CalculatedLight calculated_light ) { - vec3 light_direction = normalize(light.position - vertex_data.world_space_pos); vec3 norm = normalize(vertex_data.world_space_normal); - vec3 diffuse_light = calc_diffuse_light( + calculated_light.diffuse = calc_diffuse_light( material, - light.phong, + light_phong, light_direction, norm, vertex_data.texture_coords ); - vec3 specular_light = calc_specular_light( + calculated_light.specular = calc_specular_light( material, - light.phong, + light_phong, light_direction, norm, view_pos, vertex_data.world_space_pos, vertex_data.texture_coords ); - - float attenuation = calc_attenuation(light, vertex_data.world_space_pos); - - diffuse_light *= attenuation; - specular_light *= attenuation; - - return diffuse_light + specular_light; } #endif diff --git a/engine/src/lighting.rs b/engine/src/lighting.rs index ffa2645..398161f 100644 --- a/engine/src/lighting.rs +++ b/engine/src/lighting.rs @@ -1,6 +1,7 @@ use ecs::{Component, Sole}; use crate::color::Color; +use crate::data_types::vector::Vec3; use crate::util::builder; builder! { @@ -64,6 +65,26 @@ impl Default for AttenuationParams } } +builder! { +#[builder(name = DirectionalLightBuilder, derives = (Debug, Default, Clone))] +#[derive(Debug, Default, Clone, Component)] +#[non_exhaustive] +pub struct DirectionalLight +{ + pub diffuse: Color, + pub specular: Color, + pub direction: Vec3, +} +} + +impl DirectionalLight +{ + pub fn builder() -> DirectionalLightBuilder + { + DirectionalLightBuilder::default() + } +} + builder! { /// Global light properties. #[builder(name = GlobalLightBuilder, derives = (Debug, Clone, Default))] diff --git a/engine/src/renderer/opengl.rs b/engine/src/renderer/opengl.rs index 89f920c..3fe3388 100644 --- a/engine/src/renderer/opengl.rs +++ b/engine/src/renderer/opengl.rs @@ -11,9 +11,10 @@ use ecs::system::{Into as _, System}; use ecs::{Component, Query}; use crate::camera::Camera; +use crate::color::Color; use crate::data_types::dimens::Dimens; use crate::event::{Present as PresentEvent, Start as StartEvent}; -use crate::lighting::{GlobalLight, PointLight}; +use crate::lighting::{DirectionalLight, GlobalLight, PointLight}; use crate::material::{Flags as MaterialFlags, Material}; use crate::matrix::Matrix; use crate::mesh::Mesh; @@ -100,6 +101,7 @@ fn render( Transform, )>, point_light_query: Query<(PointLight, Transform)>, + directional_lights: Query<(DirectionalLight,)>, camera_query: Query<(Camera,)>, window: Single, global_light: Single, @@ -125,6 +127,8 @@ fn render( .map(|(point_light, transform)| ((*point_light).clone(), (*transform).clone())) .collect::>(); + let directional_lights = directional_lights.iter().collect::>(); + let GlObjects { shader_programs: gl_shader_programs, textures: gl_textures, @@ -154,6 +158,11 @@ fn render( &global_light, shader_program, point_lights.as_slice(), + directional_lights + .iter() + .map(|(dir_light,)| &**dir_light) + .collect::>() + .as_slice(), &camera, ); @@ -358,6 +367,7 @@ fn apply_light( global_light: &GlobalLight, gl_shader_program: &mut GlShaderProgram, point_lights: &[(PointLight, Transform)], + directional_lights: &[&DirectionalLight], camera: &Camera, ) { @@ -366,15 +376,55 @@ fn apply_light( "Shader cannot handle more than 64 point lights" ); + debug_assert!( + directional_lights.len() < 64, + "Shader cannot handle more than 64 directional lights" + ); + + for (dir_light_index, dir_light) in directional_lights.iter().enumerate() { + gl_shader_program.set_uniform_vec_3fv( + &create_light_uniform_name( + "directional_lights", + dir_light_index, + "direction", + ), + &dir_light.direction, + ); + + set_light_phong_uniforms( + gl_shader_program, + "directional_lights", + dir_light_index, + *dir_light, + ); + } + + gl_shader_program.set_uniform_1i( + cstr!("directional_light_cnt"), + directional_lights.len() as i32, + ); + for (point_light_index, (point_light, point_light_transform)) in point_lights.iter().enumerate() { - set_point_light_uniforms( + gl_shader_program.set_uniform_vec_3fv( + &create_light_uniform_name("point_lights", point_light_index, "position"), + &point_light_transform.position, + ); + + set_light_phong_uniforms( gl_shader_program, + "point_lights", point_light_index, point_light, - point_light_transform, - ) + ); + + set_light_attenuation_uniforms( + gl_shader_program, + "point_lights", + point_light_index, + point_light, + ); } gl_shader_program.set_uniform_1i(cstr!("point_light_cnt"), point_lights.len() as i32); @@ -421,55 +471,96 @@ fn apply_light( gl_shader_program.set_uniform_vec_3fv(cstr!("view_pos"), &camera.position); } -fn set_point_light_uniforms( +fn set_light_attenuation_uniforms( gl_shader_program: &mut GlShaderProgram, - point_light_index: usize, - point_light: &PointLight, - point_light_transform: &Transform, + light_array: &str, + light_index: usize, + light: &PointLight, ) { - gl_shader_program.set_uniform_vec_3fv( - &create_point_light_uniform_name(point_light_index, "position"), - &point_light_transform.position, - ); - - gl_shader_program.set_uniform_vec_3fv( - &create_point_light_uniform_name(point_light_index, "phong.diffuse"), - &point_light.diffuse.clone().into(), - ); - - gl_shader_program.set_uniform_vec_3fv( - &create_point_light_uniform_name(point_light_index, "phong.specular"), - &point_light.specular.clone().into(), - ); - gl_shader_program.set_uniform_1fv( - &create_point_light_uniform_name(point_light_index, "attenuation_props.constant"), - point_light.attenuation_params.constant, + &create_light_uniform_name( + light_array, + light_index, + "attenuation_props.constant", + ), + light.attenuation_params.constant, ); gl_shader_program.set_uniform_1fv( - &create_point_light_uniform_name(point_light_index, "attenuation_props.linear"), - point_light.attenuation_params.linear, + &create_light_uniform_name(light_array, light_index, "attenuation_props.linear"), + light.attenuation_params.linear, ); gl_shader_program.set_uniform_1fv( - &create_point_light_uniform_name( - point_light_index, + &create_light_uniform_name( + light_array, + light_index, "attenuation_props.quadratic", ), - point_light.attenuation_params.quadratic, + light.attenuation_params.quadratic, + ); +} + +fn set_light_phong_uniforms( + gl_shader_program: &mut GlShaderProgram, + light_array: &str, + light_index: usize, + light: &impl Light, +) +{ + gl_shader_program.set_uniform_vec_3fv( + &create_light_uniform_name(light_array, light_index, "phong.diffuse"), + &light.diffuse().clone().into(), + ); + + gl_shader_program.set_uniform_vec_3fv( + &create_light_uniform_name(light_array, light_index, "phong.specular"), + &light.specular().clone().into(), ); } -fn create_point_light_uniform_name( - point_light_index: usize, - point_light_field: &str, +trait Light +{ + fn diffuse(&self) -> &Color; + fn specular(&self) -> &Color; +} + +impl Light for PointLight +{ + fn diffuse(&self) -> &Color + { + &self.diffuse + } + + fn specular(&self) -> &Color + { + &self.specular + } +} + +impl Light for DirectionalLight +{ + fn diffuse(&self) -> &Color + { + &self.diffuse + } + + fn specular(&self) -> &Color + { + &self.specular + } +} + +fn create_light_uniform_name( + light_array: &str, + light_index: usize, + light_field: &str, ) -> CString { unsafe { CString::from_vec_with_nul_unchecked( - format!("point_lights[{point_light_index}].{point_light_field}\0").into(), + format!("{light_array}[{light_index}].{light_field}\0").into(), ) } } -- cgit v1.2.3-18-g5258