summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2022-11-01 19:12:04 +0000
committerDan Goodliffe <dan@randomdan.homeip.net>2022-11-01 19:12:04 +0000
commit3b791f79bf53e481d053ea4516eedce8be3423bf (patch)
tree39817b0996eaa867c7f7abbc5dbd5cb706ecbaa5
parentSomewhat dirty but functional helper to save a texture (diff)
downloadilt-3b791f79bf53e481d053ea4516eedce8be3423bf.tar.bz2
ilt-3b791f79bf53e481d053ea4516eedce8be3423bf.tar.xz
ilt-3b791f79bf53e481d053ea4516eedce8be3423bf.zip
Switch to a deferred lighting based render pipeline
Tidy-up required.
-rw-r--r--gfx/gl/shaders/basicShader.fs23
-rw-r--r--gfx/gl/shaders/basicShader.vs18
-rw-r--r--gfx/gl/shaders/landmassShader.fs46
-rw-r--r--gfx/gl/shaders/landmassShader.vs16
-rw-r--r--gfx/gl/shaders/lightingShader.fs62
-rw-r--r--gfx/gl/shaders/lightingShader.vs13
-rw-r--r--gfx/gl/shaders/waterShader.fs21
-rw-r--r--gfx/gl/shaders/waterShader.vs23
-rw-r--r--ui/gameMainWindow.cpp9
-rw-r--r--ui/gameMainWindow.h3
-rw-r--r--ui/sceneRenderer.cpp102
-rw-r--r--ui/sceneRenderer.h18
-rw-r--r--ui/window.cpp2
13 files changed, 292 insertions, 64 deletions
diff --git a/gfx/gl/shaders/basicShader.fs b/gfx/gl/shaders/basicShader.fs
index 0bd42b4..9c4945b 100644
--- a/gfx/gl/shaders/basicShader.fs
+++ b/gfx/gl/shaders/basicShader.fs
@@ -1,15 +1,20 @@
#version 330 core
-in vec2 texCoord0;
-in vec3 normal0;
+in vec3 FragPos;
+in vec2 TexCoords;
+in vec3 Normal;
-uniform sampler2D sampler;
-uniform vec3 lightDirection;
-uniform vec3 lightColor;
-uniform vec3 ambientColor;
+out vec4 gPosition;
+out vec4 gNormal;
+out vec4 gAlbedoSpec;
-void main()
+uniform sampler2D texture0;
+
+void
+main()
{
- gl_FragColor = texture(sampler, texCoord0);
- gl_FragColor.rgb *= clamp(ambientColor + (dot(-lightDirection, normal0) * lightColor), 0.0, 1.0);
+ float clear = round(texture(texture0, TexCoords).a);
+ gPosition = vec4(FragPos, clear);
+ gNormal = vec4(Normal, clear);
+ gAlbedoSpec = texture(texture0, TexCoords);
}
diff --git a/gfx/gl/shaders/basicShader.vs b/gfx/gl/shaders/basicShader.vs
index 8f2ab3e..bc7ea5d 100644
--- a/gfx/gl/shaders/basicShader.vs
+++ b/gfx/gl/shaders/basicShader.vs
@@ -4,15 +4,21 @@ in vec3 position;
in vec2 texCoord;
in vec3 normal;
-out vec2 texCoord0;
-out vec3 normal0;
+out vec3 FragPos;
+out vec2 TexCoords;
+out vec3 Normal;
uniform mat4 viewProjection;
uniform mat4 model;
-void main()
+void
+main()
{
- gl_Position = viewProjection * model * vec4(position, 1.0);
- texCoord0 = texCoord;
- normal0 = (model * vec4(normal, 0.0)).xyz;
+ vec4 worldPos = model * vec4(position, 1.0);
+
+ FragPos = worldPos.xyz;
+ TexCoords = texCoord;
+ Normal = (model * vec4(normal, 0.0)).xyz;
+
+ gl_Position = viewProjection * worldPos;
}
diff --git a/gfx/gl/shaders/landmassShader.fs b/gfx/gl/shaders/landmassShader.fs
index aa368dc..7c08e8e 100644
--- a/gfx/gl/shaders/landmassShader.fs
+++ b/gfx/gl/shaders/landmassShader.fs
@@ -1,13 +1,14 @@
#version 330 core
-in vec2 texCoord0;
-in vec3 normal0;
-in float height;
+in vec3 FragPos;
+in vec2 TexCoords;
+in vec3 Normal;
-uniform sampler2D sampler;
-uniform vec3 lightDirection;
-uniform vec3 lightColor;
-uniform vec3 ambientColor;
+layout(location = 0) out vec4 gPosition;
+layout(location = 1) out vec4 gNormal;
+layout(location = 2) out vec4 gAlbedoSpec;
+
+uniform sampler2D texture0;
const vec3 grass = vec3(.1, .4, .05);
const vec3 slope = vec3(.6, .6, .4);
@@ -32,36 +33,39 @@ mixBetween(vec3 colA, vec3 colB, float blend, float low, float high)
void
main()
{
- vec4 tex = texture(sampler, texCoord0);
- gl_FragColor = tex;
- gl_FragColor.rgb *= clamp(ambientColor + (dot(-lightDirection, normal0) * lightColor), 0.0, 1.0);
+ vec3 color = texture(texture0, TexCoords).rgb;
+ float height = FragPos.z;
if (height < beachline) { // Sandy beach
- gl_FragColor.rgb *= sand;
+ color *= sand;
}
- else if (normal0.z < slope_max) { // Dark rocky face
- gl_FragColor.rgb *= rock;
+ else if (Normal.z < slope_max) { // Dark rocky face
+ color *= rock;
}
else { // Colour by lesser slope
- if (normal0.z < slope_mid) {
- gl_FragColor.rgb *= mixBetween(rock, slope, normal0.z, slope_max, slope_mid);
+ if (Normal.z < slope_mid) {
+ color *= mixBetween(rock, slope, Normal.z, slope_max, slope_mid);
}
- else if (normal0.z < slope_min) {
- gl_FragColor.rgb *= mixBetween(slope, grass, normal0.z, slope_mid, slope_min);
+ else if (Normal.z < slope_min) {
+ color *= mixBetween(slope, grass, Normal.z, slope_mid, slope_min);
}
else {
- gl_FragColor.rgb *= grass;
+ color *= grass;
}
// Add a snow covering
if (height > snowline_low) {
- vec3 tsnow = tex.rgb * snow;
+ vec3 tsnow = color * snow;
if (height > snowline_high) {
- gl_FragColor.rgb = tsnow;
+ color = tsnow;
}
else {
- gl_FragColor.rgb = mixBetween(gl_FragColor.rgb, tsnow, height, snowline_low, snowline_high);
+ color = mixBetween(color, tsnow, height, snowline_low, snowline_high);
}
}
}
+
+ gPosition = vec4(FragPos, 1);
+ gNormal = vec4(Normal, 1);
+ gAlbedoSpec = vec4(color, 1);
}
diff --git a/gfx/gl/shaders/landmassShader.vs b/gfx/gl/shaders/landmassShader.vs
index bc9a947..6bf39b0 100644
--- a/gfx/gl/shaders/landmassShader.vs
+++ b/gfx/gl/shaders/landmassShader.vs
@@ -4,16 +4,18 @@ in vec3 position;
in vec2 texCoord;
in vec3 normal;
-out vec2 texCoord0;
-out vec3 normal0;
-out float height;
+out vec3 FragPos;
+out vec2 TexCoords;
+out vec3 Normal;
uniform mat4 viewProjection;
-void main()
+void
+main()
{
+ FragPos = position;
+ TexCoords = texCoord;
+ Normal = normal;
+
gl_Position = viewProjection * vec4(position, 1.0);
- texCoord0 = texCoord;
- normal0 = normal;
- height = position.z;
}
diff --git a/gfx/gl/shaders/lightingShader.fs b/gfx/gl/shaders/lightingShader.fs
new file mode 100644
index 0000000..b0ca20a
--- /dev/null
+++ b/gfx/gl/shaders/lightingShader.fs
@@ -0,0 +1,62 @@
+#version 330 core
+#extension GL_ARB_shading_language_420pack : enable
+
+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);
+
+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);
+
+ FragColor = vec3(Diffuse * lighting);
+}
diff --git a/gfx/gl/shaders/lightingShader.vs b/gfx/gl/shaders/lightingShader.vs
new file mode 100644
index 0000000..933a46a
--- /dev/null
+++ b/gfx/gl/shaders/lightingShader.vs
@@ -0,0 +1,13 @@
+#version 330 core
+
+in vec3 aPos;
+in vec2 aTexCoords;
+
+out vec2 TexCoords;
+
+void
+main()
+{
+ TexCoords = aTexCoords;
+ gl_Position = vec4(aPos, 1.0);
+}
diff --git a/gfx/gl/shaders/waterShader.fs b/gfx/gl/shaders/waterShader.fs
index abfa532..d242566 100644
--- a/gfx/gl/shaders/waterShader.fs
+++ b/gfx/gl/shaders/waterShader.fs
@@ -1,13 +1,22 @@
#version 330 core
+#extension GL_ARB_shading_language_420pack : enable
-in vec2 texCoord0;
-in float depth;
+in vec3 FragPos;
+in vec2 TexCoords;
+in vec3 Normal;
-uniform sampler2D sampler;
+out vec4 gPosition;
+out vec4 gNormal;
+out vec4 gAlbedoSpec;
+
+uniform sampler2D texture0;
uniform vec3 waves;
-void main()
+void
+main()
{
- gl_FragColor = texture(sampler, texCoord0);
- gl_FragColor.a *= clamp(-depth * .7, .1, 1.0);
+ gPosition = vec4(FragPos, 1);
+ gNormal = vec4(Normal, 1);
+ gAlbedoSpec = texture(texture0, TexCoords);
+ gAlbedoSpec.a *= clamp(-FragPos.z * .7, .1, 1.0);
}
diff --git a/gfx/gl/shaders/waterShader.vs b/gfx/gl/shaders/waterShader.vs
index bc4b7fc..fe9206f 100644
--- a/gfx/gl/shaders/waterShader.vs
+++ b/gfx/gl/shaders/waterShader.vs
@@ -4,19 +4,22 @@ in vec3 position;
in vec2 texCoord;
in vec3 normal;
-out vec2 texCoord0;
-out float depth;
+out vec3 FragPos;
+out vec2 TexCoords;
+out vec3 Normal;
uniform mat4 viewProjection;
uniform vec3 waves;
-void main()
+void
+main()
{
- vec3 wpos = vec3(
- position.x + cos(waves.x),
- position.y + cos(waves.x * waves.y / 2),
- cos(waves.x + position.x + (position.y / 8)) * .3);
- gl_Position = viewProjection * vec4(wpos, 1.0);
- texCoord0 = texCoord;
- depth = position.z;
+ vec4 wpos = vec4(position.x + cos(waves.x), position.y + cos(waves.x * waves.y / 2),
+ cos(waves.x + position.x + (position.y / 8)) * .3, 1.0);
+
+ FragPos = vec3(wpos.xy, position.z);
+ TexCoords = texCoord;
+ Normal = normal;
+
+ gl_Position = viewProjection * wpos;
}
diff --git a/ui/gameMainWindow.cpp b/ui/gameMainWindow.cpp
index 84d0ca6..c08588d 100644
--- a/ui/gameMainWindow.cpp
+++ b/ui/gameMainWindow.cpp
@@ -30,7 +30,8 @@ public:
};
GameMainWindow::GameMainWindow(size_t w, size_t h) :
- Window {w, h, "I Like Trains"}, camera {{-1250.0F, -1250.0F, 35.0F}, quarter_pi, rdiv(w, h), 0.1F, 10000.0F}
+ Window {w, h, "I Like Trains"}, SceneRenderer {size}, camera {{-1250.0F, -1250.0F, 35.0F}, quarter_pi, rdiv(w, h),
+ 0.1F, 10000.0F}
{
uiComponents.create<ManualCameraController>(glm::vec2 {-1150, -1150});
auto gms = uiComponents.create<GameMainSelector>(&camera, glm::vec2 {w, h});
@@ -51,8 +52,10 @@ GameMainWindow::tick(TickDuration)
void
GameMainWindow::render() const
{
- glEnable(GL_DEPTH_TEST);
- gameState->world.apply<Renderable>(&Renderable::render, shader);
+ SceneRenderer::render([this] {
+ gameState->world.apply<Renderable>(&Renderable::render, shader);
+ uiComponents.apply<WorldOverlay>(&WorldOverlay::render, shader);
+ });
Window::render();
}
diff --git a/ui/gameMainWindow.h b/ui/gameMainWindow.h
index 9cc72ab..2c2c501 100644
--- a/ui/gameMainWindow.h
+++ b/ui/gameMainWindow.h
@@ -3,10 +3,11 @@
#include "chronology.hpp"
#include "gfx/gl/camera.h"
#include "gfx/gl/shader.h"
+#include "sceneRenderer.h"
#include "window.h"
#include <cstddef>
-class GameMainWindow : public Window {
+class GameMainWindow : public Window, SceneRenderer {
public:
GameMainWindow(size_t w, size_t h);
diff --git a/ui/sceneRenderer.cpp b/ui/sceneRenderer.cpp
new file mode 100644
index 0000000..5cd5097
--- /dev/null
+++ b/ui/sceneRenderer.cpp
@@ -0,0 +1,102 @@
+#include "sceneRenderer.h"
+#include <gfx/gl/shaders/fs-lightingShader.h>
+#include <gfx/gl/shaders/vs-lightingShader.h>
+
+SceneRenderer::SceneRenderer(glm::ivec2 size) : lighting {lightingShader_vs.compile(), lightingShader_fs.compile()}
+{
+ glBindFramebuffer(GL_FRAMEBUFFER, gBuffer);
+ const auto configuregdata
+ = [size](const GLuint data, const GLint format, const GLenum type, const GLenum attachment) {
+ glBindTexture(GL_TEXTURE_2D, data);
+ glTexImage2D(GL_TEXTURE_2D, 0, format, size.x, size.y, 0, GL_RGBA, type, NULL);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, data, 0);
+ };
+ 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<unsigned int, 3> attachments {
+ GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2};
+ glDrawBuffers(attachments.size(), attachments.data());
+
+ glBindRenderbuffer(GL_RENDERBUFFER, depth);
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, size.x, size.y);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth);
+
+ // finally check if framebuffer is complete
+ if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
+ throw std::runtime_error("Framebuffer not complete!");
+ }
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+}
+
+unsigned int quadVAO = 0;
+unsigned int quadVBO;
+void
+renderQuad()
+{
+ if (quadVAO == 0) {
+ float quadVertices[] = {
+ // positions // texture Coords
+ -1.0f,
+ 1.0f,
+ 0.0f,
+ 0.0f,
+ 1.0f,
+ -1.0f,
+ -1.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 1.0f,
+ 1.0f,
+ 0.0f,
+ 1.0f,
+ 1.0f,
+ 1.0f,
+ -1.0f,
+ 0.0f,
+ 1.0f,
+ 0.0f,
+ };
+ // setup plane VAO
+ glGenVertexArrays(1, &quadVAO);
+ glGenBuffers(1, &quadVBO);
+ glBindVertexArray(quadVAO);
+ glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW);
+ glEnableVertexAttribArray(0);
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), nullptr);
+ glEnableVertexAttribArray(1);
+ glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), reinterpret_cast<void *>(3 * sizeof(float)));
+ }
+ glBindVertexArray(quadVAO);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ glBindVertexArray(0);
+}
+
+void
+SceneRenderer::render(std::function<void()> content) const
+{
+ glEnable(GL_BLEND);
+ glEnable(GL_DEPTH_TEST);
+ // Geometry pass
+ glBindFramebuffer(GL_FRAMEBUFFER, gBuffer);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ content();
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ // Lighting pass
+ glDisable(GL_BLEND);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ glUseProgram(lighting.m_program);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, gPosition);
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, gNormal);
+ glActiveTexture(GL_TEXTURE2);
+ glBindTexture(GL_TEXTURE_2D, gAlbedoSpec);
+ // TODO Configure lights
+ renderQuad();
+}
diff --git a/ui/sceneRenderer.h b/ui/sceneRenderer.h
new file mode 100644
index 0000000..2e1c372
--- /dev/null
+++ b/ui/sceneRenderer.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "gfx/gl/shader.h"
+#include "lib/glArrays.h"
+#include <functional>
+
+class SceneRenderer {
+public:
+ SceneRenderer(glm::ivec2 size);
+
+ void render(std::function<void()> content) const;
+
+private:
+ glFrameBuffer gBuffer;
+ glTexture gPosition, gNormal, gAlbedoSpec;
+ glRenderBuffer depth;
+ ProgramHandleBase lighting;
+};
diff --git a/ui/window.cpp b/ui/window.cpp
index 419abc3..82f4d40 100644
--- a/ui/window.cpp
+++ b/ui/window.cpp
@@ -94,7 +94,7 @@ Window::refresh() const
void
Window::render() const
{
- uiComponents.apply<WorldOverlay>(&WorldOverlay::render, getShader());
+ glEnable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
uiComponents.apply(&UIComponent::render, uiShader, UIComponent::Position {});
}