First bloom tests

Pre alpha test version, and the code is ugly here and there…But I would really like some input on improvements, and how to make it fit better into jme, so heres the code…

(Users need to change paths to images and shaders accordingly)



One hack is the fullscreenquad, thought it was the easiest way at the time…

lots of adjustments can be done by changing the parameters(to get right amount of bloom for a scene, and to balance speed with looks, like setting number of blur passes)

I had a version with jmeDesktop sliders, but unfortunately it hangs all the time on my computer(the TestJMEDesktop does that too), so now it's just these:

1 - show bloom on/off

2/3 - set blursize

4/5 - set exposure mult

6/7 - set exposure cutoff

8/9 - set blur intensity multiplier

0 - reset parameters to default



and oh, it's about zero documentation in the code


FullScreenQuad.java


import com.jme.intersection.CollisionResults;
import com.jme.renderer.Renderer;
import com.jme.scene.Geometry;
import com.jme.scene.Spatial;
import org.lwjgl.opengl.GL11;

/**
 * FullScreenQuad
 */
public class FullScreenQuad extends Geometry {
    public FullScreenQuad(String name) {
        super(name);
    }

    public void draw(Renderer renderer) {
        super.applyStates();

        GL11.glMatrixMode(GL11.GL_MODELVIEW);
        GL11.glPushMatrix();
        GL11.glLoadIdentity();
        GL11.glMatrixMode(GL11.GL_PROJECTION);
        GL11.glPushMatrix();
        GL11.glLoadIdentity();
        GL11.glBegin(GL11.GL_QUADS);
        GL11.glTexCoord2f(0, 0);
        GL11.glVertex3i(-1, -1, -1);
        GL11.glTexCoord2f(1, 0);
        GL11.glVertex3i(1, -1, -1);
        GL11.glTexCoord2f(1, 1);
        GL11.glVertex3i(1, 1, -1);
        GL11.glTexCoord2f(0, 1);
        GL11.glVertex3i(-1, 1, -1);
        GL11.glEnd();
        GL11.glPopMatrix();
        GL11.glMatrixMode(GL11.GL_MODELVIEW);
        GL11.glPopMatrix();
    }

    public void findCollisions(Spatial spatial, CollisionResults collisionResults) {
    }

    public boolean hasCollision(Spatial spatial, boolean b) {
        return false;
    }
}



extract.vert


varying vec4 viewCoords;
varying vec2 vTexCoord;

void main(void)
{
   vec2 Pos = sign(gl_Vertex.xy);

   gl_Position = vec4(Pos.xy, 0, 1);
   vTexCoord.x = 0.5 * (1.0 + Pos.x);
   vTexCoord.y = 0.5 * (1.0 + Pos.y);

   viewCoords = gl_ModelViewProjectionMatrix * gl_Vertex;
}



extract.frag


uniform float exposurePow;
uniform float exposureCutoff;
uniform sampler2D RT;

varying vec4 viewCoords;
varying vec2 vTexCoord;

void main(void)
{
   vec4 sum = texture2D(RT, vTexCoord);
   if ( (sum.r+sum.g+sum.b)/3.0 < exposureCutoff ) {
      sum = vec4(0.0);
   }
   sum = pow(sum,exposurePow);
   gl_FragColor = sum;
}



blur.vert


varying vec4 viewCoords;
varying vec2 vTexCoord;

void main(void)
{
   vec2 Pos = sign(gl_Vertex.xy);

   gl_Position = vec4(Pos.xy, 0, 1);
   vTexCoord.x = 0.5 * (1.0 + Pos.x);
   vTexCoord.y = 0.5 * (1.0 + Pos.y);

   viewCoords = gl_ModelViewProjectionMatrix * gl_Vertex;
}



blur.frag


uniform float sampleDist0;
uniform float blurIntensityMultiplier;
uniform sampler2D RT;
//uniform sampler2D depth;

varying vec4 viewCoords;
varying vec2 vTexCoord;

void main(void)
{
  vec2 samples00 = vec2(-0.326212, -0.405805);
   vec2 samples01 = vec2(-0.840144, -0.073580);
   vec2 samples02 = vec2(-0.695914,  0.457137);
   vec2 samples03 = vec2(-0.203345,  0.620716);
   vec2 samples04 = vec2( 0.962340, -0.194983);
   vec2 samples05 = vec2( 0.473434, -0.480026);
   vec2 samples06 = vec2( 0.519456,  0.767022);
   vec2 samples07 = vec2( 0.185461, -0.893124);
   vec2 samples08 = vec2( 0.507431,  0.064425);
   vec2 samples09 = vec2( 0.896420,  0.412458);
   vec2 samples10 = vec2(-0.321940, -0.932615);
   vec2 samples11 = vec2(-0.791559, -0.597705);

   vec2 newCoord;
   vec4 sum = texture2D(RT, vTexCoord);

 //depth of field
//   vec4 projCoord = viewCoords / viewCoords.q;
//   projCoord = (projCoord + 1.0) * 0.5;
//  vec4 d = texture2D(depth, projCoord);
//  sampleDist0 = (pow(d.x,25.0)-0.4)*sampleDist0;

   newCoord = vTexCoord + sampleDist0 * samples00;
   sum += texture2D(RT, newCoord);

   newCoord = vTexCoord + sampleDist0 * samples01;
   sum += texture2D(RT, newCoord);

   newCoord = vTexCoord + sampleDist0 * samples02;
   sum += texture2D(RT, newCoord);

   newCoord = vTexCoord + sampleDist0 * samples03;
   sum += texture2D(RT, newCoord);
  
   newCoord = vTexCoord + sampleDist0 * samples04;
   sum += texture2D(RT, newCoord);

   newCoord = vTexCoord + sampleDist0 * samples05;
   sum += texture2D(RT, newCoord);

   newCoord = vTexCoord + sampleDist0 * samples06;
   sum += texture2D(RT, newCoord);

   newCoord = vTexCoord + sampleDist0 * samples07;
   sum += texture2D(RT, newCoord);

   newCoord = vTexCoord + sampleDist0 * samples08;
   sum += texture2D(RT, newCoord);
  
   newCoord = vTexCoord + sampleDist0 * samples09;
   sum += texture2D(RT, newCoord);

   newCoord = vTexCoord + sampleDist0 * samples10;
   sum += texture2D(RT, newCoord);

   newCoord = vTexCoord + sampleDist0 * samples11;
   sum += texture2D(RT, newCoord);

   sum /= 13.0;
   sum *= blurIntensityMultiplier;

   gl_FragColor = sum;
}

Got this in a zip somewhere with the texture you're using?

any screenshots?  Sometimes when it comes to shaders it's really what it looks like.

the textures can be anything, they are not for the effect itself, just made a testscene to run the effect on…(picked them out of the jme test-data folder too, bundled with the jme distribution)…



shots from the prog…



bloom off:





bloom on:





other bloom parameters:








the reason for not rendering the full scene once to a texture and reusing it in the final blend, is that you many times want to use a different source for the glow than the full scene…or using special glow textures or renderstates(or emissive materials) as source…



heres an example of using other renderstates for the bloom source(instead of the full rootNode scene as above)



http://img354.imageshack.us/my.php?image=shotdiff8ob.jpg

http://img485.imageshack.us/my.php?image=shotdiff22za.jpg

That looks extremely nice, MrCoder! :-o

Great job! :smiley:

I second the notion. :)  Now if you can just get the bloom effect working with water surfaces you'll be golden. :-p



darkfrog

Awsome and impressive MrCoder.

Do you have examples where this can be used in a game; i mean game use cases, where the glow effect fits perfectly ?

used correctly, I think it can add something to any scene…makes the scene more vivid…nowdays it’s often used in conjunction with HDR(high dynamic range) rendering, but I think it’s quite ok even without…

good examples of games are half-life 2, unreal engine 3, halo 2, tron 2 and so on…



heres a good page on HDR and bloom effects with nice screenshots on good usages…

http://www.bit-tech.net/gaming/2005/06/14/hl2_hdr_overview/1.html



and here is a page on glow, wich is one possible usage of the effect:

http://www.gamasutra.com/features/20040526/james_01.shtml



there are nice pics and samples of bloom on unreal technology site, both in unreal engine 2X and unreal engine 3 (and also on other nice imagespace effects that I want to develop, like depth of field and radial blur etc)

http://www.unrealtechnology.com/

the blurring part of the glslbloom code is also easily modified for other types of image space fun, like depth of field(will try to post the mod very soon as well):





i love depth of field.  What about the water reflection stuff ever gonna post it?

I get this while trying to load the extract.frag shader:



SEVERE: ERROR: 0:14: 'pow' : no matching overloaded function found

ERROR: 0:14: 'assign' :  cannot convert from 'const float' to '4-component vector of float'

ERROR: 2 compilation errors.  No code generated.



Looks like it's referring to:



sum = pow(sum,exposurePow);



ideas?

you are right, the spec says, "genType pow (genType x, genType y)",  so it's very strange my drivers are so forgiving they were accepting vec4 pos(vec4,float)…strange…

try to change it to

sum = pow(sum,vec4(exposurePow));



there are other ways of killing out dark areas, this was just my try…



hope there are no other errors like that, it's scary when the glsl compiler works differently on different cards/drivers

you could just throw your code into a glsl IDE so it'd check thinks like that.  I think 3dlabs also has a command line thing too.

That did the trick, it looks great too. Oddly enough, my JVM crashes on exit. Any clean up we should be doing you think?

yes, forgot that too…need to release the pbuffers with the cleanup method on the TextureRenderers…



    protected void cleanup() {
        tRendererFirst.cleanup();
        tRendererSecond.cleanup();
    }



in GLSLBloom.java for example, and make sure it is called from the user program...

Cool, perfect. Can you tell I'm a GLSL newbie? :wink: Anything goes wrong, I just stare at the screen for a few minutes heheh.

hehe  :smiley: even the sun has spots s