[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    playground/games/astrododge
From:       Rivo Laks <rivolaks () hot ! ee>
Date:       2008-06-28 11:50:09
Message-ID: 1214653809.632054.10610.nullmailer () svn ! kde ! org
[Download RAW message or body]

SVN commit 825492 by rivol:

- Add support for bloom.
  Bloom can be done before or after tonemapping and can of course also be disabled.

- Don't call glInit() twice.
- No need to clear color and depth buffers if we're going to overwrite its contents \
                anyway.
- Don't create depth buffer for tonemapping and luminance detection rendertargets.

 M  +5 -19     data/shaders/blur.frag  
 M  +242 -13   src/hdrglwidget.cpp  
 M  +25 -0     src/hdrglwidget.h  


--- trunk/playground/games/astrododge/data/shaders/blur.frag #825491:825492
@@ -1,7 +1,5 @@
-uniform float scale;
-uniform float weight;
 uniform float ramp;
-uniform vec2 texSize;
+uniform vec2 inverseTextureSize;
 
 uniform sampler2D inputTexture;
 
@@ -9,28 +7,16 @@
 // Offset is in pixels
 vec3 sampleAtOffset(vec2 offset)
 {
-    vec2 coord = gl_TexCoord[0].xy + offset * scale * texSize;
-    return max(vec3(0.0), texture2D(inputTexture, coord).rgb - vec3(ramp)) * weight;
+    vec2 coord = gl_TexCoord[0].xy + offset * BLURDIRECTION * inverseTextureSize;
+    return max(vec3(0.0), texture2D(inputTexture, coord).rgb - vec3(ramp));
 }
 
 
 void main()
 {
-    // First the center sample
-    vec3 result = 0.4 * max(vec3(0.0), texture2D(inputTexture, \
gl_TexCoord[0].xy).rgb - vec3(ramp)); +    vec3 result = vec3(0.0);
 
-    // Then all other samples
-    float rad = 1.0;
-    result += sampleAtOffset(vec2(-rad, -rad));
-    result += sampleAtOffset(vec2(-rad,  rad));
-    result += sampleAtOffset(vec2( rad,  rad));
-    result += sampleAtOffset(vec2( rad, -rad));
+    BLURCODE
 
-    rad = 2.0;
-    result += sampleAtOffset(vec2(-rad,  0.0)) * 0.5;
-    result += sampleAtOffset(vec2( rad,  0.0)) * 0.5;
-    result += sampleAtOffset(vec2( 0.0, -rad)) * 0.5;
-    result += sampleAtOffset(vec2( 0.0,  rad)) * 0.5;
-
     gl_FragColor = vec4(result, 1.0);
 }
--- trunk/playground/games/astrododge/src/hdrglwidget.cpp #825491:825492
@@ -19,11 +19,14 @@
 
 #include <kgllib/rendertarget.h>
 #include <kgllib/program.h>
+#include <kgllib/shader.h>
 #include <kgllib/texture.h>
 #include <eigen/vector.h>
 
 #include <KDebug>
 
+#include <QFile>
+
 using namespace Eigen;
 
 namespace KGLLib
@@ -57,6 +60,9 @@
 {
     mSceneRenderTarget = 0;
     mLuminanceDetectionTarget = 0;
+    mTonemappingTarget = 0;
+    mBloomHTarget = 0;
+    mBloomVTarget = 0;
 
     mHdrRenderingSupported = false;
     mDataPath = ".";
@@ -64,6 +70,9 @@
     mHdrRenderingActive = true;
     mExposure = 1.0f;
     mAutoExposure = false;
+    mBloomEnabled = true;
+    mBloomAfterTonemapping = false;
+    mBloomDownsize = 2;
 }
 
 void HdrGLWidget::setDataPath(const QString& path)
@@ -74,7 +83,7 @@
 void HdrGLWidget::initializeGL()
 {
     GLWidget::initializeGL();
-    initGL();
+    // GLWidget::initializeGL() calls initializeGL(Renderer*) which calls initGL()
 }
 
 void HdrGLWidget::initializeGL(Renderer* r)
@@ -114,6 +123,9 @@
     mTonemappingProgram->setUniform("sceneTexture", 0);
     mTonemappingProgram->unbind();
 
+    mBloomHProgram = generateBlurProgram(3.0, 6, true);
+    mBloomVProgram = generateBlurProgram(3.0, 6, false);
+
     // Everything succeeded, HDR rendering is supported
     mHdrRenderingSupported = true;
 }
@@ -122,16 +134,15 @@
 {
     GLWidget::resizeGL(width, height);
 
-    // Delete current render target.
+    // Delete all current render targets, they'll be recreated lazyly
     delete mSceneRenderTarget;
-    // Create new rendertarget
-    mSceneRenderTarget = new RenderTarget(width, height, true, GL_RGBA16F_ARB);
-    // We want to use mipmapped filter for the scene texture
-    mSceneRenderTarget->texture()->bind();
-    // We need to generate the mipmaps before we use them for filtering.
-    glGenerateMipmapEXT(GL_TEXTURE_2D);
-    mSceneRenderTarget->texture()->setFilter(GL_LINEAR_MIPMAP_LINEAR);
-    mSceneRenderTarget->texture()->disable();
+    mSceneRenderTarget = 0;
+    delete mTonemappingTarget;
+    mTonemappingTarget = 0;
+    delete mBloomHTarget;
+    mBloomHTarget = 0;
+    delete mBloomVTarget;
+    mBloomVTarget = 0;
 }
 
 void HdrGLWidget::render()
@@ -145,6 +156,16 @@
     }
 
     // Render the scene
+    if (!mSceneRenderTarget || mSceneRenderTarget->size() != size()) {
+        delete mSceneRenderTarget;
+        mSceneRenderTarget = new RenderTarget(width(), height(), true, \
GL_RGBA16F_ARB); +        // We want to use mipmapped filter for the scene texture
+        mSceneRenderTarget->texture()->bind();
+        // We need to generate the mipmaps before we use them for filtering.
+        glGenerateMipmapEXT(GL_TEXTURE_2D);
+        mSceneRenderTarget->texture()->setFilter(GL_LINEAR_MIPMAP_LINEAR);
+        mSceneRenderTarget->texture()->disable();
+    }
     activateRenderTarget(mSceneRenderTarget);
     renderScene();
     deactivateRenderTarget(mSceneRenderTarget);
@@ -153,8 +174,39 @@
     if (mAutoExposure) {
         calculateHdrExposure();
     }
+
+    if (mBloomEnabled && !mBloomAfterTonemapping) {
+        // Do the bloom before tonemapping
+        hdrBloom();
+    }
+
     // Do the tonemapping
-    hdrTonemapping();
+    if (mBloomEnabled && mBloomAfterTonemapping) {
+        // When we do bloom after tonemapping, then tonemapping's results need
+        //  to go to their own rendertarget
+        if (!mTonemappingTarget || mTonemappingTarget->size() != size()) {
+            delete mTonemappingTarget;
+            mTonemappingTarget = new RenderTarget(width(), height(), false, \
GL_RGBA16F_ARB); +        }
+        activateRenderTarget(mTonemappingTarget);
+        hdrTonemapping();
+        deactivateRenderTarget(mTonemappingTarget);
+        // Copy tonemapping's results onto screen
+        mTonemappingTarget->texture()->enable();
+        setupOrthoProjection(width(), height());
+        render2DQuad(width(), height());
+        mTonemappingTarget->texture()->disable();
+
+        // We'll use additive blending to combine results of tonemapping and bloom
+        hdrBloom();
+    } else {
+        // No bloom here, just tonemapping and results go directly onto the screen.
+        glEnable(GL_BLEND);
+        glBlendFunc(GL_ONE, GL_ONE);
+        hdrTonemapping();
+        glDisable(GL_BLEND);
+        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    }
 }
 
 void HdrGLWidget::calculateHdrExposure()
@@ -168,7 +220,7 @@
     const int luminanceDetectionTargetSize = 8;
     if (!mLuminanceDetectionTarget) {
         mLuminanceDetectionTarget = new RenderTarget(luminanceDetectionTargetSize, \
                luminanceDetectionTargetSize,
-                                                     true, GL_RGBA16F_ARB);
+                                                     false, GL_RGBA16F_ARB);
     }
 
     activateRenderTarget(mLuminanceDetectionTarget);
@@ -216,6 +268,100 @@
     mSceneRenderTarget->texture()->disable();
 }
 
+void HdrGLWidget::hdrBloom()
+{
+    // The source rendertarget which we'll blur
+    RenderTarget* sourceTarget = mBloomAfterTonemapping ? mTonemappingTarget : \
mSceneRenderTarget; +
+    // Recreate bloom target if necessary
+    int blurw = width()/mBloomDownsize;
+    int blurh = height()/mBloomDownsize;
+    if (!mBloomHTarget || mBloomHTarget->size() != QSize(blurw, blurh)) {
+        delete mBloomHTarget;
+        mBloomHTarget = new RenderTarget(blurw, blurh, false, GL_RGBA16F_ARB);
+        // Use linear filtering
+        mBloomHTarget->texture()->bind();
+        mBloomHTarget->texture()->setFilter(GL_LINEAR);
+        mBloomHTarget->texture()->disable();
+        // Update texture size variables in programs
+        mBloomHProgram->bind();
+        mBloomHProgram->setUniform("inverseTextureSize", Vector2f(1.0f / blurw, 1.0f \
/ blurh)); +        mBloomHProgram->unbind();
+        mBloomVProgram->bind();
+        mBloomVProgram->setUniform("inverseTextureSize", Vector2f(1.0f / blurw, 1.0f \
/ blurh)); +        mBloomVProgram->unbind();
+    }
+
+    // First the horizontal blur pass
+    activateRenderTarget(mBloomHTarget);
+    // Bind scene texture
+    glActiveTexture(GL_TEXTURE0);
+    sourceTarget->texture()->enable();
+    // Bind tonemapping shader
+    mBloomHProgram->bind();
+    if (!mBloomAfterTonemapping) {
+        const float rampAfterTonemapping = 0.7;
+        const float rampBeforeTonemapping = -log(1 - rampAfterTonemapping) / \
exposure(); +//         kDebug() << "    ramp mapping:" << rampAfterTonemapping << \
"->" << rampBeforeTonemapping; +        mBloomHProgram->setUniform("ramp", \
rampBeforeTonemapping); +    } else {
+        mBloomHProgram->setUniform("ramp", 0.8f);
+    }
+    // Render a quad
+    setupOrthoProjection(blurw, blurh);
+    render2DQuad(blurw, blurh);
+    // Unbind everything
+    mBloomHProgram->unbind();
+    glActiveTexture(GL_TEXTURE0);
+    sourceTarget->texture()->disable();
+    deactivateRenderTarget(mBloomHTarget);
+
+
+    // Then the vertical blur pass, results of which go directly onto screen
+    //  (with additive blending)
+    if (mBloomDownsize != 1) {
+        // When bloom texture is downsized, we can't render directly onto
+        //  screen, so we must use another rendertarget
+        if (!mBloomVTarget || mBloomVTarget->size() != QSize(blurw, blurh)) {
+            delete mBloomVTarget;
+            mBloomVTarget = new RenderTarget(blurw, blurh, false, GL_RGBA16F_ARB);
+            // Use linear filtering
+            mBloomVTarget->texture()->bind();
+            mBloomVTarget->texture()->setFilter(GL_LINEAR);
+            mBloomVTarget->texture()->disable();
+        }
+        activateRenderTarget(mBloomVTarget);
+    } else {
+        glEnable(GL_BLEND);
+        glBlendFunc(GL_ONE, GL_ONE);
+    }
+    // Bind scene texture
+    glActiveTexture(GL_TEXTURE0);
+    mBloomHTarget->texture()->enable();
+    // Bind tonemapping shader
+    mBloomVProgram->bind();
+    // Render a quad
+    setupOrthoProjection(blurw, blurh);
+    render2DQuad(blurw, blurh);
+    // Unbind everything
+    mBloomVProgram->unbind();
+    glActiveTexture(GL_TEXTURE0);
+    mBloomHTarget->texture()->disable();
+
+    if (mBloomDownsize != 1) {
+        deactivateRenderTarget(mBloomVTarget);
+        // Copy blur results onto screen
+        glEnable(GL_BLEND);
+        glBlendFunc(GL_ONE, GL_ONE);
+        mBloomVTarget->texture()->enable();
+        setupOrthoProjection(width(), height());
+        render2DQuad(width(), height());
+        mBloomVTarget->texture()->disable();
+    }
+    glDisable(GL_BLEND);
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+}
+
 void HdrGLWidget::renderScene()
 {
 }
@@ -238,7 +384,6 @@
 {
     // Set up ortho projection, clear buffers
     glViewport(0, 0, width, height);
-    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     glDisable(GL_DEPTH_TEST);
 
     glMatrixMode(GL_PROJECTION);
@@ -264,6 +409,90 @@
     glPopAttrib();
 }
 
+float* HdrGLWidget::calculateBlurKernel(float sigma, int radius)
+{
+    float* kernel = new float[radius+1];
+    kernel[0] = 1.0;
+    float sum = 1.0;
+    for (int i = 1; i <= radius; i++) {
+        kernel[i] = exp(-(i*i) / (2*sigma*sigma));
+        sum += kernel[i];
+    }
+    for (int i = 0; i <= radius; i++) {
+        kernel[i] = kernel[i] / sum;
+    }
+
+    return kernel;
 }
 
+Program* HdrGLWidget::generateBlurProgram(float sigma, int radius, bool horizontal)
+{
+    kDebug();
+    Shader* vert = generateBlurVertexShader(sigma, radius, horizontal);
+    Shader* frag = generateBlurFragmentShader(sigma, radius, horizontal);
+    if (!vert || !frag) {
+        return 0;
+    }
+    QList<Shader*> shaders;
+    shaders << vert << frag;
+    Program* prog = new Program(shaders);
+    if (!prog->isValid()) {
+        kError() << "Invalid program";
+        delete prog;
+        return 0;
+    }
+    prog->bind();
+    prog->setUniform("ramp", horizontal ? 0.8f : 0.0f);
+    prog->setUniform("inputTexture", 0);
+    prog->unbind();
+    kDebug() << "All done";
+    return prog;
+}
+
+Shader* HdrGLWidget::generateBlurVertexShader(float sigma, int radius, bool \
horizontal) +{
+    Shader* s = new VertexShader(mDataPath + "/blur.vert");
+    if (!s->isValid()) {
+        kError() << "Invalid shader";
+        delete s;
+        return 0;
+    }
+    return s;
+}
+
+Shader* HdrGLWidget::generateBlurFragmentShader(float sigma, int radius, bool \
horizontal) +{
+    QFile f(mDataPath + "/blur.frag");
+    if (!f.open(QIODevice::ReadOnly)) {
+        kDebug() << "Can't open blur.frag for reading";
+        return 0;
+    }
+    QByteArray source;
+    if (horizontal) {
+        source += "#define BLURDIRECTION vec2(1.0, 0.0)\n";
+    } else {
+        source += "#define BLURDIRECTION vec2(0.0, 1.0)\n";
+    }
+    source += "#define BLURCODE ";
+    float* kernel = calculateBlurKernel(sigma, radius);
+    for (int r = -radius; r <= radius; r++) {
+        source += QString(" \\\n    result += sampleAtOffset(%1.0) * \
%2;").arg(r).arg(kernel[qAbs(r)]).toAscii(); +    }
+    delete kernel;
+    source += "\n\n";
+    source += f.readAll();
+    kDebug() << "Shader source is:\n" << source;
+
+    FragmentShader* shader = new FragmentShader();
+    shader->setSource(source);
+    if (!shader->compile()) {
+        kError() << "Shader failed to compile";
+        delete shader;
+        return 0;
+    }
+    return shader;
+}
+
+}
+
 #include "hdrglwidget.moc"
--- trunk/playground/games/astrododge/src/hdrglwidget.h #825491:825492
@@ -24,6 +24,7 @@
 {
 class RenderTarget;
 class Program;
+class Shader;
 
 
 class HdrGLWidget : public GLWidget
@@ -78,6 +79,15 @@
      **/
     void setAutoExposure(bool a)  { mAutoExposure = a; }
 
+    bool bloomEnabled() const  { return mBloomEnabled; }
+    void setBloomEnabled(bool e)  { mBloomEnabled = e; }
+
+    bool bloomAfterTonemapping() const  { return mBloomAfterTonemapping; }
+    void setBloomAfterTonemapping(bool e)  { mBloomAfterTonemapping = e; }
+
+    int bloomDownsize() const  { return mBloomDownsize; }
+    void setBloomDownsize(int d)  { mBloomDownsize = d; }
+
     void render2DQuad(float width, float height) const;
     void setupOrthoProjection(int width, int height) const;
     void activateRenderTarget(RenderTarget* target) const;
@@ -97,9 +107,15 @@
     virtual void renderScene();
 
     virtual void hdrTonemapping();
+    virtual void hdrBloom();
 
     virtual void calculateHdrExposure();
 
+    virtual float* calculateBlurKernel(float sigma, int radius);
+    virtual Program* generateBlurProgram(float sigma, int radius, bool horizontal);
+    virtual Shader* generateBlurVertexShader(float sigma, int radius, bool \
horizontal); +    virtual Shader* generateBlurFragmentShader(float sigma, int radius, \
bool horizontal); +
 private:
     void init();
     void initGL();
@@ -109,10 +125,19 @@
 
     RenderTarget* mSceneRenderTarget;
     RenderTarget* mLuminanceDetectionTarget;
+    RenderTarget* mTonemappingTarget;
+    RenderTarget* mBloomHTarget;
+    RenderTarget* mBloomVTarget;
     QString mDataPath;
     Program* mTonemappingProgram;
+    Program* mBloomHProgram;
+    Program* mBloomVProgram;
+
     float mExposure;
     bool mAutoExposure;
+    bool mBloomEnabled;
+    bool mBloomAfterTonemapping;
+    int mBloomDownsize;
 };
 
 }


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic