246 lines
7.6 KiB
C++
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";
|
|
|
|
|