From: Mikko Rasa Date: Sun, 25 Jan 2009 10:39:28 +0000 (+0000) Subject: Add post-processing effect framework X-Git-Tag: 1.1~10 X-Git-Url: http://git.tdb.fi/?a=commitdiff_plain;h=119d9819ac9e9a8d274d2410beffe54e470485a3;p=libs%2Fgl.git Add post-processing effect framework Add Bloom effect Allow querying currently bound Framebuffer Add floating-point PixelFormats --- diff --git a/source/bloom.cpp b/source/bloom.cpp new file mode 100644 index 00000000..8a3bf3b2 --- /dev/null +++ b/source/bloom.cpp @@ -0,0 +1,157 @@ +/* $Id$ + +This file is part of libmspgl +Copyright © 2009 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#include +#include +#include "bloom.h" +#include "meshbuilder.h" +#include "texunit.h" + +using namespace std; + +namespace { + +static const char blur_vs[]= + "varying vec2 texcoord;\n" + "void main()\n" + "{\n" + " gl_Position=vec4(gl_Vertex.xy*2.0-1.0, 0.0, 1.0);\n" + " texcoord=gl_Vertex.xy;\n" + "}"; + +static const char blur_fs[]= + "uniform sampler2D source;\n" + "uniform vec2 delta;\n" + "uniform float factors[19];\n" + "uniform int size;\n" + "varying vec2 texcoord;\n" + "void main()\n" + "{\n" + " gl_FragColor=vec4(0.0, 0.0, 0.0, 0.0);\n" + " for(int i=-size; i<=size; ++i)\n" + " gl_FragColor+=texture2D(source, texcoord+delta*i)*factors[i+size];\n" + "}"; + +static const char combine_vs[]= + "varying vec2 texcoord;\n" + "void main()\n" + "{\n" + " gl_Position=vec4(gl_Vertex.xy*2.0-1.0, 0.0, 1.0);\n" + " texcoord=gl_Vertex.xy;\n" + "}"; + +static const char combine_fs[]= + "uniform sampler2D source;\n" + "uniform sampler2D blurred;\n" + "uniform float strength;\n" + "varying vec2 texcoord;\n" + "void main()\n" + "{\n" + " gl_FragColor=mix(texture2D(source, texcoord), texture2D(blurred, texcoord), strength);" + "}"; + +} + +namespace Msp { +namespace GL { + +Bloom::Bloom(unsigned w, unsigned h): + blur_shader(blur_vs, blur_fs), + combine_shader(combine_vs, combine_fs), + quad(VERTEX2) +{ + int loc=blur_shader.get_uniform_location("delta"); + blur_shdata[0].uniform(loc, 1.0f/w, 0.0f); + blur_shdata[1].uniform(loc, 0.0f, 1.0f/h); + + loc=blur_shader.get_uniform_location("source"); + for(unsigned i=0; i<2; ++i) + { + blur_shdata[i].uniform(loc, 0); + tex[i].storage(RGB16F, w, h, 0); + tex[i].image(0, RGB, UNSIGNED_BYTE, 0); + tex[i].set_min_filter(NEAREST); + } + + combine_shdata.uniform(combine_shader.get_uniform_location("source"), 1); + combine_shdata.uniform(combine_shader.get_uniform_location("blurred"), 0); + + set_radius(2.0f); + set_strength(0.2f); + + MeshBuilder mbld(quad); + mbld.begin(QUADS); + mbld.vertex(0, 0); + mbld.vertex(1, 0); + mbld.vertex(1, 1); + mbld.vertex(0, 1); + mbld.end(); +} + +void Bloom::set_radius(float r) +{ + if(r<=0.0f) + throw InvalidParameterValue("Radius must be positive"); + + int size=min(static_cast(r*3.0f), 9); + int loc=blur_shader.get_uniform_location("size"); + blur_shdata[0].uniform(loc, size); + blur_shdata[1].uniform(loc, size); + + vector factors(size*2+1); + float sum=0.0f; + r=2*r*r; + for(int i=-size; i<=size; ++i) + sum+=(factors[size+i]=exp(-i*i/r)); + + for(int i=0; i<=size*2; ++i) + { + loc=blur_shader.get_uniform_location(format("factors[%d]", i)); + float f=factors[i]/sum; + blur_shdata[0].uniform(loc, f); + blur_shdata[1].uniform(loc, f); + } +} + +void Bloom::set_strength(float s) +{ + if(s<0.0f || s>1.0f) + throw InvalidParameterValue("Strength must be in the range [0.0, 1.0]"); + combine_shdata.uniform(combine_shader.get_uniform_location("strength"), s); +} + +void Bloom::render(const Texture2D &src) +{ + const Framebuffer *dest=Framebuffer::current(); + blur_shader.bind(); + fbo.bind(); + src.bind_to(0); + for(unsigned i=0; i<2; ++i) + { + fbo.attach(COLOR_ATTACHMENT0, tex[i], 0); + blur_shdata[i].apply(); + quad.draw(); + tex[i].bind_to(0); + } + + if(dest) + dest->bind(); + else + Framebuffer::unbind(); + + combine_shader.bind(); + combine_shdata.apply(); + src.bind_to(1); + quad.draw(); + Program::unbind(); + Texture::unbind(); + TexUnit::activate(0); + Texture::unbind(); +} + +} // namespace GL +} // namespace Msp diff --git a/source/bloom.h b/source/bloom.h new file mode 100644 index 00000000..c02604af --- /dev/null +++ b/source/bloom.h @@ -0,0 +1,57 @@ +/* $Id$ + +This file is part of libmspgl +Copyright © 2009 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#ifndef MSP_GL_BLOOM_H_ +#define MSP_GL_BLOOM_H_ + +#include "framebuffer.h" +#include "mesh.h" +#include "postprocessor.h" +#include "texture2d.h" +#include "program.h" +#include "programdata.h" + +namespace Msp { +namespace GL { + +/** +The Bloom post-processing effect causes very bright areas of the image to bleed +into surrounding pixels. Commonly used together with HDR rendering. + +The technique used is to gaussian blur the image and then blend the result with +the original image. With suitable parameters, this effect may also be used as +a blur filter. +*/ +class Bloom: public PostProcessor +{ +private: + Framebuffer fbo; + Texture2D tex[2]; + Program blur_shader; + ProgramData blur_shdata[2]; + Program combine_shader; + ProgramData combine_shdata; + Mesh quad; + +public: + Bloom(unsigned, unsigned); + + /** Sets the σ value of the gaussian blur. Values much larger than 4.0 are + likely to cause artifacts. */ + void set_radius(float); + + /** Sets the blend factor between original and blurred images. Larger + values mean more blurriness. */ + void set_strength(float); + + virtual void render(const Texture2D &); +}; + +} // namespace GL +} // namespace Msp + +#endif diff --git a/source/framebuffer.cpp b/source/framebuffer.cpp index 97a0147d..7ae391a4 100644 --- a/source/framebuffer.cpp +++ b/source/framebuffer.cpp @@ -30,7 +30,7 @@ Framebuffer::~Framebuffer() void Framebuffer::bind() const { glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, id); - current=this; + cur_fbo=this; } void Framebuffer::attach(FramebufferAttachment attch, Renderbuffer &rbuf) @@ -51,22 +51,27 @@ FramebufferStatus Framebuffer::check_status() const return static_cast(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT)); } +const Framebuffer *Framebuffer::current() +{ + return cur_fbo; +} + void Framebuffer::unbind() { - if(current) + if(cur_fbo) { glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - current=0; + cur_fbo=0; } } void Framebuffer::maybe_bind() const { - if(current!=this) + if(cur_fbo!=this) bind(); } -const Framebuffer *Framebuffer::current=0; +const Framebuffer *Framebuffer::cur_fbo=0; } // namespace GL } // namespace Msp diff --git a/source/framebuffer.h b/source/framebuffer.h index 437ac1af..ce362125 100644 --- a/source/framebuffer.h +++ b/source/framebuffer.h @@ -55,7 +55,7 @@ class Framebuffer private: uint id; - static const Framebuffer *current; + static const Framebuffer *cur_fbo; public: Framebuffer(); @@ -73,6 +73,7 @@ public: */ FramebufferStatus check_status() const; + static const Framebuffer *current(); static void unbind(); private: void maybe_bind() const; diff --git a/source/pixelformat.h b/source/pixelformat.h index d61788a6..ef373b86 100644 --- a/source/pixelformat.h +++ b/source/pixelformat.h @@ -11,6 +11,7 @@ Distributed under the LGPL #include #include #include "gl.h" +#include namespace Msp { namespace GL { @@ -26,10 +27,22 @@ enum PixelFormat ALPHA = GL_ALPHA, RGB = GL_RGB, RGBA = GL_RGBA, + RGB8 = GL_RGB8, + RGB16F = GL_RGB16F_ARB, + RGB32F = GL_RGB32F_ARB, + RGBA8 = GL_RGBA8, + RGBA16F = GL_RGBA16F_ARB, + RGBA32F = GL_RGBA32F_ARB, BGR = GL_BGR, BGRA = GL_BGRA, LUMINANCE = GL_LUMINANCE, - LUMINANCE_ALPHA = GL_LUMINANCE_ALPHA + LUMINANCE8 = GL_LUMINANCE8, + LUMINANCE16F = GL_LUMINANCE16F_ARB, + LUMINANCE32F = GL_LUMINANCE32F_ARB, + LUMINANCE_ALPHA = GL_LUMINANCE_ALPHA, + LUMINANCE_ALPHA8 = GL_LUMINANCE_ALPHA8, + LUMINANCE_ALPHA16F = GL_LUMINANCE_ALPHA16F_ARB, + LUMINANCE_ALPHA32F = GL_LUMINANCE_ALPHA32F_ARB, }; std::istream &operator>>(std::istream &, PixelFormat &); diff --git a/source/postprocessor.h b/source/postprocessor.h new file mode 100644 index 00000000..e40d8043 --- /dev/null +++ b/source/postprocessor.h @@ -0,0 +1,33 @@ +/* $Id$ + +This file is part of libmspgl +Copyright © 2009 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#ifndef MSP_GL_POSTPROCESSOR_H_ +#define MSP_GL_POSTPROCESSOR_H_ + +namespace Msp { +namespace GL { + +class Texture2D; + +/** +Base class for post-processing effects. +*/ +class PostProcessor +{ +protected: + PostProcessor() { } +public: + /** + Renders the effect. Takes the source texture as a parameter. + */ + virtual void render(const Texture2D &) =0; +}; + +} // namespace GL +} // namespace Msp + +#endif