summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2024-05-22 22:42:43 +0200
committerHampusM <hampus@hampusmat.com>2024-05-22 22:42:43 +0200
commite9504a3b90ef081dcd622381694f6c51e2844c2d (patch)
tree479f1e21c892c3cfc964c139015d60840862df89
parentdb4017c1165b9ba02655508e615d161a4c42acf0 (diff)
feat(engine): add support for multiple point lights
-rw-r--r--TODO.md2
-rw-r--r--engine/fragment.glsl46
-rw-r--r--engine/light.glsl39
-rw-r--r--engine/src/renderer/mod.rs125
4 files changed, 129 insertions, 83 deletions
diff --git a/TODO.md b/TODO.md
index f91e275..f4bb66a 100644
--- a/TODO.md
+++ b/TODO.md
@@ -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();