SparrowRenderer/src/posteffectmodule.cpp
2016-06-06 10:01:58 +02:00

246 lines
7.6 KiB
C++

#include "posteffectmodule.h"
#include "framebuffer.h"
#include "texture.h"
#include "shader.h"
#include "textureblur.h"
#include "textureredux.h"
#include "shadersource.h"
#include <glm/ext.hpp>
const GLfloat PostEffectModule::vertices[] = {
-1.0f, -1.0f,
3.0f, -1.0f,
-1.0f, 3.0f
};
PostEffectModule::PostEffectModule(int width, int height) :
frameBuffers(NULL),
outputFBO(FrameBuffer::screen),
blur(NULL),
blurSource(NULL),
redux(NULL),
bloom_threshold(0.7f)
{
for(int i=0; i<NB_SHADERS; ++i)
shaders[i] = NULL;
// set up vao
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, 3 * 2 * sizeof(GLfloat), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*2, NULL);
glEnableVertexAttribArray(0);
resize(width, height);
}
PostEffectModule::~PostEffectModule()
{
glDeleteVertexArrays(1, &vao);
glDeleteBuffers(1, &vbo);
for(int i=0; i<NB_FBO; ++i)
frameBuffers[i].deleteTextures();
delete[](frameBuffers);
}
void PostEffectModule::resize(int w, int h)
{
width = w;
height = h;
Texture* tex;
if(frameBuffers != NULL)
{
for(int i=0; i<NB_FBO; ++i)
frameBuffers[i].deleteTextures();
delete[](frameBuffers);
}
frameBuffers = new FrameBuffer[NB_FBO];
// TODO : don't delete, forward module reference is lost
// creating input FBO
// Color buffer
tex = new Texture(GL_RGBA, GL_RGBA16F, width, height, GL_HALF_FLOAT, GL_TEXTURE_RECTANGLE);
frameBuffers[INPUT_FBO].addTexture(tex, GL_COLOR_ATTACHMENT0);
// Depth buffer
tex = new Texture(GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, width, height, GL_FLOAT, GL_TEXTURE_RECTANGLE);
frameBuffers[INPUT_FBO].addTexture(tex, GL_DEPTH_ATTACHMENT);
// Picking texture
tex = new Texture(GL_RGB, GL_RGB32F, width, height, GL_FLOAT, GL_TEXTURE_RECTANGLE);
frameBuffers[INPUT_FBO].addTexture(tex, GL_COLOR_ATTACHMENT1);
frameBuffers[INPUT_FBO].initColorAttachments();
// creating luminance FBO
// luminance filter
tex = new Texture(GL_RGB, GL_RGB16F, width, height, GL_HALF_FLOAT, GL_TEXTURE_RECTANGLE);
frameBuffers[LUMINANCE_FBO].addTexture(tex, GL_COLOR_ATTACHMENT0);
frameBuffers[LUMINANCE_FBO].initColorAttachments();
// creating bloom FBO
// min/max/mean buffers
tex = new Texture(GL_RGB, GL_RGB32F, width, height, GL_FLOAT, GL_TEXTURE_RECTANGLE);
frameBuffers[BLOOM_FBO].addTexture(tex, GL_COLOR_ATTACHMENT0);
// color buffer
tex = new Texture(frameBuffers[INPUT_FBO].getTexture(0));
frameBuffers[BLOOM_FBO].addTexture(tex, GL_COLOR_ATTACHMENT1);
frameBuffers[BLOOM_FBO].initColorAttachments();
// blur and redux tools
if(blur != NULL)
delete(blur);
blur = new TextureBlur(frameBuffers + LUMINANCE_FBO);
if(blurSource != NULL)
blur->setSource(blurSource);
if(redux != NULL)
delete(redux);
redux = new TextureRedux(frameBuffers + BLOOM_FBO);
if(shaders[REDUX_SHADER] != NULL)
redux->setShader(shaders[REDUX_SHADER]);
}
void PostEffectModule::renderGL(Camera* myCamera, Scene* scene)
{
if(shaders[0] != NULL)
{
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glDisable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
glBindVertexArray(vao);
// thresholding the luminance to isolate high luminance pixels for bloom
luminanceStep();
// blur the high luminance pixels
bloomStep();
// compute average luminance and apply tonemapping
hdrStep();
glEnable(GL_DEPTH_TEST);
}
frameBuffers[INPUT_FBO].bindFBO();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
void PostEffectModule::luminanceStep()
{
glViewport(0, 0, width, height);
frameBuffers[LUMINANCE_FBO].bindFBO();
glClear(GL_COLOR_BUFFER_BIT);
shaders[LUMINANCE_SHADER]->bind();
shaders[LUMINANCE_SHADER]->bindInteger(shaders[LUMINANCE_SHADER]->getLocation("colorSampler"), 0);
frameBuffers[INPUT_FBO].getTexture(0)->bind(0);
shaders[LUMINANCE_SHADER]->bindFloat(shaders[LUMINANCE_SHADER]->getLocation("threshold"), bloom_threshold);
glDrawArrays(GL_TRIANGLES, 0, 3);
}
void PostEffectModule::bloomStep()
{
blur->blur();
glViewport(0, 0, width, height);
frameBuffers[BLOOM_FBO].bindFBO();
glClear(GL_COLOR_BUFFER_BIT);
shaders[BLOOM_SHADER]->bind();
shaders[BLOOM_SHADER]->bindInteger(shaders[BLOOM_SHADER]->getLocation("colorSampler"), 0);
frameBuffers[INPUT_FBO].getTexture(0)->bind(0);
shaders[BLOOM_SHADER]->bindInteger(shaders[BLOOM_SHADER]->getLocation("blurSampler0"), 1);
blur->getTexture(0)->bind(1);
shaders[BLOOM_SHADER]->bindInteger(shaders[BLOOM_SHADER]->getLocation("blurSampler1"), 2);
blur->getTexture(1)->bind(2);
shaders[BLOOM_SHADER]->bindInteger(shaders[BLOOM_SHADER]->getLocation("blurSampler2"), 3);
blur->getTexture(2)->bind(3);
shaders[BLOOM_SHADER]->bindInteger(shaders[BLOOM_SHADER]->getLocation("blurSampler3"), 4);
blur->getTexture(3)->bind(4);
shaders[BLOOM_SHADER]->bindInteger(shaders[BLOOM_SHADER]->getLocation("width"), width);
shaders[BLOOM_SHADER]->bindInteger(shaders[BLOOM_SHADER]->getLocation("height"), height);
glDrawArrays(GL_TRIANGLES, 0, 3);
}
void PostEffectModule::hdrStep()
{
glm::vec3 minMaxMean = redux->redux();
float gamma = 2.2f;
glViewport(0, 0, width, height);
outputFBO->bindFBO();
glClear(GL_COLOR_BUFFER_BIT);
shaders[HDR_SHADER]->bind();
shaders[HDR_SHADER]->bindInteger(shaders[HDR_SHADER]->getLocation("colorSampler"), 0);
frameBuffers[BLOOM_FBO].getTexture(1)->bind(0);
shaders[HDR_SHADER]->bindVec3(shaders[HDR_SHADER]->getLocation("minMaxMean"), minMaxMean);
shaders[HDR_SHADER]->bindFloat(shaders[HDR_SHADER]->getLocation("gamma"), gamma);
glDrawArrays(GL_TRIANGLES, 0, 3);
}
void PostEffectModule::setShaders(const std::string &luminanceFragSource,
const std::string &bloomFragSource,
const std::string &hdrFragSource,
const std::string &blurFragSource,
const std::string &reduxFragSource)
{
const std::string version_string = "#version 330 core\n";
shaders[LUMINANCE_SHADER] = new Shader(version_string+vertSource, version_string+luminanceFragSource);
shaders[BLOOM_SHADER] = new Shader(version_string+vertSource, version_string+bloomFragSource);
shaders[HDR_SHADER] = new Shader(version_string+vertSource, version_string+hdrFragSource);
shaders[REDUX_SHADER] = new Shader(version_string+vertSource, version_string+reduxFragSource);
redux->setShader(shaders[REDUX_SHADER]);
if(blurSource != NULL)
delete(blurSource);
blurSource = new ShaderSource();
blurSource->setSource(vertSource.c_str(), ShaderSource::VERTEX);
blurSource->setSource(blurFragSource.c_str(), ShaderSource::FRAGMENT);
blur->setSource(blurSource);
}
glm::vec3 PostEffectModule::getObjectInfo(int x, int y)
{
frameBuffers[INPUT_FBO].getTexture(1)->bind(0);
glm::vec3 *val = new glm::vec3[width*height];
glGetTexImage(GL_TEXTURE_RECTANGLE, 0, GL_RGB, GL_FLOAT, val);
glm::vec3 ret = val[x + (height-y)*width];
ret.z -= 1; // clearColor compensation
delete[] val;
return ret;
}
const std::string PostEffectModule::vertSource =
"layout(location = 0)in vec2 inPosition;\n\
void main(void) {\n\
gl_Position = vec4(inPosition, 0.0, 1.0);\n\
}\n";