[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