]> git.tdb.fi Git - libs/gl.git/commitdiff
Add post-processing effect framework
authorMikko Rasa <tdb@tdb.fi>
Sun, 25 Jan 2009 10:39:28 +0000 (10:39 +0000)
committerMikko Rasa <tdb@tdb.fi>
Sun, 25 Jan 2009 10:39:28 +0000 (10:39 +0000)
Add Bloom effect
Allow querying currently bound Framebuffer
Add floating-point PixelFormats

source/bloom.cpp [new file with mode: 0644]
source/bloom.h [new file with mode: 0644]
source/framebuffer.cpp
source/framebuffer.h
source/pixelformat.h
source/postprocessor.h [new file with mode: 0644]

diff --git a/source/bloom.cpp b/source/bloom.cpp
new file mode 100644 (file)
index 0000000..8a3bf3b
--- /dev/null
@@ -0,0 +1,157 @@
+/* $Id$
+
+This file is part of libmspgl
+Copyright © 2009  Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#include <cmath>
+#include <msp/strings/formatter.h>
+#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<int>(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<float> 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 (file)
index 0000000..c02604a
--- /dev/null
@@ -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
index 97a0147d4d3e2966777f715cd537022976a44a1c..7ae391a4a18c600dfe68c7461419dcaf3928d412 100644 (file)
@@ -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<FramebufferStatus>(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
index 437ac1afb79faeef5275df4d43403919c081cbba..ce36212528bb8ea5f2c5d9863fc61cb3ec810f73 100644 (file)
@@ -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;
index d61788a630ecb702359605afb8b23ba42bf60c78..ef373b86ba467ef2132f0aad2a8adf18fe1b769a 100644 (file)
@@ -11,6 +11,7 @@ Distributed under the LGPL
 #include <istream>
 #include <msp/gbase/pixelformat.h>
 #include "gl.h"
+#include <GL/glext.h>
 
 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 (file)
index 0000000..e40d804
--- /dev/null
@@ -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