From b0315b7ebc16fcbae6c3098db6c824f9057d2a71 Mon Sep 17 00:00:00 2001 From: HampusM Date: Mon, 20 Nov 2023 22:00:34 +0100 Subject: feat(engine): add materials --- engine/fragment-color.glsl | 4 +- engine/fragment-texture.glsl | 4 +- engine/light.glsl | 35 ++++++++++---- engine/src/color.rs | 12 +++++ engine/src/lib.rs | 21 +------- engine/src/lighting.rs | 72 ++++++++++++++++----------- engine/src/material.rs | 113 +++++++++++++++++++++++++++++++++++++++++++ engine/src/object.rs | 35 +++++++++++++- engine/src/opengl/shader.rs | 10 ---- engine/src/renderer/mod.rs | 61 +++++++++++++++-------- engine/src/vector.rs | 14 ++++++ 11 files changed, 289 insertions(+), 92 deletions(-) create mode 100644 engine/src/material.rs (limited to 'engine') diff --git a/engine/fragment-color.glsl b/engine/fragment-color.glsl index fcf8d28..4213860 100644 --- a/engine/fragment-color.glsl +++ b/engine/fragment-color.glsl @@ -12,9 +12,9 @@ uniform vec3 view_pos; void main() { - vec3 ambient_light = ambient_light_strength * light_color; + vec3 ambient_light = calc_ambient_light(); - vec3 light_direction = normalize(light_pos - in_frag_pos); + vec3 light_direction = normalize(light.position - in_frag_pos); vec3 norm = normalize(in_normal); vec3 diffuse_light = calc_diffuse_light(light_direction, norm); diff --git a/engine/fragment-texture.glsl b/engine/fragment-texture.glsl index 2948a2e..69718a6 100644 --- a/engine/fragment-texture.glsl +++ b/engine/fragment-texture.glsl @@ -15,9 +15,9 @@ uniform sampler2D input_texture; void main() { - vec3 ambient_light = ambient_light_strength * light_color; + vec3 ambient_light = calc_ambient_light(); - vec3 light_direction = normalize(light_pos - in_frag_pos); + vec3 light_direction = normalize(light.position - in_frag_pos); vec3 norm = normalize(in_normal); vec3 diffuse_light = calc_diffuse_light(light_direction, norm); diff --git a/engine/light.glsl b/engine/light.glsl index 3f1c601..0ceac16 100644 --- a/engine/light.glsl +++ b/engine/light.glsl @@ -1,18 +1,33 @@ #version 330 core -uniform vec3 light_color; -uniform vec3 light_pos; - -uniform float ambient_light_strength; -uniform float specular_light_strength; - -uniform uint specular_shininess; +struct Material { + vec3 ambient; + vec3 diffuse; + vec3 specular; + float shininess; +}; + +struct Light { + vec3 position; + + vec3 ambient; + vec3 diffuse; + vec3 specular; +}; + +uniform Material material; +uniform Light light; + +vec3 calc_ambient_light() +{ + return light.ambient * material.ambient; +} vec3 calc_diffuse_light(in vec3 light_dir, in vec3 norm) { float diff = max(dot(norm, light_dir), 0.0); - return diff * light_color; + return light.diffuse * (diff * material.diffuse); } vec3 calc_specular_light( @@ -27,8 +42,8 @@ vec3 calc_specular_light( vec3 reflect_direction = reflect(-light_dir, norm); float spec = - pow(max(dot(view_direction, reflect_direction), 0.0), specular_shininess); + pow(max(dot(view_direction, reflect_direction), 0.0), material.shininess); - return specular_light_strength * spec * light_color; + return light.specular * (spec * material.specular); } diff --git a/engine/src/color.rs b/engine/src/color.rs index 2fd2cd3..697ea8b 100644 --- a/engine/src/color.rs +++ b/engine/src/color.rs @@ -11,3 +11,15 @@ impl Color { pub const WHITE_F32: Self = Self { red: 1.0, green: 1.0, blue: 1.0 }; } + +impl From for Color +{ + fn from(value: Value) -> Self + { + Self { + red: value.clone(), + green: value.clone(), + blue: value, + } + } +} diff --git a/engine/src/lib.rs b/engine/src/lib.rs index e6568a1..30346ed 100644 --- a/engine/src/lib.rs +++ b/engine/src/lib.rs @@ -7,7 +7,7 @@ use glfw::window::KeyState; use glfw::{Window, WindowBuilder}; use crate::camera::Camera; -use crate::lighting::{LightSettings, LightSource}; +use crate::lighting::LightSource; use crate::object::{Id as ObjectId, Object}; use crate::renderer::Renderer; use crate::vector::Vec2; @@ -22,6 +22,7 @@ mod transform; pub mod camera; pub mod color; pub mod lighting; +pub mod material; pub mod math; pub mod object; pub mod texture; @@ -37,7 +38,6 @@ pub struct Engine /// Objects have to be dropped before window. Otherwise, UB. objects: BTreeMap, light_source: Option, - light_settings: Option, window: Window, renderer: Renderer, delta_time: Duration, @@ -76,7 +76,6 @@ impl Engine renderer, objects: BTreeMap::new(), light_source: None, - light_settings: None, delta_time: Duration::ZERO, }) } @@ -129,8 +128,6 @@ impl Engine { let mut prev_frame_start: Option = None; - let default_light_settings = LightSettings::default(); - while !self.window.should_close() { self.update_delta_time(&mut prev_frame_start); @@ -141,9 +138,6 @@ impl Engine self.renderer.render( self.objects.values(), self.light_source.as_ref(), - self.light_settings - .as_ref() - .unwrap_or(&default_light_settings), &window_size, ); @@ -204,17 +198,6 @@ impl Engine Ok(Vec2 { x: pos.x, y: pos.y }) } - pub fn set_light_settings(&mut self, light_settings: LightSettings) - { - self.light_settings = Some(light_settings); - } - - #[must_use] - pub fn light_settings(&self) -> Option<&LightSettings> - { - self.light_settings.as_ref() - } - fn update_delta_time(&mut self, prev_frame_start: &mut Option) { let frame_start_time = Instant::now(); diff --git a/engine/src/lighting.rs b/engine/src/lighting.rs index e7fb901..f14c0b3 100644 --- a/engine/src/lighting.rs +++ b/engine/src/lighting.rs @@ -1,31 +1,13 @@ use crate::color::Color; use crate::vector::Vec3; -#[derive(Debug, Clone)] -pub struct LightSettings -{ - pub ambient_light_strength: f32, - pub specular_light_strength: f32, - pub specular_shininess: u32, -} - -impl Default for LightSettings -{ - fn default() -> Self - { - Self { - ambient_light_strength: 1.0, - specular_light_strength: 0.0, - specular_shininess: 32, - } - } -} - #[derive(Debug, Clone)] pub struct LightSource { position: Vec3, - color: Color, + ambient: Color, + diffuse: Color, + specular: Color, } impl LightSource @@ -37,9 +19,21 @@ impl LightSource } #[must_use] - pub fn color(&self) -> &Color + pub fn ambient(&self) -> &Color + { + &self.ambient + } + + #[must_use] + pub fn diffuse(&self) -> &Color { - &self.color + &self.diffuse + } + + #[must_use] + pub fn specular(&self) -> &Color + { + &self.specular } pub fn translate(&mut self, translation: Vec3) @@ -52,7 +46,9 @@ impl LightSource pub struct LightSourceBuilder { position: Vec3, - color: Color, + ambient: Color, + diffuse: Color, + specular: Color, } impl LightSourceBuilder @@ -62,7 +58,9 @@ impl LightSourceBuilder { Self { position: Vec3::default(), - color: Color::WHITE_F32, + ambient: Color::WHITE_F32, + diffuse: Color::WHITE_F32, + specular: Color::WHITE_F32, } } @@ -75,9 +73,25 @@ impl LightSourceBuilder } #[must_use] - pub fn color(mut self, color: Color) -> Self + pub fn ambient(mut self, ambient: Color) -> Self + { + self.ambient = ambient; + + self + } + + #[must_use] + pub fn diffuse(mut self, diffuse: Color) -> Self + { + self.diffuse = diffuse; + + self + } + + #[must_use] + pub fn specular(mut self, specular: Color) -> Self { - self.color = color; + self.specular = specular; self } @@ -87,7 +101,9 @@ impl LightSourceBuilder { LightSource { position: self.position.clone(), - color: self.color.clone(), + ambient: self.ambient.clone(), + diffuse: self.diffuse.clone(), + specular: self.specular.clone(), } } } diff --git a/engine/src/material.rs b/engine/src/material.rs new file mode 100644 index 0000000..240d7e2 --- /dev/null +++ b/engine/src/material.rs @@ -0,0 +1,113 @@ +use crate::color::Color; + +#[derive(Debug, Clone)] +pub struct Material +{ + ambient: Color, + diffuse: Color, + specular: Color, + shininess: f32, +} + +impl Material +{ + #[must_use] + pub fn ambient(&self) -> &Color + { + &self.ambient + } + + #[must_use] + pub fn diffuse(&self) -> &Color + { + &self.diffuse + } + + #[must_use] + pub fn specular(&self) -> &Color + { + &self.specular + } + + #[must_use] + pub fn shininess(&self) -> f32 + { + self.shininess + } +} + +/// [`Material`] builder. +#[derive(Debug, Clone)] +pub struct Builder +{ + ambient: Color, + diffuse: Color, + specular: Color, + shininess: f32, +} + +impl Builder +{ + #[must_use] + pub fn new() -> Self + { + Self { + ambient: 0.2.into(), + diffuse: 0.5.into(), + specular: 1.0.into(), + shininess: 32.0, + } + } + + #[must_use] + pub fn ambient(mut self, ambient: Color) -> Self + { + self.ambient = ambient; + + self + } + + #[must_use] + pub fn diffuse(mut self, diffuse: Color) -> Self + { + self.diffuse = diffuse; + + self + } + + #[must_use] + pub fn specular(mut self, specular: Color) -> Self + { + self.specular = specular; + + self + } + + #[must_use] + pub fn shininess(mut self, shininess: f32) -> Self + { + self.shininess = shininess; + + self + } + + /// Builds a new [`Material`]. + #[must_use] + pub fn build(&self) -> Material + { + Material { + ambient: self.ambient.clone(), + diffuse: self.diffuse.clone(), + specular: self.specular.clone(), + shininess: self.shininess, + } + } +} + +impl Default for Builder +{ + fn default() -> Self + { + Self::new() + } +} diff --git a/engine/src/object.rs b/engine/src/object.rs index 3827763..6749124 100644 --- a/engine/src/object.rs +++ b/engine/src/object.rs @@ -2,6 +2,7 @@ use std::fs::read_to_string; use std::io::Error as IoError; use std::path::{Path, PathBuf}; +use crate::material::{Builder as MaterialBuilder, Material}; use crate::opengl::shader::{ Error as ShaderError, Kind as ShaderKind, @@ -28,6 +29,7 @@ pub struct Object renderable: Renderable, transform: Transform, texture: Option, + material: Material, } impl Object @@ -62,6 +64,12 @@ impl Object self.texture.as_ref() } + #[must_use] + pub fn material(&self) -> &Material + { + &self.material + } + pub(crate) fn renderable(&self) -> &Renderable { &self.renderable @@ -74,12 +82,13 @@ impl Object } /// Object builder. -#[derive(Debug, Default)] +#[derive(Debug)] pub struct Builder { vertices: Vec, indices: Option>, texture: Option, + material: Material, } impl Builder @@ -88,7 +97,12 @@ impl Builder #[must_use] pub fn new() -> Self { - Self::default() + Self { + vertices: Vec::new(), + indices: None, + texture: None, + material: MaterialBuilder::new().build(), + } } #[must_use] @@ -115,6 +129,14 @@ impl Builder self } + #[must_use] + pub fn material(mut self, material: Material) -> Self + { + self.material = material; + + self + } + /// Builds a new [`Object`]. /// /// # Errors @@ -212,6 +234,7 @@ impl Builder renderable, transform, texture: self.texture, + material: self.material, }) } @@ -226,6 +249,14 @@ impl Builder } } +impl Default for Builder +{ + fn default() -> Self + { + Self::new() + } +} + /// Object error #[derive(Debug, thiserror::Error)] pub enum Error diff --git a/engine/src/opengl/shader.rs b/engine/src/opengl/shader.rs index 4bf56aa..9bed09b 100644 --- a/engine/src/opengl/shader.rs +++ b/engine/src/opengl/shader.rs @@ -205,16 +205,6 @@ impl Program } } - pub fn set_uniform_1uiv(&self, _: &CurrentlyBound, name: &CStr, num: u32) - { - let uniform_location = - unsafe { gl::GetUniformLocation(self.program, name.as_ptr().cast()) }; - - unsafe { - gl::Uniform1uiv(uniform_location, 1, &num); - } - } - fn get_info_log(&self) -> String { let mut buf = vec![gl::types::GLchar::default(); 512]; diff --git a/engine/src/renderer/mod.rs b/engine/src/renderer/mod.rs index d46612f..6fa692c 100644 --- a/engine/src/renderer/mod.rs +++ b/engine/src/renderer/mod.rs @@ -6,7 +6,7 @@ use glfw::WindowSize; use crate::camera::Camera; use crate::color::Color; -use crate::lighting::{LightSettings, LightSource}; +use crate::lighting::LightSource; use crate::object::Object; use crate::opengl::buffer::{ ArrayKind as ArrayBufferKind, @@ -68,7 +68,6 @@ impl Renderer &self, objects: impl IntoIterator, light_source: Option<&LightSource>, - light_settings: &LightSettings, window_size: &WindowSize, ) { @@ -90,7 +89,6 @@ impl Renderer light_source, &self.camera, &shader_program_curr_bound, - light_settings, ); if let Some(texture) = obj.texture() { @@ -262,43 +260,68 @@ fn apply_light( light_source: Option<&LightSource>, camera: &Camera, shader_program_curr_bound: &CurrentlyBound, - light_settings: &LightSettings, ) { obj.renderable().shader_program.set_uniform_vec_3fv( shader_program_curr_bound, - cstr!("light_color"), + cstr!("light.position"), + &light_source.map_or_else(Vec3::default, |light_source| { + light_source.position().clone() + }), + ); + + obj.renderable().shader_program.set_uniform_vec_3fv( + shader_program_curr_bound, + cstr!("light.ambient"), &light_source .map_or(Color::WHITE_F32, |light_source| { - light_source.color().clone() + light_source.ambient().clone() }) .into(), ); obj.renderable().shader_program.set_uniform_vec_3fv( shader_program_curr_bound, - cstr!("light_pos"), - &light_source.map_or_else(Vec3::default, |light_source| { - light_source.position().clone() - }), + cstr!("light.diffuse"), + &light_source + .map_or(Color::WHITE_F32, |light_source| { + light_source.diffuse().clone() + }) + .into(), ); - obj.renderable().shader_program.set_uniform_1fv( + obj.renderable().shader_program.set_uniform_vec_3fv( shader_program_curr_bound, - cstr!("ambient_light_strength"), - light_settings.ambient_light_strength, + cstr!("light.specular"), + &light_source + .map_or(Color::WHITE_F32, |light_source| { + light_source.specular().clone() + }) + .into(), ); - obj.renderable().shader_program.set_uniform_1fv( + obj.renderable().shader_program.set_uniform_vec_3fv( shader_program_curr_bound, - cstr!("specular_light_strength"), - light_settings.specular_light_strength, + cstr!("material.ambient"), + &obj.material().ambient().clone().into(), ); - obj.renderable().shader_program.set_uniform_1uiv( + obj.renderable().shader_program.set_uniform_vec_3fv( + shader_program_curr_bound, + cstr!("material.diffuse"), + &obj.material().diffuse().clone().into(), + ); + + obj.renderable().shader_program.set_uniform_vec_3fv( + shader_program_curr_bound, + cstr!("material.specular"), + &obj.material().specular().clone().into(), + ); + + obj.renderable().shader_program.set_uniform_1fv( shader_program_curr_bound, - cstr!("specular_shininess"), - light_settings.specular_shininess, + cstr!("material.shininess"), + obj.material().shininess(), ); obj.renderable().shader_program.set_uniform_vec_3fv( diff --git a/engine/src/vector.rs b/engine/src/vector.rs index a5ef911..e0aa262 100644 --- a/engine/src/vector.rs +++ b/engine/src/vector.rs @@ -226,6 +226,20 @@ where } } +impl From for Vec3 +where + Value: Clone, +{ + fn from(value: Value) -> Self + { + Self { + x: value.clone(), + y: value.clone(), + z: value, + } + } +} + impl From> for Vec3 { fn from(color: Color) -> Self -- cgit v1.2.3-18-g5258