From c78454ade80bc2a2e8ce1c74b288132c1c770aac Mon Sep 17 00:00:00 2001 From: Joseph Walton-Rivers <joseph@walton-rivers.uk> Date: Sat, 9 Jul 2022 13:17:41 +0100 Subject: [PATCH] shaders based on opengl redbook --- demo/data/redbook/lighting_frag.glsl | 104 +++++++++++++++++++++++++++ demo/data/redbook/lighting_vert.glsl | 26 +++++++ demo/data/rollball.yml | 14 ++-- fggl/gfx/ogl/renderer.cpp | 4 +- fggl/gfx/ogl/shader.cpp | 3 + fggl/gfx/ogl4/models.cpp | 84 ++++++++++++++++++---- include/fggl/gfx/ogl/types.hpp | 5 ++ include/fggl/gfx/phong.hpp | 36 +++++----- 8 files changed, 237 insertions(+), 39 deletions(-) create mode 100644 demo/data/redbook/lighting_frag.glsl create mode 100644 demo/data/redbook/lighting_vert.glsl diff --git a/demo/data/redbook/lighting_frag.glsl b/demo/data/redbook/lighting_frag.glsl new file mode 100644 index 0000000..78242e7 --- /dev/null +++ b/demo/data/redbook/lighting_frag.glsl @@ -0,0 +1,104 @@ +/** + * OpenGL RedBook Shader. + * Examples 7.8, 7.9 and 7.10. + */ +#version 330 core + +struct LightProperties { + bool isEnabled; + bool isLocal; + bool isSpot; + + vec3 ambient; + vec3 colour; + vec3 position; + + vec3 halfVector; + vec3 coneDirection; + float spotCosCustoff; + float spotExponent; + float constantAttenuation; + float linearAttenuation; + float quadraticAttenuation; +}; + +// example 7.9 +struct MaterialProperties { + vec3 emission; + vec3 ambient; + vec3 diffuse; + vec3 specular; + float shininess; +}; + +const int MaxLights = 8; +uniform LightProperties lights[MaxLights]; + +const int MaxMaterials = 1; +uniform MaterialProperties materials[MaxMaterials]; + +uniform float Strength; +uniform vec3 EyeDirection; + +in vec4 Position; +in vec3 Normal; +in vec4 Colour; +flat in int MatIndex; + +out vec4 FragColour; + +void main() { + vec3 scatteredLight = vec3(0.0); + vec3 reflectedLight = vec3(0.0); + + for(int light = 0; light < MaxLights; ++light) { + if ( !lights[light].isEnabled ) continue; + + vec3 halfVector; + vec3 lightDirection = lights[light].position; + float attenuation = 1.0; + + float specular = 0; + if ( lights[light].isLocal ) { + lightDirection = lightDirection - vec3(Position); + float lightDistance = length(lightDirection); + lightDirection = lightDirection / lightDistance; + + attenuation = 1.0 / + lights[light].constantAttenuation + + lights[light].linearAttenuation * lightDistance + + lights[light].quadraticAttenuation * lightDistance * lightDistance; + + if ( lights[light].isSpot ) { + float spotCos = dot(lightDirection, -lights[light].coneDirection); + if ( spotCos < lights[light].spotCosCustoff ) + attenuation = 0.0; + else + attenuation *= pow(spotCos, lights[light].spotExponent); + } + + halfVector = normalize(lightDirection + EyeDirection); + specular = max(0.0, dot(Normal, halfVector)); + } else { + //halfVector = lights[light].halfVector; + halfVector = reflect(-lightDirection, Normal); + specular = max(0.0, dot(EyeDirection, halfVector)); + } + + float diffuse = max(0.0, dot(Normal, lightDirection)); + + + if (diffuse == 0.0) + specular = 0.0; + else + specular = pow(specular, materials[MatIndex].shininess) * Strength; + + scatteredLight += lights[light].ambient * materials[MatIndex].ambient * attenuation + + lights[light].colour * materials[MatIndex].diffuse * diffuse * attenuation; + reflectedLight += lights[light].colour * materials[MatIndex].specular * + specular * attenuation; + } + + vec3 rgb = min( materials[MatIndex].emission + Colour.rgb * scatteredLight + reflectedLight, vec3(1.0)); + FragColour = vec4(rgb, 1.0); +} \ No newline at end of file diff --git a/demo/data/redbook/lighting_vert.glsl b/demo/data/redbook/lighting_vert.glsl new file mode 100644 index 0000000..435d901 --- /dev/null +++ b/demo/data/redbook/lighting_vert.glsl @@ -0,0 +1,26 @@ +/** + * OpenGL RedBook Shader. + * Example 7.8 + */ +#version 330 core + +uniform mat4 MVPMatrix; +uniform mat4 MVMatrix; +uniform mat3 NormalMatrix; + +in vec4 VertexPosition; +in vec3 VertexNormal; +in vec4 VertexColour; + +out vec4 Position; +out vec3 Normal; +out vec4 Colour; +out int matIndex; + +void main() { + Colour = vec4(1.0, 1.0, 1.0, 1.0f); + Normal = NormalMatrix * VertexNormal; + Position = MVMatrix * VertexPosition; + gl_Position = MVPMatrix * VertexPosition; + matIndex = 0; +} \ No newline at end of file diff --git a/demo/data/rollball.yml b/demo/data/rollball.yml index defd6c0..c1258bf 100644 --- a/demo/data/rollball.yml +++ b/demo/data/rollball.yml @@ -4,7 +4,7 @@ prefabs: components: Transform: StaticMesh: - pipeline: phong + pipeline: redbook/lighting shape: type: box scale: [1.0, 5.0, 41] @@ -18,7 +18,7 @@ prefabs: components: Transform: StaticMesh: - pipeline: phong + pipeline: redbook/lighting shape: type: box scale: [39, 5, 1] @@ -31,7 +31,7 @@ prefabs: components: Transform: StaticMesh: - pipeline: phong + pipeline: redbook/lighting shape: type: box # we don't (currently) support planes... scale: [39, 0.5, 39] @@ -44,14 +44,14 @@ prefabs: components: Transform: StaticMesh: - pipeline: phong + pipeline: redbook/lighting shape: type: sphere gfx::material: ambient: [0.25, 0.25, 0.25] diffuse: [0.4, 0.4, 0.4] specular: [0.774597,0.774597,0.774597] - shininess: 0.6 + shininess: 16 phys::Body: shape: type: sphere @@ -60,14 +60,14 @@ prefabs: components: Transform: StaticMesh: - pipeline: phong + pipeline: redbook/lighting shape: type: box gfx::material: ambient: [0.0215, 0.1754, 0.0215] diffuse: [1, 1, 1] specular: [0.0633, 0.727811, 0.633] - shininess: 0.6 + shininess: 16 phys::Body: type: kinematic shape: diff --git a/fggl/gfx/ogl/renderer.cpp b/fggl/gfx/ogl/renderer.cpp index 45a42aa..f4fe812 100644 --- a/fggl/gfx/ogl/renderer.cpp +++ b/fggl/gfx/ogl/renderer.cpp @@ -169,8 +169,8 @@ namespace fggl::gfx { m_canvasPipeline = m_cache->get(ogl4::FALLBACK_CANVAS_PIPELINE); } - ShaderConfig shader3DConfig = ShaderFromName("phong"); - m_cache->load(shader3DConfig); + m_cache->load(ShaderFromName("phong")); + m_cache->load(ShaderFromName("redbook/lighting")); // rendering helpers m_canvasRenderer = std::make_unique<ogl4::CanvasRenderer>(fonts); diff --git a/fggl/gfx/ogl/shader.cpp b/fggl/gfx/ogl/shader.cpp index a38aec9..21403f4 100644 --- a/fggl/gfx/ogl/shader.cpp +++ b/fggl/gfx/ogl/shader.cpp @@ -62,6 +62,9 @@ ShaderCache::ShaderCache(fggl::data::Storage* storage) : m_storage(storage), m_s if ( !GLAD_GL_ARB_get_program_binary ) { spdlog::warn("the graphics card doesn support shader caching, disabling"); m_binary = false; + } else { + // debug - disable shader cache + m_binary = false; } if ( GLAD_GL_ARB_shading_language_include ) { diff --git a/fggl/gfx/ogl4/models.cpp b/fggl/gfx/ogl4/models.cpp index ed30c5c..62b3e0d 100644 --- a/fggl/gfx/ogl4/models.cpp +++ b/fggl/gfx/ogl4/models.cpp @@ -75,7 +75,15 @@ namespace fggl::gfx::ogl4 { auto* meshComp = world.get<data::StaticMesh>(renderable); auto* modelComp = world.add<StaticModel>(renderable); - setupComponent(modelComp, m_phong, meshComp->mesh); + + auto shader = m_phong; + try { + shader = std::make_shared<ogl::Shader>( m_shaders->get( meshComp->pipeline ) ); + } catch ( std::out_of_range& e) { + debug::log(debug::Level::warning, "Could not find shader: {}", meshComp->pipeline); + } + + setupComponent(modelComp, shader, meshComp->mesh); // no active model, we need to resolve/load one. spdlog::info("looks like {} needs a static mesh", renderable); @@ -153,27 +161,79 @@ namespace fggl::gfx::ogl4 { // new shader - need to re-send the view and projection matrices shader = model->pipeline; shader->use(); - shader->setUniformMtx(shader->uniform("view"), viewMatrix); - shader->setUniformMtx(shader->uniform("projection"), projectionMatrix); + if ( shader->hasUniform("projection") ) { + shader->setUniformMtx(shader->uniform("view"), viewMatrix); + shader->setUniformMtx(shader->uniform("projection"), projectionMatrix); + } } // set model transform auto* transform = world.get<math::Transform>(entity); - shader->setUniformMtx(shader->uniform("model"), transform->model()); + if (shader->hasUniform("model")) { + shader->setUniformMtx(shader->uniform("model"), transform->model()); + } else { + shader->setUniformMtx(shader->uniform("MVPMatrix"), projectionMatrix * viewMatrix * transform->model()); + shader->setUniformMtx(shader->uniform("MVMatrix"), viewMatrix * transform->model()); + + auto normalMatrix = glm::mat3(glm::transpose(inverse(transform->model()))); + shader->setUniformMtx(shader->uniform("NormalMatrix"), normalMatrix); + } + + // setup lighting mode + if ( shader->hasUniform("lights[0].isEnabled") ) { + bool local = true; + + shader->setUniformI(shader->uniform("lights[0].isEnabled"), 1); + shader->setUniformI(shader->uniform("lights[0].isLocal"), local); + shader->setUniformI(shader->uniform("lights[0].isSpot"), 0); + + shader->setUniformF(shader->uniform("lights[0].constantAttenuation"), 5.0f); + shader->setUniformF(shader->uniform("lights[0].linearAttenuation"), 0.0f); + shader->setUniformF(shader->uniform("lights[0].quadraticAttenuation"), 0.0f); + + shader->setUniformF(shader->uniform("Strength"), 0.6F); + + if (!local) { + lightPos = glm::normalize(lightPos); + auto viewDir = glm::normalize(camTransform->origin() - transform->origin()); + auto halfVector = glm::normalize(lightPos + viewDir); + shader->setUniformF(shader->uniform("lights[0].halfVector"), halfVector ); + shader->setUniformF(shader->uniform("EyeDirection"), viewDir); + shader->setUniformF(shader->uniform("lights[0].position"), lightPos); + } else { + auto camModelView = (viewMatrix * camTransform->model() * math::vec4(0.0f, 0.0f, 0.0f, 1.0f)); + auto modelModelView = (viewMatrix * transform->model() * math::vec4(0.0f, 0.0f, 0.0f, 1.0f)); + math::vec3 viewDir = glm::normalize(camModelView - modelModelView); + shader->setUniformF(shader->uniform("EyeDirection"), viewDir); + + shader->setUniformF(shader->uniform("lights[0].position"), math::vec3(viewMatrix * math::vec4(lightPos, 1.0f))); + } + + shader->setUniformF(shader->uniform("lights[0].ambient"), {0.0f, 0.5f, 0.0f}); + shader->setUniformF(shader->uniform("lights[0].colour"), {0.5f, 0.5f, 0.5f}); + } // material detection with fallback auto* material = &gfx::DEFAULT_MATERIAL; if ( world.has<PhongMaterial>(entity) ) { material = world.get<PhongMaterial>(entity); } - shader->setUniformF(shader->uniform("material.ambient"), material->ambient); - shader->setUniformF(shader->uniform("material.diffuse"), material->diffuse); - shader->setUniformF(shader->uniform("material.specular"), material->specular); - shader->setUniformF(shader->uniform("material.shininess"), material->shininess); - - auto lightPosIdx = shader->uniform("lightPos"); - if ( lightPosIdx != -1 ) { - shader->setUniformF(lightPosIdx, lightPos); + + if ( shader->hasUniform("material.ambient") ) { + shader->setUniformF(shader->uniform("material.ambient"), material->ambient); + shader->setUniformF(shader->uniform("material.diffuse"), material->diffuse); + shader->setUniformF(shader->uniform("material.specular"), material->specular); + shader->setUniformF(shader->uniform("material.shininess"), material->shininess); + } else { + shader->setUniformF(shader->uniform("materials[0].emission"), material->emission); + shader->setUniformF(shader->uniform("materials[0].ambient"), material->ambient); + shader->setUniformF(shader->uniform("materials[0].diffuse"), material->diffuse); + shader->setUniformF(shader->uniform("materials[0].specular"), material->specular); + shader->setUniformF(shader->uniform("materials[0].shininess"), material->shininess); + } + + if ( shader->hasUniform("lightPos")) { + shader->setUniformF( shader->uniform("lightPos"), lightPos); } auto vao = model->vao; diff --git a/include/fggl/gfx/ogl/types.hpp b/include/fggl/gfx/ogl/types.hpp index 25ae694..73b1b44 100644 --- a/include/fggl/gfx/ogl/types.hpp +++ b/include/fggl/gfx/ogl/types.hpp @@ -59,6 +59,11 @@ namespace fggl::gfx::ogl { glUseProgram( m_obj ); } + inline bool hasUniform(const std::string_view& name) const { + auto location = glGetUniformLocation( m_obj, name.data() ); + return location != -1; + } + inline Location uniform(const std::string_view& name) const { auto location = glGetUniformLocation( m_obj, name.data() ); if ( location == -1 ) { diff --git a/include/fggl/gfx/phong.hpp b/include/fggl/gfx/phong.hpp index 5c10908..e62773e 100644 --- a/include/fggl/gfx/phong.hpp +++ b/include/fggl/gfx/phong.hpp @@ -25,47 +25,47 @@ namespace fggl::gfx { struct PhongMaterial { constexpr static const char* name = "gfx::material"; + math::vec3 emission; math::vec3 ambient; math::vec3 diffuse; math::vec3 specular; float shininess; }; + constexpr math::vec3 DEFAULT_EMISSION {0.0F, 0.0F, 0.0F}; constexpr math::vec3 DEFAULT_AMBIENT { 0.05F, 0.05F, 0.05F}; constexpr math::vec3 DEFAULT_DIFFUSE { 0.5F, 0.5F, 0.5F}; constexpr math::vec3 DEFAULT_SPECULAR { 0.7F, 0.7F, 0.7F}; - constexpr float DEFAULT_SHININESS = .078125F; + //constexpr float DEFAULT_SHININESS = .078125F; + constexpr float DEFAULT_SHININESS = 16.0F; constexpr PhongMaterial DEFAULT_MATERIAL { + DEFAULT_EMISSION, DEFAULT_AMBIENT, DEFAULT_DIFFUSE, DEFAULT_SPECULAR, DEFAULT_SHININESS }; - - enum class LightType { - Directional, - Point, - Spot - }; - struct Light { constexpr static const char* name = "gfx::light"; - LightType type; - math::vec3 position; + bool enabled; + bool local; + bool spot; - // colours math::vec3 ambient; - math::vec3 diffuse; - math::vec3 specular; + math::vec3 colour; + math::vec3 position; + math::vec3 halfVector; + math::vec3 coneDirection; - // distance data - math::vec3 falloffs; // (constant, linear, quadratic) - float cutOff; - float outerCutOff; + float spotCosCutoff; + float spotExponent; + float constantAttenuation; + float linearAttenuation; + float quadraticAttenuation; }; -} // namesapce fggl::gfx +} // namespace fggl::gfx #endif //FGGL_GFX_PHONG_HPP -- GitLab