From b092f64b8b30207b3d5a848c67a62076adc83e88 Mon Sep 17 00:00:00 2001 From: MichalSt Date: Fri, 22 Dec 2023 16:13:48 +0000 Subject: [PATCH] Added a phong renderer variation for uniform colour. The new variation allows lighting + a uniform set colour. Renamed shader phong to phong-texture. Added shader phong-uColour. Texture component owns an additional colour as a backfall when no texture is supplied. Added a scene with two spheres using the new shader. --- source/Component/Texture.cpp | 12 ++ source/Component/Texture.hpp | 5 + .../GLSL/{phong.frag => phong-texture.frag} | 0 .../GLSL/{phong.vert => phong-texture.vert} | 0 source/OpenGL/GLSL/phong-uColour.frag | 186 ++++++++++++++++++ source/OpenGL/GLSL/phong-uColour.vert | 27 +++ source/OpenGL/OpenGLRenderer.cpp | 42 ++-- source/OpenGL/PhongRenderer.cpp | 41 ++-- source/OpenGL/PhongRenderer.hpp | 6 +- source/System/SceneSystem.cpp | 38 +++- source/System/SceneSystem.hpp | 1 + 11 files changed, 329 insertions(+), 29 deletions(-) rename source/OpenGL/GLSL/{phong.frag => phong-texture.frag} (100%) rename source/OpenGL/GLSL/{phong.vert => phong-texture.vert} (100%) create mode 100644 source/OpenGL/GLSL/phong-uColour.frag create mode 100644 source/OpenGL/GLSL/phong-uColour.vert diff --git a/source/Component/Texture.cpp b/source/Component/Texture.cpp index ea9dbee..a4159a5 100644 --- a/source/Component/Texture.cpp +++ b/source/Component/Texture.cpp @@ -22,11 +22,19 @@ namespace Component : m_diffuse{} , m_specular{} , m_shininess{32.f} + , m_colour{glm::vec4(1.f)} {} Texture::Texture(const TextureRef& m_diffuse) noexcept : m_diffuse{m_diffuse} , m_specular{} , m_shininess{32.f} + , m_colour{glm::vec4(1.f)} + {} + Texture::Texture(const glm::vec4& p_colour) noexcept + : m_diffuse{} + , m_specular{} + , m_shininess{32.f} + , m_colour{p_colour} {} void Texture::draw_UI(System::TextureSystem& p_texture_system) @@ -48,6 +56,10 @@ namespace Component m_specular = p_texture_system.getTexture(availableTextures[selected]); ImGui::Slider("Shininess", m_shininess, 1.f, 512.f, "%.1f"); + ImGui::ColorEdit4("Colour", &m_colour[0]); + ImGui::SameLine(); + ImGui::Text("Used if no textures are specified."); + ImGui::TreePop(); } } diff --git a/source/Component/Texture.hpp b/source/Component/Texture.hpp index cdd3692..563846b 100644 --- a/source/Component/Texture.hpp +++ b/source/Component/Texture.hpp @@ -4,6 +4,7 @@ #include "Utility/ResourceManager.hpp" #include "Utility/File.hpp" +#include #include namespace Data @@ -41,8 +42,12 @@ namespace Component TextureRef m_specular; float m_shininess; + glm::vec4 m_colour; + Texture() noexcept; Texture(const TextureRef& m_diffuse) noexcept; + Texture(const glm::vec4& p_colour) noexcept; + void draw_UI(System::TextureSystem& p_texture_system); }; }; // namespace Component \ No newline at end of file diff --git a/source/OpenGL/GLSL/phong.frag b/source/OpenGL/GLSL/phong-texture.frag similarity index 100% rename from source/OpenGL/GLSL/phong.frag rename to source/OpenGL/GLSL/phong-texture.frag diff --git a/source/OpenGL/GLSL/phong.vert b/source/OpenGL/GLSL/phong-texture.vert similarity index 100% rename from source/OpenGL/GLSL/phong.vert rename to source/OpenGL/GLSL/phong-texture.vert diff --git a/source/OpenGL/GLSL/phong-uColour.frag b/source/OpenGL/GLSL/phong-uColour.frag new file mode 100644 index 0000000..8888844 --- /dev/null +++ b/source/OpenGL/GLSL/phong-uColour.frag @@ -0,0 +1,186 @@ +#version 430 core + +uniform vec3 view_position; +uniform float shininess; +uniform sampler2D diffuse; +uniform sampler2D specular; + +uniform sampler2D shadow_map; +uniform float PCF_bias; +uniform vec4 uColour; + +struct DirectionalLight +{ + vec3 direction; + + vec3 ambient; + vec3 diffuse; + vec3 specular; +}; +buffer DirectionalLightsBuffer +{ + uint number_of_directional_lights; + DirectionalLight directional_lights[]; +}; +vec4 directional_light_contribution(DirectionalLight p_light, vec3 p_frag_normal, vec3 p_view_direction); + + +struct PointLight +{ + vec3 position; + + float constant; + float linear; + float quadratic; + + vec3 ambient; + vec3 diffuse; + vec3 specular; +}; +buffer PointLightsBuffer +{ + uint number_of_point_lights; + PointLight point_lights[]; +}; +vec4 point_light_contribution(PointLight p_light, vec3 p_frag_normal, vec3 p_frag_pos, vec3 p_view_direction); + + +struct SpotLight +{ + vec3 position; + + vec3 direction; + float cutoff; + float outer_cutoff; + + float constant; + float linear; + float quadratic; + + vec3 ambient; + vec3 diffuse; + vec3 specular; +}; +buffer SpotLightsBuffer +{ + uint number_of_spot_lights; + SpotLight spot_lights[]; +}; +vec4 spot_light_contribution(SpotLight p_light, vec3 p_frag_normal, vec3 p_frag_pos, vec3 p_view_direction); + + +float shadow_calculation(vec4 frag_position_light_space); + +in VS_OUT { + vec3 position; + vec3 normal; + vec4 position_light_space; +} fs_in; +out vec4 Colour; + +void main() +{ + Colour = vec4(0.0, 0.0, 0.0, 1.0); + + vec3 frag_normal = normalize(fs_in.normal); + vec3 view_direction = normalize(view_position - fs_in.position); + + for (uint i = 0; i < number_of_point_lights; i++) + { + Colour += point_light_contribution(point_lights[i], frag_normal, fs_in.position, view_direction); + } + for (uint i = 0; i < number_of_spot_lights; i++) + { + Colour += spot_light_contribution(spot_lights[i], frag_normal, fs_in.position, view_direction); + } + for (uint i = 0; i < number_of_directional_lights; i++) + { + Colour += directional_light_contribution(directional_lights[i], frag_normal, view_direction); + } +} + +vec4 directional_light_contribution(DirectionalLight p_light, vec3 p_frag_normal, vec3 p_view_direction) +{ + vec3 light_direction = normalize(-p_light.direction); + + // diffuse shading + float diff = max(dot(p_frag_normal, light_direction), 0.0); + + // specular shading + vec3 reflect_direction = reflect(-light_direction, p_frag_normal); + float spec = pow(max(dot(p_view_direction, reflect_direction), 0.0), shininess); + + // combine results + vec3 ambient = p_light.ambient * vec3(uColour.rgb); + vec3 diffuse = p_light.diffuse * diff * vec3(uColour.rgb); + vec3 specular = p_light.specular * spec * vec3(uColour.rgb); + + float shadow = shadow_calculation(fs_in.position_light_space); + //shadow = 0.0; + return vec4((ambient + (shadow * (diffuse + specular))).xyz, 1.0); + //return vec4((ambient + diffuse + specular).xyz, 1.0); +} +vec4 point_light_contribution(PointLight p_light, vec3 p_frag_normal, vec3 p_frag_pos, vec3 p_view_direction) +{ + vec3 light_direction = normalize(p_light.position - p_frag_pos); + + // diffuse shading + float diff = max(dot(p_frag_normal, light_direction), 0.0); + + // specular shading + vec3 reflect_direction = reflect(-light_direction, p_frag_normal); + float spec = pow(max(dot(p_view_direction, reflect_direction), 0.0), shininess); + + // attenuation + float distance = length(p_light.position - p_frag_pos); + float attenuation = 1.0 / (p_light.constant + p_light.linear * distance + p_light.quadratic * (distance * distance)); + + // combine results + vec3 ambient = p_light.ambient * vec3(uColour.rgb) * attenuation; + vec3 diffuse = p_light.diffuse * diff * vec3(uColour.rgb) * attenuation; + vec3 specular = p_light.specular * spec * vec3(uColour.rgb) * attenuation; + + return vec4((ambient + diffuse + specular).xyz, 1.0); +} +vec4 spot_light_contribution(SpotLight p_light, vec3 p_frag_normal, vec3 p_frag_pos, vec3 p_view_direction) +{ + vec3 light_direction = normalize(p_light.position - p_frag_pos); + + // diffuse shading + float diff = max(dot(p_frag_normal, light_direction), 0.0); + + // specular shading + vec3 reflect_direction = reflect(-light_direction, p_frag_normal); + float spec = pow(max(dot(p_view_direction, reflect_direction), 0.0), shininess); + + // attenuation + float distance = length(p_light.position - p_frag_pos); + float attenuation = 1.0 / (p_light.constant + p_light.linear * distance + p_light.quadratic * (distance * distance)); + + // spotlight intensity + float theta = dot(light_direction, normalize(-p_light.direction)); + float epsilon = p_light.cutoff - p_light.outer_cutoff; + float intensity = clamp((theta - p_light.outer_cutoff) / epsilon, 0.0, 1.0); + + // combine results + vec3 ambient = p_light.ambient * vec3(uColour.rgb) * attenuation * intensity; + vec3 diffuse = p_light.diffuse * diff * vec3(uColour.rgb) * attenuation * intensity; + vec3 specular = p_light.specular * spec * vec3(uColour.rgb) * attenuation * intensity; + + return vec4((ambient + diffuse + specular).xyz, 1.0); +} + +float shadow_calculation(vec4 frag_position_light_space) +{ + // If the depth of the frag_position_light_space is larger than the closest depth from the light perspective. + // The fragment being rendered is ocluded. + + // perform perspective divide + transfrom to [0,1] texture space + vec3 projected_coords = ((frag_position_light_space.xyz / frag_position_light_space.w) * 0.5) + 0.5; + // get depth of current fragment from light's perspective + float frag_depth_light_space = projected_coords.z; + // get closest depth value from light's perspective (using [0,1] range fragPosLight as coords) + float closest_depth = texture(shadow_map, projected_coords.xy).r; + // check whether current frag pos is in shadow + return frag_depth_light_space + PCF_bias > closest_depth ? 0.5 : 1.0; +} \ No newline at end of file diff --git a/source/OpenGL/GLSL/phong-uColour.vert b/source/OpenGL/GLSL/phong-uColour.vert new file mode 100644 index 0000000..dc87988 --- /dev/null +++ b/source/OpenGL/GLSL/phong-uColour.vert @@ -0,0 +1,27 @@ +#version 430 core + +layout (location = 0) in vec3 VertexPosition; +layout (location = 1) in vec3 VertexNormal; + +uniform mat4 model; +uniform mat4 light_proj_view; + +layout(shared) uniform ViewProperties +{ + mat4 view; + mat4 projection; +} viewProperties; + +out VS_OUT { + vec3 position; + vec3 normal; + vec4 position_light_space; +} vs_out; + +void main() +{ + vs_out.position = vec3(model * vec4(VertexPosition, 1.0)); + vs_out.normal = mat3(transpose(inverse(model))) * VertexNormal; + vs_out.position_light_space = light_proj_view * vec4(vs_out.position, 1.0); + gl_Position = viewProperties.projection * viewProperties.view * model * vec4(VertexPosition, 1.0); +} \ No newline at end of file diff --git a/source/OpenGL/OpenGLRenderer.cpp b/source/OpenGL/OpenGLRenderer.cpp index 7518b88..9f775a1 100644 --- a/source/OpenGL/OpenGLRenderer.cpp +++ b/source/OpenGL/OpenGLRenderer.cpp @@ -96,20 +96,36 @@ namespace OpenGL scene.foreach([&](ECS::Entity& p_entity, Component::Transform& p_transform, Component::Mesh& mesh_comp) { - if (scene.has_components(p_entity)) + if (mesh_comp.m_mesh) { - auto& texComponent = scene.get_component(p_entity); + if (scene.has_components(p_entity)) + { + auto& texComponent = scene.get_component(p_entity); + + if (texComponent.m_diffuse.has_value()) + { + DrawCall dc; + dc.set_uniform("view_position", m_view_information.m_view_position); + dc.set_uniform("model", p_transform.m_model); + dc.set_uniform("shininess", texComponent.m_shininess); + dc.set_texture("diffuse", texComponent.m_diffuse); + dc.set_texture("specular", texComponent.m_specular.has_value() ? texComponent.m_specular : m_blank_texture); + dc.submit(m_phong_renderer.get_texture_shader(), mesh_comp.m_mesh); + } + else // Has a Mesh and Texture but no diffuse texture. Use the colour instead. + { + DrawCall dc; + dc.set_uniform("view_position", m_view_information.m_view_position); + dc.set_uniform("model", p_transform.m_model); + dc.set_uniform("shininess", texComponent.m_shininess); + dc.set_uniform("uColour", texComponent.m_colour); + dc.submit(m_phong_renderer.get_uniform_colour_shader(), mesh_comp.m_mesh); + } + + return; + } - DrawCall dc; - dc.set_uniform("view_position", m_view_information.m_view_position); - dc.set_uniform("model", p_transform.m_model); - dc.set_uniform("shininess", texComponent.m_shininess); - dc.set_texture("diffuse", texComponent.m_diffuse.has_value() ? texComponent.m_diffuse : m_missing_texture); - dc.set_texture("specular", texComponent.m_specular.has_value() ? texComponent.m_specular : m_blank_texture); - dc.submit(m_phong_renderer.get_shader(), mesh_comp.m_mesh); - } - else - { + // Fallback to rendering using default colour and no lighting. DrawCall dc; dc.set_uniform("model", p_transform.m_model); dc.set_uniform("colour", glm::vec4(0.06f, 0.44f, 0.81f, 1.f)); @@ -126,7 +142,7 @@ namespace OpenGL dc.set_uniform("shininess", 64.f); dc.set_texture("diffuse", p_terrain.m_texture.has_value() ? p_terrain.m_texture : m_missing_texture); dc.set_texture("specular", m_blank_texture); - dc.submit(m_phong_renderer.get_shader(), p_terrain.m_mesh); + dc.submit(m_phong_renderer.get_texture_shader(), p_terrain.m_mesh); }); } diff --git a/source/OpenGL/PhongRenderer.cpp b/source/OpenGL/PhongRenderer.cpp index 93daa15..7da22d5 100644 --- a/source/OpenGL/PhongRenderer.cpp +++ b/source/OpenGL/PhongRenderer.cpp @@ -11,8 +11,9 @@ namespace OpenGL { PhongRenderer::PhongRenderer() - : m_phong_shader{"phong"} - , m_directional_lights_buffer{m_phong_shader.get_SSBO_backing("DirectionalLightsBuffer")} + : m_phong_texture{"phong-texture"} + , m_phong_uniform_colour{"phong-uColour"} + , m_directional_lights_buffer{m_phong_texture.get_SSBO_backing("DirectionalLightsBuffer")} , m_directional_light_fixed_size{0} , m_directional_light_count_offset{0} , m_directional_light_array_stride{0} @@ -21,7 +22,7 @@ namespace OpenGL , m_directional_light_ambient_offset{0} , m_directional_light_diffuse_offset{0} , m_directional_light_specular_offset{0} - , m_point_lights_buffer{m_phong_shader.get_SSBO_backing("PointLightsBuffer")} + , m_point_lights_buffer{m_phong_texture.get_SSBO_backing("PointLightsBuffer")} , m_point_light_fixed_size{0} , m_point_light_count_offset{0} , m_point_light_array_stride{0} @@ -33,7 +34,7 @@ namespace OpenGL , m_point_light_ambient_offset{0} , m_point_light_diffuse_offset{0} , m_point_light_specular_offset{0} - , m_spot_lights_buffer{m_phong_shader.get_SSBO_backing("SpotLightsBuffer")} + , m_spot_lights_buffer{m_phong_texture.get_SSBO_backing("SpotLightsBuffer")} , m_spot_light_fixed_size{0} , m_spot_light_count_offset{0} , m_spot_light_array_stride{0} @@ -260,19 +261,33 @@ namespace OpenGL void PhongRenderer::update_light_data(System::Scene& p_scene, const Texture& p_shadow_map) { - m_phong_shader.use(); + {// Set Directional light shadow data + { + m_phong_texture.use(); + p_scene.m_entities.foreach([this, &p_scene](Component::DirectionalLight& p_light) + { + m_phong_texture.set_uniform("light_proj_view", p_light.get_view_proj(p_scene.m_bound)); + }); + + m_phong_texture.set_uniform("PCF_bias", Component::DirectionalLight::PCF_bias); - { // Set Directional light shadow data - p_scene.m_entities.foreach([this, &p_scene](Component::DirectionalLight& p_light) + active_texture(2); + m_phong_texture.set_uniform("shadow_map", 2); + p_shadow_map.bind(); + } { - m_phong_shader.set_uniform("light_proj_view", p_light.get_view_proj(p_scene.m_bound)); - }); + m_phong_uniform_colour.use(); + p_scene.m_entities.foreach([this, &p_scene](Component::DirectionalLight& p_light) + { + m_phong_uniform_colour.set_uniform("light_proj_view", p_light.get_view_proj(p_scene.m_bound)); + }); - m_phong_shader.set_uniform("PCF_bias", Component::DirectionalLight::PCF_bias); + m_phong_uniform_colour.set_uniform("PCF_bias", Component::DirectionalLight::PCF_bias); - active_texture(2); - m_phong_shader.set_uniform("shadow_map", 2); - p_shadow_map.bind(); + active_texture(2); + m_phong_uniform_colour.set_uniform("shadow_map", 2); + p_shadow_map.bind(); + } } { // Set DirectonalLight buffer data diff --git a/source/OpenGL/PhongRenderer.hpp b/source/OpenGL/PhongRenderer.hpp index 5d6aa09..77558c2 100644 --- a/source/OpenGL/PhongRenderer.hpp +++ b/source/OpenGL/PhongRenderer.hpp @@ -15,7 +15,8 @@ namespace OpenGL { class PhongRenderer { - Shader m_phong_shader; // Used to fetch the Directional, Point and spot light buffers. + Shader m_phong_texture; // Variation of phong shader that uses specular and diffuse textures. Used to fetch the Directional, Point and spot light buffers. + Shader m_phong_uniform_colour; // Variation of phong shader that uses a uniform colour instead of a texture. Utility::ResourceRef m_directional_lights_buffer; // The SSBO used across shaders to bind DirectionalLight data. GLsizeiptr m_directional_light_fixed_size; // Size in bytes of the fixed portion of the directional light shader storage block (excludes any variable-sized-array variables sizes). @@ -58,7 +59,8 @@ namespace OpenGL public: PhongRenderer(); - Shader& get_shader() { return m_phong_shader; } + Shader& get_texture_shader() { return m_phong_texture; } + Shader& get_uniform_colour_shader() { return m_phong_uniform_colour; } // Update the storage block buffer object data for all the lights in p_storage. // Only needs to happen once per frame or on changes to a light. diff --git a/source/System/SceneSystem.cpp b/source/System/SceneSystem.cpp index 896060a..1745561 100644 --- a/source/System/SceneSystem.cpp +++ b/source/System/SceneSystem.cpp @@ -17,6 +17,7 @@ #include "Geometry/Geometry.hpp" #include "Utility/Config.hpp" +#include "Utility/MeshBuilder.hpp" namespace System { @@ -26,7 +27,8 @@ namespace System , m_scene{} { add_default_camera(); - primitives_scene(); + construct_2_sphere_scene(); + //primitives_scene(); //constructBoxScene(); //constructBouncingBallScene(); } @@ -243,6 +245,40 @@ namespace System } } } + void SceneSystem::construct_2_sphere_scene() + { + auto mb = Utility::MeshBuilder{}; + mb.add_icosphere(glm::vec3(0.f), 1.f, 1); + auto icosphere_mesh = mb.get_mesh(); + auto icosphere_meshref = m_mesh_system.insert(std::move(icosphere_mesh)); + + m_scene.m_entities.add_entity( + Component::Label{"Directional light 1"}, + Component::DirectionalLight{glm::vec3(0.f, -1.f, 0.f), 0.f, 0.5f}); + + { // Red point light in-front of the box. + auto point_light = Component::PointLight{}; + point_light.m_position = glm::vec3(0.f, 3.f, 0.f); + point_light.m_colour = glm::vec3(1.f); + m_scene.m_entities.add_entity(Component::Label{"Point light"}, point_light); + } + + m_scene.m_entities.add_entity( + Component::Label{"Sphere 1"}, + Component::RigidBody{}, + Component::Transform{glm::vec3(2.f, 0.f, 0.f)}, + Component::Mesh{icosphere_meshref}, + Component::Texture{glm::vec4(0.5f, 0.5f, 0.5f, 1.f)}, + Component::Collider{}); + + m_scene.m_entities.add_entity( + Component::Label{"Sphere 2"}, + Component::RigidBody{}, + Component::Transform{glm::vec3(5.f, 0.f, 0.f)}, + Component::Mesh{icosphere_meshref}, + Component::Texture{glm::vec4(0.5f, 0.5f, 0.5f, 1.f)}, + Component::Collider{}); + } void SceneSystem::constructBouncingBallScene() { const auto containerDiffuse = Config::Texture_Directory / "metalContainerDiffuse.png"; diff --git a/source/System/SceneSystem.hpp b/source/System/SceneSystem.hpp index 28289f8..6315ec2 100644 --- a/source/System/SceneSystem.hpp +++ b/source/System/SceneSystem.hpp @@ -37,6 +37,7 @@ namespace System void add_default_camera(); void constructBouncingBallScene(); void constructBoxScene(); + void construct_2_sphere_scene(); void primitives_scene(); }; } // namespace System \ No newline at end of file