summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2023-11-20 22:00:34 +0100
committerHampusM <hampus@hampusmat.com>2023-11-20 22:00:34 +0100
commitb0315b7ebc16fcbae6c3098db6c824f9057d2a71 (patch)
treec7473fbdbcc59aff933790892ee015a6f05d8565
parenta65c8abcae46b382b2e1bb7cc5d13768325083b4 (diff)
feat(engine): add materials
-rw-r--r--engine/fragment-color.glsl4
-rw-r--r--engine/fragment-texture.glsl4
-rw-r--r--engine/light.glsl35
-rw-r--r--engine/src/color.rs12
-rw-r--r--engine/src/lib.rs21
-rw-r--r--engine/src/lighting.rs72
-rw-r--r--engine/src/material.rs113
-rw-r--r--engine/src/object.rs35
-rw-r--r--engine/src/opengl/shader.rs10
-rw-r--r--engine/src/renderer/mod.rs61
-rw-r--r--engine/src/vector.rs14
11 files changed, 289 insertions, 92 deletions
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<f32>
{
pub const WHITE_F32: Self = Self { red: 1.0, green: 1.0, blue: 1.0 };
}
+
+impl<Value: Clone> From<Value> for Color<Value>
+{
+ 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<ObjectId, Object>,
light_source: Option<LightSource>,
- light_settings: Option<LightSettings>,
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<Instant> = 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<Instant>)
{
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
@@ -2,30 +2,12 @@ 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<f32>,
- color: Color<f32>,
+ ambient: Color<f32>,
+ diffuse: Color<f32>,
+ specular: Color<f32>,
}
impl LightSource
@@ -37,9 +19,21 @@ impl LightSource
}
#[must_use]
- pub fn color(&self) -> &Color<f32>
+ pub fn ambient(&self) -> &Color<f32>
+ {
+ &self.ambient
+ }
+
+ #[must_use]
+ pub fn diffuse(&self) -> &Color<f32>
{
- &self.color
+ &self.diffuse
+ }
+
+ #[must_use]
+ pub fn specular(&self) -> &Color<f32>
+ {
+ &self.specular
}
pub fn translate(&mut self, translation: Vec3<f32>)
@@ -52,7 +46,9 @@ impl LightSource
pub struct LightSourceBuilder
{
position: Vec3<f32>,
- color: Color<f32>,
+ ambient: Color<f32>,
+ diffuse: Color<f32>,
+ specular: Color<f32>,
}
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<f32>) -> Self
+ pub fn ambient(mut self, ambient: Color<f32>) -> Self
+ {
+ self.ambient = ambient;
+
+ self
+ }
+
+ #[must_use]
+ pub fn diffuse(mut self, diffuse: Color<f32>) -> Self
+ {
+ self.diffuse = diffuse;
+
+ self
+ }
+
+ #[must_use]
+ pub fn specular(mut self, specular: Color<f32>) -> 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<f32>,
+ diffuse: Color<f32>,
+ specular: Color<f32>,
+ shininess: f32,
+}
+
+impl Material
+{
+ #[must_use]
+ pub fn ambient(&self) -> &Color<f32>
+ {
+ &self.ambient
+ }
+
+ #[must_use]
+ pub fn diffuse(&self) -> &Color<f32>
+ {
+ &self.diffuse
+ }
+
+ #[must_use]
+ pub fn specular(&self) -> &Color<f32>
+ {
+ &self.specular
+ }
+
+ #[must_use]
+ pub fn shininess(&self) -> f32
+ {
+ self.shininess
+ }
+}
+
+/// [`Material`] builder.
+#[derive(Debug, Clone)]
+pub struct Builder
+{
+ ambient: Color<f32>,
+ diffuse: Color<f32>,
+ specular: Color<f32>,
+ 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<f32>) -> Self
+ {
+ self.ambient = ambient;
+
+ self
+ }
+
+ #[must_use]
+ pub fn diffuse(mut self, diffuse: Color<f32>) -> Self
+ {
+ self.diffuse = diffuse;
+
+ self
+ }
+
+ #[must_use]
+ pub fn specular(mut self, specular: Color<f32>) -> 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<Texture>,
+ 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<Vertex>,
indices: Option<Vec<u32>>,
texture: Option<Texture>,
+ 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<Self>, 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<Item = &'obj Object>,
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<ShaderProgram>,
- 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<Value> From<Value> for Vec3<Value>
+where
+ Value: Clone,
+{
+ fn from(value: Value) -> Self
+ {
+ Self {
+ x: value.clone(),
+ y: value.clone(),
+ z: value,
+ }
+ }
+}
+
impl<Value> From<Color<Value>> for Vec3<Value>
{
fn from(color: Color<Value>) -> Self