From ffdaa93edf5eeaf9db7dc17e51554a77dd9d596d Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 19 Nov 2022 15:04:30 +0000 Subject: Separate out the illumation of the scene --- gfx/gl/shaders/directionalLight.fs | 18 ++++++++++ gfx/gl/shaders/lightingShader.fs | 52 +++-------------------------- test/test-render.cpp | 29 ++++++++++------- ui/gameMainWindow.cpp | 17 +++++++--- ui/gameMainWindow.h | 6 +++- ui/sceneRenderer.cpp | 67 ++++++++++++++++++++++++++++++++++---- ui/sceneRenderer.h | 25 ++++++++++++-- ui/window.cpp | 1 + 8 files changed, 141 insertions(+), 74 deletions(-) create mode 100644 gfx/gl/shaders/directionalLight.fs diff --git a/gfx/gl/shaders/directionalLight.fs b/gfx/gl/shaders/directionalLight.fs new file mode 100644 index 0000000..7562f96 --- /dev/null +++ b/gfx/gl/shaders/directionalLight.fs @@ -0,0 +1,18 @@ +#version 330 core +#extension GL_ARB_shading_language_420pack : enable + +out vec3 FragColor; + +in vec2 TexCoords; + +layout(binding = 1) uniform sampler2D gNormal; + +uniform vec3 lightDirection; +uniform vec3 lightColour; + +void +main() +{ + const vec3 Normal = texture(gNormal, TexCoords).rgb; + FragColor = dot(-lightDirection, Normal) * lightColour; +} diff --git a/gfx/gl/shaders/lightingShader.fs b/gfx/gl/shaders/lightingShader.fs index b0ca20a..4646b75 100644 --- a/gfx/gl/shaders/lightingShader.fs +++ b/gfx/gl/shaders/lightingShader.fs @@ -5,58 +5,14 @@ out vec3 FragColor; in vec2 TexCoords; -layout(binding = 0) uniform sampler2D gPosition; -layout(binding = 1) uniform sampler2D gNormal; layout(binding = 2) uniform sampler2D gAlbedoSpec; - -// struct Light { -// vec3 Position; -// vec3 Color; - -// float Linear; -// float Quadratic; -// float Radius; -//}; -// const int NR_LIGHTS_MAX = 12; -// uniform Light lights[NR_LIGHTS_MAX]; -// uniform vec3 viewPos; - -uniform vec3 lightDirection = normalize(vec3(1, 0, -1)); -uniform vec3 lightColor = vec3(0.6, 0.6, 0.6); -uniform vec3 ambientColor = vec3(0.5, 0.5, 0.5); +layout(binding = 3) uniform sampler2D gIllumination; void main() { - // retrieve data from gbuffer - // const vec3 FragPos = texture(gPosition, TexCoords).rgb; - const vec3 Normal = texture(gNormal, TexCoords).rgb; - const vec3 Diffuse = texture(gAlbedoSpec, TexCoords).rgb; - // float Specular = texture(gAlbedoSpec, TexCoords).a; - - // then calculate lighting as usual - // vec3 lighting = Diffuse; - const vec3 lighting = ambientColor + clamp((dot(-lightDirection, Normal) * lightColor), 0, 0.5); - // vec3 viewDir = normalize(viewPos - FragPos); - // for (int i = 0; i < NR_LIGHTS_MAX; ++i) { - // calculate distance between light source and current fragment - // float distance = length(lights[i].Position - FragPos); - // if (distance < lights[i].Radius) { - // diffuse - // vec3 lightDir = normalize(lights[i].Position - FragPos); - // vec3 diffuse = max(dot(Normal, lightDir), 0.0) * Diffuse * lights[i].Color; - // specular - // vec3 halfwayDir = normalize(lightDir + viewDir); - // float spec = pow(max(dot(Normal, halfwayDir), 0.0), 16.0); - // vec3 specular = lights[i].Color * spec * Specular; - // attenuation - // float attenuation = 1.0 / (1.0 + lights[i].Linear * distance + lights[i].Quadratic * distance * distance); - // diffuse *= attenuation; - // specular *= attenuation; - // lighting += diffuse + specular; - //} - //} - // FragColor = vec4(lighting, 1.0); + const vec3 Albedo = texture(gAlbedoSpec, TexCoords).rgb; + const vec3 Illumination = texture(gIllumination, TexCoords).rgb; - FragColor = vec3(Diffuse * lighting); + FragColor = Albedo * Illumination; } diff --git a/test/test-render.cpp b/test/test-render.cpp index 62090e3..d5a79ec 100644 --- a/test/test-render.cpp +++ b/test/test-render.cpp @@ -54,6 +54,19 @@ public: } }; +class TestScene : public SceneRenderer::SceneProvider { + Terrain terrain {[]() { + auto gd = std::make_shared(GeoData::Limits {{0, 0}, {100, 100}}); + gd->generateRandom(); + return gd; + }()}; + void + content(const SceneShader & shader) const + { + terrain.render(shader); + } +}; + BOOST_GLOBAL_FIXTURE(ApplicationBase); BOOST_GLOBAL_FIXTURE(TestMainWindow); @@ -61,29 +74,21 @@ BOOST_FIXTURE_TEST_SUITE(w, TestRenderOutput); BOOST_AUTO_TEST_CASE(basic) { - auto gd = std::make_shared(GeoData::Limits {{0, 0}, {100, 100}}); - gd->generateRandom(); - Terrain terrain {gd}; SceneRenderer ss {size, output}; ss.camera.pos = {-10, -10, 60}; ss.camera.forward = glm::normalize(glm::vec3 {1, 1, -0.5F}); - ss.render([&terrain](const auto & shader) { - terrain.render(shader); - }); + TestScene scene; + ss.render(scene); Texture::save(outImage, size, "/tmp/basic.tga"); } BOOST_AUTO_TEST_CASE(pointlight) { - auto gd = std::make_shared(GeoData::Limits {{0, 0}, {100, 100}}); - gd->generateRandom(); - Terrain terrain {gd}; SceneRenderer ss {size, output}; ss.camera.pos = {-10, -10, 60}; ss.camera.forward = glm::normalize(glm::vec3 {1, 1, -0.5F}); - ss.render([&terrain](const auto & shader) { - terrain.render(shader); - }); + TestScene scene; + ss.render(scene); Texture::save(outImage, size, "/tmp/pointlight.tga"); } diff --git a/ui/gameMainWindow.cpp b/ui/gameMainWindow.cpp index c31265a..0e861b4 100644 --- a/ui/gameMainWindow.cpp +++ b/ui/gameMainWindow.cpp @@ -45,9 +45,18 @@ GameMainWindow::tick(TickDuration) void GameMainWindow::render() const { - SceneRenderer::render([this](const auto & shader) { - gameState->world.apply(&Renderable::render, shader); - uiComponents.apply(&WorldOverlay::render, shader); - }); + SceneRenderer::render(*this); Window::render(); } +void +GameMainWindow::content(const SceneShader & shader) const +{ + gameState->world.apply(&Renderable::render, shader); + uiComponents.apply(&WorldOverlay::render, shader); +} +void +GameMainWindow::environment(const SceneShader & s, const SceneRenderer & r) const +{ + // default for now + SceneRenderer::SceneProvider::environment(s, r); +} diff --git a/ui/gameMainWindow.h b/ui/gameMainWindow.h index 1e6af20..8485266 100644 --- a/ui/gameMainWindow.h +++ b/ui/gameMainWindow.h @@ -5,11 +5,15 @@ #include "window.h" #include -class GameMainWindow : public Window, SceneRenderer { +class GameMainWindow : public Window, SceneRenderer, public SceneRenderer::SceneProvider { public: GameMainWindow(size_t w, size_t h); void tick(TickDuration) override; void render() const override; + +private: + void content(const SceneShader &) const override; + void environment(const SceneShader &, const SceneRenderer &) const override; }; diff --git a/ui/sceneRenderer.cpp b/ui/sceneRenderer.cpp index 6a68ac6..c3cff7a 100644 --- a/ui/sceneRenderer.cpp +++ b/ui/sceneRenderer.cpp @@ -1,5 +1,6 @@ #include "sceneRenderer.h" #include "maths.h" +#include #include #include #include @@ -34,9 +35,7 @@ SceneRenderer::SceneRenderer(glm::ivec2 s, GLuint o) : configuregdata(gPosition, GL_RGBA16F, GL_FLOAT, GL_COLOR_ATTACHMENT0); configuregdata(gNormal, GL_RGBA16F, GL_FLOAT, GL_COLOR_ATTACHMENT1); configuregdata(gAlbedoSpec, GL_RGBA, GL_UNSIGNED_BYTE, GL_COLOR_ATTACHMENT2); - static constexpr std::array attachments { - GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2}; - glDrawBuffers(attachments.size(), attachments.data()); + configuregdata(gIllumination, GL_RGBA16F, GL_FLOAT, GL_COLOR_ATTACHMENT3); glBindRenderbuffer(GL_RENDERBUFFER, depth); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, size.x, size.y); @@ -50,20 +49,35 @@ SceneRenderer::SceneRenderer(glm::ivec2 s, GLuint o) : } void -SceneRenderer::render(std::function content) const +SceneRenderer::render(const SceneProvider & scene) const { shader.setView(camera.GetViewProjection()); glViewport(0, 0, size.x, size.y); // Geometry pass + glBindFramebuffer(GL_FRAMEBUFFER, gBuffer); + static constexpr std::array attachments { + GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2}; + glDrawBuffers(attachments.size(), attachments.data()); glEnable(GL_BLEND); glEnable(GL_CULL_FACE); glCullFace(GL_BACK); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_DEPTH_TEST); - glBindFramebuffer(GL_FRAMEBUFFER, gBuffer); + glClearColor(0, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - content(shader); + scene.content(shader); + + // Illumination pass + glDrawBuffer(GL_COLOR_ATTACHMENT3); + glDisable(GL_DEPTH_TEST); + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, gPosition); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, gNormal); + scene.environment(shader, *this); // Lighting pass glBindFramebuffer(GL_FRAMEBUFFER, output); @@ -75,9 +89,48 @@ SceneRenderer::render(std::function content) const glBindTexture(GL_TEXTURE_2D, gNormal); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, gAlbedoSpec); - // TODO Configure lights + glActiveTexture(GL_TEXTURE3); + glBindTexture(GL_TEXTURE_2D, gIllumination); lighting.use(); glBindVertexArray(displayVAO); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glBindVertexArray(0); } + +void +SceneRenderer::setAmbientLight(const glm::vec3 & colour) const +{ + glClearColor(colour.r, colour.g, colour.b, 1.0F); + glClear(GL_COLOR_BUFFER_BIT); +} + +void +SceneRenderer::setDirectionalLight(const glm::vec3 & colour, const glm::vec3 & direction) const +{ + dirLight.use(); + dirLight.setDirectionalLight(colour, direction); + glBindVertexArray(displayVAO); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glBindVertexArray(0); +} + +SceneRenderer::DirectionalLightProgram::DirectionalLightProgram() : + Program {lightingShader_vs, directionalLight_fs}, directionLoc {*this, "lightDirection"}, colourLoc {*this, + "lightColour"} +{ +} + +void +SceneRenderer::DirectionalLightProgram::setDirectionalLight(const glm::vec3 & c, const glm::vec3 & d) const +{ + glUniform3fv(colourLoc, 1, glm::value_ptr(c)); + const auto nd = glm::normalize(d); + glUniform3fv(directionLoc, 1, glm::value_ptr(nd)); +} + +void +SceneRenderer::SceneProvider::environment(const SceneShader &, const SceneRenderer & renderer) const +{ + renderer.setAmbientLight({0.5F, 0.5F, 0.5F}); + renderer.setDirectionalLight({0.6F, 0.6F, 0.6F}, {1, 0, -1}); +} diff --git a/ui/sceneRenderer.h b/ui/sceneRenderer.h index c06fa83..8b81d0c 100644 --- a/ui/sceneRenderer.h +++ b/ui/sceneRenderer.h @@ -9,9 +9,18 @@ class SceneRenderer { public: + class SceneProvider { + public: + virtual ~SceneProvider() = default; + virtual void content(const SceneShader &) const = 0; + virtual void environment(const SceneShader &, const SceneRenderer &) const; + }; + explicit SceneRenderer(glm::ivec2 size, GLuint output); - void render(std::function content) const; + void render(const SceneProvider &) const; + void setAmbientLight(const glm::vec3 & colour) const; + void setDirectionalLight(const glm::vec3 & colour, const glm::vec3 & direction) const; Camera camera; @@ -19,14 +28,26 @@ private: glm::ivec2 size; GLuint output; glFrameBuffer gBuffer; - glTexture gPosition, gNormal, gAlbedoSpec; + glTexture gPosition, gNormal, gAlbedoSpec, gIllumination; glRenderBuffer depth; class DeferredLightProgram : public Program { public: using Program::Program; using Program::use; }; + class DirectionalLightProgram : public Program { + public: + DirectionalLightProgram(); + using Program::use; + + void setDirectionalLight(const glm::vec3 &, const glm::vec3 &) const; + + private: + RequiredUniformLocation directionLoc, colourLoc; + }; + DeferredLightProgram lighting; + DirectionalLightProgram dirLight; glVertexArray displayVAO; glBuffer displayVBO; SceneShader shader; diff --git a/ui/window.cpp b/ui/window.cpp index 51aa827..5930292 100644 --- a/ui/window.cpp +++ b/ui/window.cpp @@ -77,6 +77,7 @@ void Window::render() const { glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_DEPTH_TEST); uiComponents.apply(&UIComponent::render, uiShader, UIComponent::Position {}); } -- cgit v1.2.3