diff options
author | HampusM <hampus@hampusmat.com> | 2024-05-22 22:42:43 +0200 |
---|---|---|
committer | HampusM <hampus@hampusmat.com> | 2024-05-22 22:42:43 +0200 |
commit | e9504a3b90ef081dcd622381694f6c51e2844c2d (patch) | |
tree | 479f1e21c892c3cfc964c139015d60840862df89 | |
parent | db4017c1165b9ba02655508e615d161a4c42acf0 (diff) |
feat(engine): add support for multiple point lights
-rw-r--r-- | TODO.md | 2 | ||||
-rw-r--r-- | engine/fragment.glsl | 46 | ||||
-rw-r--r-- | engine/light.glsl | 39 | ||||
-rw-r--r-- | engine/src/renderer/mod.rs | 125 |
4 files changed, 129 insertions, 83 deletions
@@ -1,7 +1,7 @@ - [x] Support for multiple textures - [x] Non-hardcoded projection settings - [x] Model importing -- [ ] Multiple light sources +- [x] Multiple light sources - [ ] Transparent/translucent models - [ ] Animations - [ ] Physics diff --git a/engine/fragment.glsl b/engine/fragment.glsl index 9becd4c..6e852f3 100644 --- a/engine/fragment.glsl +++ b/engine/fragment.glsl @@ -2,6 +2,8 @@ #preinclude "light.glsl" +#define MAX_POINT_LIGHT_CNT 64 + out vec4 FragColor; in vec2 in_texture_coords; @@ -12,37 +14,25 @@ in vec3 in_normal; uniform vec3 view_pos; uniform sampler2D input_texture; uniform Material material; -uniform PointLight light; +uniform PointLight point_lights[MAX_POINT_LIGHT_CNT]; +uniform int point_light_cnt; void main() { vec3 ambient_light = calc_ambient_light(material, in_texture_coords); - vec3 light_direction = normalize(light.position - in_frag_pos); - vec3 norm = normalize(in_normal); - - vec3 diffuse_light = calc_diffuse_light( - material, - light, - light_direction, - norm, - in_texture_coords - ); - - vec3 specular_light = calc_specular_light( - material, - light, - light_direction, - norm, - view_pos, - in_frag_pos, - in_texture_coords - ); - - float attenuation = calc_attenuation(light, in_frag_pos); - - diffuse_light *= attenuation; - specular_light *= attenuation; - - FragColor = vec4((ambient_light + diffuse_light + specular_light), 1.0); + 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], + in_frag_pos, + in_normal, + in_texture_coords, + view_pos, + material + ); + } + + FragColor = vec4((ambient_light + point_light_sum), 1.0); } diff --git a/engine/light.glsl b/engine/light.glsl index e9b2a61..7516a58 100644 --- a/engine/light.glsl +++ b/engine/light.glsl @@ -73,4 +73,43 @@ float calc_attenuation(in PointLight point_light, in vec3 position) * pow(light_distance, 2)); } +vec3 calc_point_light( + in PointLight light, + in vec3 frag_pos, + in vec3 normal, + in vec2 texture_coords, + in vec3 view_pos, + in Material material +) +{ + vec3 light_direction = normalize(light.position - frag_pos); + vec3 norm = normalize(normal); + + vec3 diffuse_light = calc_diffuse_light( + material, + light, + light_direction, + norm, + texture_coords + ); + + vec3 specular_light = calc_specular_light( + material, + light, + light_direction, + norm, + view_pos, + frag_pos, + texture_coords + ); + + float attenuation = calc_attenuation(light, frag_pos); + + diffuse_light *= attenuation; + specular_light *= attenuation; + + return diffuse_light + specular_light; +} + + #endif diff --git a/engine/src/renderer/mod.rs b/engine/src/renderer/mod.rs index ad587b5..485c0bb 100644 --- a/engine/src/renderer/mod.rs +++ b/engine/src/renderer/mod.rs @@ -1,5 +1,5 @@ use std::collections::HashMap; -use std::ffi::c_void; +use std::ffi::{c_void, CString}; use std::process::abort; use cstr::cstr; @@ -9,7 +9,6 @@ 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}; @@ -39,7 +38,7 @@ use crate::projection::{new_perspective_matrix, Projection}; use crate::shader::Program as ShaderProgram; use crate::texture::{Id as TextureId, Texture}; use crate::transform::Transform; -use crate::vector::{Vec2, Vec3}; +use crate::vector::Vec2; use crate::vertex::{AttributeComponentType, Vertex}; use crate::window::Window; @@ -119,10 +118,10 @@ fn render( // TODO: Maybe find a way to not clone here? Cloning here is needed since a transform // can be in both the object query and the light source query - let point_light = point_light_query + let point_lights = point_light_query .iter() - .next() - .map(|(point_light, transform)| (point_light.clone(), transform.clone())); + .map(|(point_light, transform)| ((*point_light).clone(), (*transform).clone())) + .collect::<Vec<_>>(); let GlObjects { shader_programs: gl_shader_programs, @@ -152,11 +151,7 @@ fn render( &material_flags, &global_light, shader_program, - point_light - .as_ref() - .map(|(point_light, point_light_transform)| { - (point_light, point_light_transform) - }), + point_lights.as_slice(), &camera, ); @@ -360,55 +355,27 @@ fn apply_light( material_flags: &MaterialFlags, global_light: &GlobalLight, gl_shader_program: &mut GlShaderProgram, - point_light: Option<(&PointLight, &Transform)>, + point_lights: &[(PointLight, Transform)], camera: &Camera, ) { - gl_shader_program.set_uniform_vec_3fv( - cstr!("light.position"), - &point_light.map_or_else(Vec3::default, |(_, point_light_transform)| { - point_light_transform.position - }), - ); - - gl_shader_program.set_uniform_vec_3fv( - cstr!("light.diffuse"), - &point_light - .map_or(Color::WHITE_F32, |(point_light, _)| { - point_light.diffuse.clone() - }) - .into(), + debug_assert!( + point_lights.len() < 64, + "Shader cannot handle more than 64 point lights" ); - gl_shader_program.set_uniform_vec_3fv( - cstr!("light.specular"), - &point_light - .map_or(Color::WHITE_F32, |(point_light, _)| { - point_light.specular.clone() - }) - .into(), - ); - - gl_shader_program.set_uniform_1fv( - cstr!("light.constant"), - point_light.map_or(1.0, |(light_source, _)| { - light_source.attenuation_params.constant - }), - ); - - gl_shader_program.set_uniform_1fv( - cstr!("light.linear"), - point_light.map_or(0.0, |(light_source, _)| { - light_source.attenuation_params.linear - }), - ); + for (point_light_index, (point_light, point_light_transform)) in + point_lights.iter().enumerate() + { + set_point_light_uniforms( + gl_shader_program, + point_light_index, + point_light, + point_light_transform, + ) + } - gl_shader_program.set_uniform_1fv( - cstr!("light.quadratic"), - point_light.map_or(0.0, |(light_source, _)| { - light_source.attenuation_params.quadratic - }), - ); + gl_shader_program.set_uniform_1i(cstr!("point_light_cnt"), point_lights.len() as i32); gl_shader_program.set_uniform_vec_3fv( cstr!("material.ambient"), @@ -452,6 +419,56 @@ fn apply_light( gl_shader_program.set_uniform_vec_3fv(cstr!("view_pos"), &camera.position); } +fn set_point_light_uniforms( + gl_shader_program: &mut GlShaderProgram, + point_light_index: usize, + point_light: &PointLight, + point_light_transform: &Transform, +) +{ + 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, "diffuse"), + &point_light.diffuse.clone().into(), + ); + + gl_shader_program.set_uniform_vec_3fv( + &create_point_light_uniform_name(point_light_index, "specular"), + &point_light.specular.clone().into(), + ); + + gl_shader_program.set_uniform_1fv( + &create_point_light_uniform_name(point_light_index, "constant"), + point_light.attenuation_params.constant, + ); + + gl_shader_program.set_uniform_1fv( + &create_point_light_uniform_name(point_light_index, "linear"), + point_light.attenuation_params.linear, + ); + + gl_shader_program.set_uniform_1fv( + &create_point_light_uniform_name(point_light_index, "quadratic"), + point_light.attenuation_params.quadratic, + ); +} + +fn create_point_light_uniform_name( + point_light_index: usize, + point_light_field: &str, +) -> CString +{ + unsafe { + CString::from_vec_with_nul_unchecked( + format!("point_lights[{point_light_index}].{point_light_field}\0").into(), + ) + } +} + fn create_view(camera: &Camera) -> Matrix<f32, 4, 4> { let mut view = Matrix::new(); |