summaryrefslogtreecommitdiff
path: root/engine/src/renderer
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2024-11-23 21:32:03 +0100
committerHampusM <hampus@hampusmat.com>2024-11-23 21:32:03 +0100
commitdaf280048d82eed42d44423ce50ae9e809ba91a9 (patch)
treefdd1580b3c50f2f7cebc5175b38777a7117c904f /engine/src/renderer
parent999264a46f9a545771c6710b0893ca32cf6e7ee3 (diff)
refactor(engine): make shaders a renderer detail
Diffstat (limited to 'engine/src/renderer')
-rw-r--r--engine/src/renderer/opengl.rs99
-rw-r--r--engine/src/renderer/opengl/glsl/fragment.glsl73
-rw-r--r--engine/src/renderer/opengl/glsl/light.glsl133
-rw-r--r--engine/src/renderer/opengl/glsl/vertex.glsl24
-rw-r--r--engine/src/renderer/opengl/glsl/vertex_data.glsl11
5 files changed, 305 insertions, 35 deletions
diff --git a/engine/src/renderer/opengl.rs b/engine/src/renderer/opengl.rs
index 6e6347b..deb26a8 100644
--- a/engine/src/renderer/opengl.rs
+++ b/engine/src/renderer/opengl.rs
@@ -2,7 +2,9 @@
use std::collections::HashMap;
use std::ffi::{c_void, CString};
+use std::io::{Error as IoError, ErrorKind as IoErrorKind};
use std::ops::Deref;
+use std::path::Path;
use std::process::abort;
use ecs::actions::Actions;
@@ -24,8 +26,13 @@ use crate::mesh::Mesh;
use crate::opengl::buffer::{Buffer, Usage as BufferUsage};
#[cfg(feature = "debug")]
use crate::opengl::debug::{MessageSeverity, MessageSource, MessageType};
+use crate::opengl::glsl::{
+ preprocess as glsl_preprocess,
+ PreprocessingError as GlslPreprocessingError,
+};
use crate::opengl::shader::{
Error as GlShaderError,
+ Kind as ShaderKind,
Program as GlShaderProgram,
Shader as GlShader,
};
@@ -41,7 +48,6 @@ use crate::opengl::vertex_array::{
};
use crate::opengl::{clear_buffers, enable, BufferClearMask, Capability};
use crate::projection::{new_perspective_matrix, Projection};
-use crate::shader::Program as ShaderProgram;
use crate::texture::{Id as TextureId, Texture};
use crate::transform::{Position, Scale};
use crate::util::NeverDrop;
@@ -51,7 +57,6 @@ use crate::window::Window;
type RenderableEntity = (
Mesh,
- ShaderProgram,
Material,
Option<MaterialFlags>,
Option<Position>,
@@ -137,34 +142,24 @@ fn render(
let directional_lights = directional_lights.iter().collect::<Vec<_>>();
let GlobalGlObjects {
- shader_programs: gl_shader_programs,
+ shader_program,
textures: gl_textures,
} = &mut *gl_objects;
+ let shader_program =
+ shader_program.get_or_insert_with(|| create_default_shader_program().unwrap());
+
clear_buffers(BufferClearMask::COLOR | BufferClearMask::DEPTH);
for (
entity_index,
- (
- mesh,
- shader_program,
- material,
- material_flags,
- position,
- scale,
- draw_flags,
- gl_objects,
- ),
+ (mesh, material, material_flags, position, scale, draw_flags, gl_objects),
) in query.iter().enumerate()
{
let material_flags = material_flags
.map(|material_flags| material_flags.clone())
.unwrap_or_default();
- let shader_program = gl_shader_programs
- .entry(shader_program.u64_hash())
- .or_insert_with(|| create_gl_shader_program(&shader_program).unwrap());
-
let new_gl_objects;
let gl_objects = if let Some(gl_objects) = gl_objects.as_deref() {
@@ -248,7 +243,7 @@ fn render(
#[derive(Debug, Default, Component)]
struct GlobalGlObjects
{
- shader_programs: HashMap<u64, GlShaderProgram>,
+ shader_program: Option<GlShaderProgram>,
textures: HashMap<TextureId, GlTexture>,
}
@@ -300,34 +295,68 @@ fn create_gl_texture(texture: &Texture) -> GlTexture
gl_texture
}
-fn create_gl_shader_program(
- shader_program: &ShaderProgram,
-) -> Result<GlShaderProgram, GlShaderError>
+const VERTEX_GLSL_SHADER_SRC: &str = include_str!("opengl/glsl/vertex.glsl");
+const FRAGMENT_GLSL_SHADER_SRC: &str = include_str!("opengl/glsl/fragment.glsl");
+
+const VERTEX_DATA_GLSL_SHADER_SRC: &str = include_str!("opengl/glsl/vertex_data.glsl");
+const LIGHT_GLSL_SHADER_SRC: &str = include_str!("opengl/glsl/light.glsl");
+
+fn create_default_shader_program() -> Result<GlShaderProgram, CreateShaderError>
{
- let gl_shaders = shader_program
- .shaders()
- .iter()
- .map(|shader| {
- let gl_shader = GlShader::new(shader.kind());
+ let mut vertex_shader = GlShader::new(ShaderKind::Vertex);
- gl_shader.set_source(shader.source())?;
- gl_shader.compile()?;
+ vertex_shader.set_source(&*glsl_preprocess(
+ VERTEX_GLSL_SHADER_SRC,
+ &get_glsl_shader_content,
+ )?)?;
- Ok(gl_shader)
- })
- .collect::<Result<Vec<_>, _>>()?;
+ vertex_shader.compile()?;
- let gl_shader_program = GlShaderProgram::new();
+ let mut fragment_shader = GlShader::new(ShaderKind::Fragment);
- for gl_shader in &gl_shaders {
- gl_shader_program.attach(gl_shader);
- }
+ fragment_shader.set_source(&*glsl_preprocess(
+ FRAGMENT_GLSL_SHADER_SRC,
+ &get_glsl_shader_content,
+ )?)?;
+
+ fragment_shader.compile()?;
+
+ let mut gl_shader_program = GlShaderProgram::new();
+
+ gl_shader_program.attach(&vertex_shader);
+ gl_shader_program.attach(&fragment_shader);
gl_shader_program.link()?;
Ok(gl_shader_program)
}
+#[derive(Debug, thiserror::Error)]
+enum CreateShaderError
+{
+ #[error(transparent)]
+ ShaderError(#[from] GlShaderError),
+
+ #[error(transparent)]
+ PreprocessingError(#[from] GlslPreprocessingError),
+}
+
+fn get_glsl_shader_content(path: &Path) -> Result<Vec<u8>, std::io::Error>
+{
+ if path == Path::new("vertex_data.glsl") {
+ return Ok(VERTEX_DATA_GLSL_SHADER_SRC.as_bytes().to_vec());
+ }
+
+ if path == Path::new("light.glsl") {
+ return Ok(LIGHT_GLSL_SHADER_SRC.as_bytes().to_vec());
+ }
+
+ Err(IoError::new(
+ IoErrorKind::NotFound,
+ format!("Content for shader file {} not found", path.display()),
+ ))
+}
+
#[derive(Debug, Component)]
struct GlObjects
{
diff --git a/engine/src/renderer/opengl/glsl/fragment.glsl b/engine/src/renderer/opengl/glsl/fragment.glsl
new file mode 100644
index 0000000..5bf5ff2
--- /dev/null
+++ b/engine/src/renderer/opengl/glsl/fragment.glsl
@@ -0,0 +1,73 @@
+#version 330 core
+
+#preinclude "light.glsl"
+#preinclude "vertex_data.glsl"
+
+#define MAX_LIGHT_CNT 64
+
+out vec4 FragColor;
+
+in VertexData vertex_data;
+
+uniform vec3 view_pos;
+uniform sampler2D input_texture;
+uniform Material material;
+
+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++) {
+ 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,
+ 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 + directional_light_sum + point_light_sum), 1.0);
+}
diff --git a/engine/src/renderer/opengl/glsl/light.glsl b/engine/src/renderer/opengl/glsl/light.glsl
new file mode 100644
index 0000000..1bc23a4
--- /dev/null
+++ b/engine/src/renderer/opengl/glsl/light.glsl
@@ -0,0 +1,133 @@
+#version 330 core
+
+#ifndef LIGHT_GLSL
+#define LIGHT_GLSL
+
+#preinclude "vertex_data.glsl"
+
+struct Material
+{
+ vec3 ambient;
+ vec3 diffuse;
+ vec3 specular;
+ sampler2D ambient_map;
+ sampler2D diffuse_map;
+ sampler2D specular_map;
+ float shininess;
+};
+
+struct LightPhong
+{
+ vec3 diffuse;
+ vec3 specular;
+};
+
+struct AttenuationProperties
+{
+ float constant;
+ float linear;
+ float quadratic;
+};
+
+struct PointLight
+{
+ LightPhong phong;
+ vec3 position;
+ 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;
+}
+
+vec3 calc_diffuse_light(
+ in Material material,
+ in LightPhong light_phong,
+ in vec3 light_dir,
+ in vec3 norm,
+ in vec2 texture_coords
+)
+{
+ float diff = max(dot(norm, light_dir), 0.0);
+
+ return light_phong.diffuse * (
+ diff * (vec3(texture(material.diffuse_map, texture_coords)) * material.diffuse)
+ );
+}
+
+vec3 calc_specular_light(
+ in Material material,
+ in LightPhong light_phong,
+ in vec3 light_dir,
+ in vec3 norm,
+ in vec3 view_pos,
+ in vec3 frag_pos,
+ in vec2 texture_coords
+)
+{
+ vec3 view_direction = normalize(view_pos - frag_pos);
+
+ vec3 reflect_direction = reflect(-light_dir, norm);
+
+ float spec =
+ pow(max(dot(view_direction, reflect_direction), 0.0), material.shininess);
+
+ return light_phong.specular * (
+ spec * (vec3(texture(material.specular_map, texture_coords)) * material.specular)
+ );
+}
+
+float calc_attenuation(in PointLight point_light, in vec3 position)
+{
+ float light_distance = length(point_light.position - position);
+
+ return 1.0 / (point_light.attenuation_props.constant
+ + point_light.attenuation_props.linear
+ * light_distance + point_light.attenuation_props.quadratic
+ * pow(light_distance, 2));
+}
+
+void calc_light(
+ in vec3 light_direction,
+ in LightPhong light_phong,
+ in VertexData vertex_data,
+ in vec3 view_pos,
+ in Material material,
+ out CalculatedLight calculated_light
+)
+{
+ vec3 norm = normalize(vertex_data.world_space_normal);
+
+ calculated_light.diffuse = calc_diffuse_light(
+ material,
+ light_phong,
+ light_direction,
+ norm,
+ vertex_data.texture_coords
+ );
+
+ calculated_light.specular = calc_specular_light(
+ material,
+ light_phong,
+ light_direction,
+ norm,
+ view_pos,
+ vertex_data.world_space_pos,
+ vertex_data.texture_coords
+ );
+}
+
+#endif
diff --git a/engine/src/renderer/opengl/glsl/vertex.glsl b/engine/src/renderer/opengl/glsl/vertex.glsl
new file mode 100644
index 0000000..b57caa6
--- /dev/null
+++ b/engine/src/renderer/opengl/glsl/vertex.glsl
@@ -0,0 +1,24 @@
+#version 330 core
+
+#preinclude "vertex_data.glsl"
+
+layout (location = 0) in vec3 pos;
+layout (location = 1) in vec2 texture_coords;
+layout (location = 2) in vec3 normal;
+
+out VertexData vertex_data;
+
+uniform mat4 model;
+uniform mat4 view;
+uniform mat4 projection;
+
+void main()
+{
+ gl_Position = projection * view * model * vec4(pos, 1.0);
+
+ vertex_data.world_space_pos = vec3(model * vec4(pos, 1.0));
+ vertex_data.texture_coords = texture_coords;
+
+ // TODO: Do this using CPU for performance increase
+ vertex_data.world_space_normal = mat3(transpose(inverse(model))) * normal;
+}
diff --git a/engine/src/renderer/opengl/glsl/vertex_data.glsl b/engine/src/renderer/opengl/glsl/vertex_data.glsl
new file mode 100644
index 0000000..486d445
--- /dev/null
+++ b/engine/src/renderer/opengl/glsl/vertex_data.glsl
@@ -0,0 +1,11 @@
+#ifndef VERTEX_DATA_GLSL
+#define VERTEX_DATA_GLSL
+
+struct VertexData
+{
+ vec2 texture_coords;
+ vec3 world_space_pos;
+ vec3 world_space_normal;
+};
+
+#endif