Add a framebuffer which the scene is rendered to. Render this framebuffer to screen afterwards

This commit is contained in:
Peder Bergebakken Sundt 2019-03-31 23:46:05 +02:00
parent fb9ff7c829
commit f275aef0b0
6 changed files with 160 additions and 39 deletions

19
res/shaders/post.frag Normal file
View File

@ -0,0 +1,19 @@
#version 430 core
layout(location = 0) out vec4 color_out;
layout(binding = 0) uniform sampler2D framebuffer;
layout(binding = 1) uniform sampler2D depthbuffer;
uniform uint windowWidth;
uniform uint windowHeight;
uniform float time;
void main() {
float dx = 1.0/windowWidth;
float dy = 1.0/windowHeight;
vec2 UV = gl_FragCoord.xy / vec2(windowWidth, windowHeight);
color_out = texture(framebuffer, UV);
}

9
res/shaders/post.vert Normal file
View File

@ -0,0 +1,9 @@
#version 430 core
in layout(location = 0) vec3 vertex;
out layout(location = 0) vec2 UV;
void main() {
gl_Position = vec4(vertex, 1.0);
UV = vertex.xy*0.5 + 0.5;
}

View File

@ -50,7 +50,7 @@ struct Light { // point lights, coordinates in MV space
uniform Light light[N_LIGHTS]; uniform Light light[N_LIGHTS];
out vec4 color_out; layout(location = 0) out vec4 color_out;
vec3 reflection(vec3 basecolor, vec3 nnormal) { vec3 reflection(vec3 basecolor, vec3 nnormal) {

View File

@ -45,8 +45,6 @@ void runProgram(GLFWwindow* window, CommandLineOptions options)
// Rendering Loop // Rendering Loop
while (!glfwWindowShouldClose(window)) while (!glfwWindowShouldClose(window))
{ {
// Clear colour and depth buffers
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glfwGetWindowSize(window, &w, &h); glfwGetWindowSize(window, &w, &h);
double td = c.getTimeDeltaSeconds(); double td = c.getTimeDeltaSeconds();

View File

@ -10,7 +10,7 @@
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <algorithm> #include <algorithm>
#include <utilities/glfont.h> #include <utilities/glutils.h>
#include <utilities/shader.hpp> #include <utilities/shader.hpp>
#include <utilities/timeutils.hpp> #include <utilities/timeutils.hpp>
@ -26,6 +26,21 @@ typedef unsigned int uint;
sf::Sound* sound; sf::Sound* sound;
sf::SoundBuffer* buffer; sf::SoundBuffer* buffer;
// for keeping track of the currently loaded shader in renderNode()
Gloom::Shader* current_shader = nullptr;
Gloom::Shader* prev_shader = nullptr; // The last shader to glDrawElements
// the framebuffer we render the scene to before post-processing
GLuint framebufferID = 0;
GLuint framebufferTextureID = 0;
GLuint framebufferDepthBufferID = 0;
GLuint framebufferDepthTextureID = 0;
// the surface we use for post-processing
GLuint postVAO;
Gloom::Shader* post_shader = nullptr;
void mouse_callback(GLFWwindow* window, double x, double y) { void mouse_callback(GLFWwindow* window, double x, double y) {
static bool mouse_mode = false; static bool mouse_mode = false;
int winw, winh; int winw, winh;
@ -47,13 +62,64 @@ void mouse_callback(GLFWwindow* window, double x, double y) {
} }
} }
void initRenderer(GLFWwindow* window, CommandLineOptions options) { void initRenderer(GLFWwindow* window, int windowWidth, int windowHeight) {
static bool first/*time*/ = true;
if (first&&false) {
buffer = new sf::SoundBuffer(); buffer = new sf::SoundBuffer();
if (!buffer->loadFromFile("../res/Hall of the Mountain King.ogg")) { if (!buffer->loadFromFile("../res/Hall of the Mountain King.ogg")) {
return; return;
} }
}
glfwSetCursorPosCallback(window, mouse_callback); if(first) glfwSetCursorPosCallback(window, mouse_callback);
// setup the framebuffer we render the scene to, and the tris we render
// as the post-processing stage
if (first) glGenFramebuffers(1, &framebufferID);
glBindFramebuffer(GL_FRAMEBUFFER, framebufferID);
if (first) glGenTextures(1, &framebufferTextureID);
glBindTexture(GL_TEXTURE_2D, framebufferTextureID);
// Give an empty image to OpenGL ( the last "0" )
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, windowWidth, windowHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
if (first) glGenTextures(1, &framebufferDepthTextureID);
glBindTexture(GL_TEXTURE_2D, framebufferDepthTextureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, windowWidth, windowHeight, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
if (first) glGenRenderbuffers(1, &framebufferDepthBufferID);
glBindRenderbuffer(GL_RENDERBUFFER, framebufferDepthBufferID);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, windowWidth, windowHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, framebufferDepthBufferID);
// Set "framebufferTextureID" as our colour attachement #0
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, framebufferTextureID, 0);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, framebufferDepthTextureID, 0);
// Set the list of draw buffers.
GLenum drawBuffers[] = {GL_COLOR_ATTACHMENT0};
glDrawBuffers(1, drawBuffers);
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
std::cerr << (glCheckFramebufferStatus(GL_FRAMEBUFFER)) << endl;
throw 1;
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
if (first) {
postVAO = generatePostQuadBuffer();
post_shader = new Gloom::Shader();
post_shader->makeBasicShader("../res/shaders/post.vert", "../res/shaders/post.frag");
}
first = false;
} }
// traverses and updates matricies // traverses and updates matricies
@ -146,38 +212,38 @@ void renderNode(SceneNode* node, Gloom::Shader* parent_shader, vector<NodeDistSh
} }
}; };
static Light lights[N_LIGHTS]; static Light lights[N_LIGHTS];
static Gloom::Shader* s = nullptr; // The currently active shader
static Gloom::Shader* prev_s = nullptr; // The last shader to glDrawElements
if (node->isHidden) return; if (node->isHidden) return;
// activate the correct shader // activate the correct shader
Gloom::Shader* node_shader = (node->shader != nullptr) Gloom::Shader* s = (node->shader != nullptr)
? node->shader ? node->shader
: parent_shader; : parent_shader;
if (s != node_shader) { if (current_shader != s) {
s = node_shader; current_shader = s;
s->activate(); current_shader->activate();
uint i = 0; for (Light l : lights) l.push_to_shader(s, i++); uint i = 0; for (Light l : lights) l.push_to_shader(s, i++);
} }
bool shader_changed = s == prev_s; bool shader_changed = current_shader != prev_shader;
#define cache(x) static decltype(node->x) cached_ ## x; if (shader_changed && cached_ ## x != node->x) { cached_ ## x = node->x; #define init_cache(x) static decltype(node->x) cached_##x;
#define if_cache(x) if (shader_changed || cached_##x != node->x) { cached_##x = node->x;
#define cache(x) init_cache(x) if_cache(x)
#define um4fv(x) cache(x) glUniformMatrix4fv(s->location(#x), 1, GL_FALSE, glm::value_ptr(node->x)); } #define um4fv(x) cache(x) glUniformMatrix4fv(s->location(#x), 1, GL_FALSE, glm::value_ptr(node->x)); }
#define u2fv(x) cache(x) glUniform2fv( s->location(#x), 1, glm::value_ptr(node->x)); } #define u2fv(x) cache(x) glUniform2fv( s->location(#x), 1, glm::value_ptr(node->x)); }
#define u3fv(x) cache(x) glUniform3fv( s->location(#x), 1, glm::value_ptr(node->x)); } #define u3fv(x) cache(x) glUniform3fv( s->location(#x), 1, glm::value_ptr(node->x)); }
#define u1f(x) cache(x) glUniform1f( s->location(#x), node->x); } #define u1f(x) cache(x) glUniform1f( s->location(#x), node->x); }
#define u1ui(x) cache(x) glUniform1ui( s->location(#x), node->x); } #define u1ui(x) cache(x) glUniform1ui( s->location(#x), node->x); }
#define ubtu(n,i,x) if(node->i) { cache(x) glBindTextureUnit(n, node->x); } } #define ubtu(n,i,x) init_cache(x) if(node->i) { if_cache(x) glBindTextureUnit(n, node->x); } } else cached_##x = -1;
switch(node->nodeType) { switch(node->nodeType) {
case GEOMETRY: case GEOMETRY:
if (transparent_nodes!=nullptr && node->has_transparancy()) { if (transparent_nodes!=nullptr && node->has_transparancy()) {
// defer to sorted pass later on // defer to sorted pass later on
//transparent_nodes->emplace_back(node, node_shader, glm::length(vec3(node->MVP[3]))); //transparent_nodes->emplace_back(node, s, glm::length(vec3(node->MVP[3])));
//transparent_nodes->push_back({node, node_shader, glm::length(vec3(node->MVP[3]))}); //transparent_nodes->push_back({node, s, glm::length(vec3(node->MVP[3]))});
transparent_nodes->emplace_back(node, node_shader, glm::length(vec3(node->MVP*vec4(0,0,0,1)))); transparent_nodes->emplace_back(node, s, glm::length(vec3(node->MVP*vec4(0,0,0,1))));
//transparent_nodes->push_back({node, node_shader, glm::length(vec3(node->MVP*vec4(0,0,0,1)))}); //transparent_nodes->push_back({node, s, glm::length(vec3(node->MVP*vec4(0,0,0,1)))});
} }
else if(node->vertexArrayObjectID != -1) { else if(node->vertexArrayObjectID != -1) {
if (node->opacity <= 0.05) break; if (node->opacity <= 0.05) break;
@ -208,7 +274,7 @@ void renderNode(SceneNode* node, Gloom::Shader* parent_shader, vector<NodeDistSh
ubtu(3, isReflectionMapped , reflectionTextureID); ubtu(3, isReflectionMapped , reflectionTextureID);
glBindVertexArray(node->vertexArrayObjectID); glBindVertexArray(node->vertexArrayObjectID);
glDrawElements(GL_TRIANGLES, node->VAOIndexCount, GL_UNSIGNED_INT, nullptr); glDrawElements(GL_TRIANGLES, node->VAOIndexCount, GL_UNSIGNED_INT, nullptr);
prev_s = s; prev_shader = current_shader;
} }
break; break;
case SPOT_LIGHT: case SPOT_LIGHT:
@ -239,18 +305,31 @@ void renderNode(SceneNode* node, Gloom::Shader* parent_shader, vector<NodeDistSh
if (do_recursive) if (do_recursive)
for(SceneNode* child : node->children) for(SceneNode* child : node->children)
renderNode(child, node_shader, transparent_nodes, true); renderNode(child, s, transparent_nodes, true);
} }
// draw // draw
void renderFrame(GLFWwindow* window, int windowWidth, int windowHeight) { void renderFrame(GLFWwindow* window, int windowWidth, int windowHeight) {
static int old_windowWidth = windowWidth;
static int old_windowHeight = windowHeight;
if (old_windowWidth != windowWidth || old_windowHeight != windowHeight) {
old_windowWidth = windowWidth;
old_windowHeight = windowHeight;
cout << "reinit renderer" << endl;
initRenderer(window, old_windowWidth, windowHeight);
}
// render to internal buffer
glBindFramebuffer(GL_FRAMEBUFFER, framebufferID);
glViewport(0, 0, windowWidth, windowHeight); glViewport(0, 0, windowWidth, windowHeight);
// Clear colour and depth buffers
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
static vector<NodeDistShader> transparent_nodes; static vector<NodeDistShader> transparent_nodes;
transparent_nodes.clear(); transparent_nodes.clear();
renderNode(rootNode, nullptr, &transparent_nodes); // rootNode defined in scene.hpp
// externs from scene.hpp, they must have shaders set
renderNode(rootNode, nullptr, &transparent_nodes);
// sort and render transparent node, sorted by distance from camera // sort and render transparent node, sorted by distance from camera
std::sort( std::sort(
@ -260,13 +339,29 @@ void renderFrame(GLFWwindow* window, int windowWidth, int windowHeight) {
return a.dist > b.dist; return a.dist > b.dist;
}); });
glDepthMask(GL_FALSE); // read only glDepthMask(GL_FALSE); // read only
//glDisable(GL_DEPTH_TEST);
for (NodeDistShader a : transparent_nodes) for (NodeDistShader a : transparent_nodes)
renderNode(a.node, a.s, nullptr, false); renderNode(a.node, a.s, nullptr, false);
//std::cout << transparent_nodes.size() << std::endl;
glDepthMask(GL_TRUE); // read write glDepthMask(GL_TRUE); // read write
//glEnable(GL_DEPTH_TEST);
renderNode(hudNode, nullptr); // rootNode defined in scene.hpp
// render framebuffer to window
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, windowWidth, windowHeight);
post_shader->activate();
current_shader = post_shader;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
static Clock c;
static float t = 0.0;
t += c.getTimeDeltaSeconds();
glUniform1f(post_shader->location("time"), t);
glUniform1ui(post_shader->location("windowWidth"), windowWidth);
glUniform1ui(post_shader->location("windowHeight"), windowHeight);
glBindTextureUnit(0, framebufferTextureID);
glBindTextureUnit(1, framebufferDepthTextureID);
glBindVertexArray(postVAO);
glDrawElements(GL_TRIANGLES, 6 /*vertices*/, GL_UNSIGNED_INT, nullptr);
prev_shader = post_shader;
renderNode(hudNode, nullptr);
} }

View File

@ -7,6 +7,6 @@
// further divied into: // further divied into:
#include "scene.hpp" #include "scene.hpp"
void initRenderer(GLFWwindow* window, CommandLineOptions options); void initRenderer(GLFWwindow* window,int windowWidth, int windowHeight);
void updateFrame(GLFWwindow* window, int windowWidth, int windowHeight); void updateFrame(GLFWwindow* window, int windowWidth, int windowHeight);
void renderFrame(GLFWwindow* window, int windowWidth, int windowHeight); void renderFrame(GLFWwindow* window, int windowWidth, int windowHeight);