Multi-Pass with Filter/Filter on Certain Objects

I have a couple things I have been working on for a few days but can’t seem to figure out, so I’ll post both of them in the same place so as to not spam the boards.

1.

I have programmed a small, simple bloom shader using this code:

uniform sampler2D m_Texture;

varying vec2 texCoord;

void main() {
    vec4 color = texture2D(m_Texture, texCoord);

    int h, v;
    vec4 sum = vec4(0);
    for(h = -2; h <= 2; h++){
        for(v = -2; v <= 2; v++){
            vec2 offset = vec2(h, v) * 0.005;
            sum += texture2D(m_Texture, texCoord  + vec4(offset, 0.0, 0.0));
        }
    }
    gl_FragColor = (sum / 25) + color;
}

So that produces a (nasty) looking bloom effect as shown in these photos:

I would like to implement a real blur, like gaussian blur, to get something like this:

See how there aren’t any obvious blur pieces like mine has? In my pictures above you can see the different levels of the “blur” coming out from the boxes.
In order to fix I thought I could do a gaussian blur as described in this article. This does the blur in the vertex shader, and it’s usually done in the fragment shader, but that’s offtopic.
In order to do it this way I need to do multiple passes. Of course I could do the blur in a single pass, but from what I’ve heard that isn’t very good for performance (right?).

So I checked out the built in Bloom filter and saw them using the Pass class, but I honestly don’t know the correct way to use it. So how would I use Pass for a two pass gaussian blur for my bloom?

2.

So I tried implementing this filter into my actual game to see if I could improve performance from the built in bloom filter. Since I couldn’t limit the effect to only my player (the ball) the whole scene is extraordinarily “bloomish”. Check it out:

With

Without

So as you can see it’s a little overpowered. The whole reason I am doing this is to get the ball to just glow a little bit to get this effect:

[video]http://www.youtube.com/watch?v=IL3MIwlnfdU[/video]

My game is a little similar to it in terms of appearance but the gameplay is going to be completely different, I’m just using it for a little role model on the graphics side.
So can I just apply my filter to the little playerball?

Thanks for any help guys, I really appreciate it.

1 Like

The built in bloom filter already lets you glow just selected objects if you want. Is there a reason you are writing your own?

Performance reasons as well as learning. I’m running *nix and for some reason, maybe it’s my ati drivers, mouse input and keyboard input gets very slow when there are large effects going on, or when the framerate is high (over 70 seems to be when it starts and when testing on Minecraft it seemed to start getting input lag at about 70 FPS).

@Slyth said: Performance reasons as well as learning. I'm running *nix and for some reason, maybe it's my ati drivers, mouse input and keyboard input gets very slow when there are large effects going on, or when the framerate is high (over 70 seems to be when it starts and when testing on Minecraft it seemed to start getting input lag at about 70 FPS).

But your description of what you are trying to do sounds exactly like what the existing bloom filter is already doing (right down to the gaussian blur) so I’m not sure how you will improve performance doing pretty much exactly the same thing.

So at the very least if you have ideas for improving the same thing then you could start with the same thing and “undo” what you think is slow. But it sounds like the problem is hardware + OS related anyway if even Minecraft is causing issues.

Oh cool, the bloom filter uses gaussian too? Neat.
Anyways, you’re most likely right it probably is OS related. Even though it may be pointless I would still like to try and do this to learn more about the engine and shaders.

ubuntu by any chance? they fucked up the ati driver, the driver itself works fine on arch on my machine for example (40fps to 460)

You guessed it. Switching to an arch/crunchbang dual boot soon. Anyways, back on topic, can anyone help me?

  1. Initialize the built in postRenderPasses as an ArrayList
  2. Create a Pass, call the init method, create a material for the vertical blur, feed it with parameters, add the material to the pass (setPassMaterial), then add the pass the the postRenderPassses list
  3. redo 2 for the horizontal blur pass.

This is pretty much what is done in the bloom filter

Thanks @nehon, I got all the pass stuff to work however I’m running into a ridiculous elementary problem that really has me irritated. The program is seeming to refuse to pass anything other than a Texture2D into my shaders. I very specifically have defined a uniform, put it in the .j3md file and passed it in through beforeRender() however whenever I print it out the program prints null. The shader automatically assigns the value to 0 (or just thinks of null as 0?) therefore I am essentially setting blur to 0/0 which doesn’t even throw an error for some reason. I thought dividing by zero was impossible.
Here’s the horizontal blur (it’s the same on the vertical, just switched to the y axis on the sum += part):

uniform float Scale;
uniform float Size;
uniform sampler2D m_Texture;
varying vec2 texCoord;

void main() {

    vec4 color = texture2D(m_Texture, texCoord);

    float s = float(Scaleint);

    float blurSize = Scale/Size;

    vec4 sum = vec4(0.0);

    sum += texture2D(m_Texture, vec2(texCoord.x- 4.0*blurSize, texCoord.y )) * 0.05;
    sum += texture2D(m_Texture, vec2(texCoord.x- 3.0*blurSize, texCoord.y )) * 0.09;
    sum += texture2D(m_Texture, vec2(texCoord.x - 2.0*blurSize, texCoord.y)) * 0.12;
    sum += texture2D(m_Texture, vec2(texCoord.x- blurSize, texCoord.y )) * 0.15;
    sum += texture2D(m_Texture, vec2(texCoord.x, texCoord.y)) * 0.16;
    sum += texture2D(m_Texture, vec2(texCoord.x+ blurSize, texCoord.y )) * 0.15;
    sum += texture2D(m_Texture, vec2(texCoord.x+ 2.0*blurSize, texCoord.y )) * 0.12;
    sum += texture2D(m_Texture, vec2(texCoord.x+ 3.0*blurSize, texCoord.y )) * 0.09;
    sum += texture2D(m_Texture, vec2(texCoord.x+ 4.0*blurSize, texCoord.y )) * 0.05;
    
    gl_FragColor = sum;
}

As well as the .j3md:

MaterialDef HGaussianBlur {

    MaterialParameters {
        Int NumSamples
        Float Scale
        Float Size
        Texture2D Texture
    }

    Technique {
        VertexShader GLSL150: Common/MatDefs/Post/Post15.vert
        FragmentShader GLSL150: Shaders/HGaussianBlur.frag

        WorldParameters {
            WorldViewProjectionMatrix
        }

        Defines {
            RESOLVE_MS : NumSamples
        }
    }

    Technique {
        VertexShader GLSL100: Common/MatDefs/Post/Post.vert
        FragmentShader GLSL100: Shaders/HGaussianBlur.frag

        WorldParameters {
            WorldViewProjectionMatrix
        }
    }
}

And finally the extends Filter class

[java]
public class CustomBloomFilter extends Filter {

Main main;
private float blurScale = 1.0f;
Material vGBlur, hGBlur;
Pass vGPass = new Pass(), hGPass = new Pass();
float downSamplingFactor = 1;
int screenWidth;
int screenHeight;

public CustomBloomFilter(Main main) {
    super("CustomBloomFilter");
    this.main = main;
}

@Override
protected Material getMaterial() {
    return this.material;
}

@Override
protected void initFilter(final AssetManager manager, final RenderManager renderManager, final ViewPort vp, final int w, final int h) {
    screenWidth = (int) Math.max(1, (w / downSamplingFactor));
    screenHeight = (int) Math.max(1, (h / downSamplingFactor));
    postRenderPasses = new ArrayList<Pass>();

    System.out.println(screenWidth + " / " + screenHeight);

    hGBlur = new Material(manager, "MatDefs/HGaussianBlur.j3md");
    hGPass = new Pass() {
        @Override
        public boolean requiresSceneAsTexture() {
            return true;
        }

        @Override
        public void beforeRender() {
            hGBlur.setFloat("Size", 512.0f);
            hGBlur.setFloat("Scale", 1.0f);
        }
    };
    hGPass.init(renderManager.getRenderer(), screenWidth, screenHeight, Image.Format.RGBA8, Image.Format.Depth, 1, hGBlur);
    postRenderPasses.add(hGPass);

    vGBlur = new Material(manager, "MatDefs/VGaussianBlur.j3md");
    vGPass = new Pass() {
        @Override
        public void beforeRender() {
            vGBlur.setFloat("Size", 512.0f);
            vGBlur.setFloat("Scale", 1.0f);
            vGBlur.setTexture("Texture", hGPass.getRenderedTexture());
        }
    };
    vGPass.init(renderManager.getRenderer(), screenWidth, screenHeight, Image.Format.RGBA8, Image.Format.Depth, 1, vGBlur);
    postRenderPasses.add(vGPass);

    System.out.println(hGBlur.getParam("Size") + " : " + vGBlur.getParam("Scale"));

    material = new Material(manager, "MatDefs/BloomFilter.j3md");
    material.setTexture("BloomTex", vGPass.getRenderedTexture());
}

}
[/java]

I have set everything down to the variable names to the same as the built in bloom shader (don’t ask me why the variable names are the same, I do weird stuff when debugging) and I honestly can’t figure out what is going wrong. I thought maybe it was something to do with the values I was passing in so I just set them to 1.0 and 512.0, but still nothing.

I certainly don’t expect you to look through all this code and run it, debug it, and just give me correct code, but maybe could you just skim over it or just tell me what you think could be going on?

Thanks, it’s really appreciated

Bump?

Sorry i missed that post.

You don’t have to set your parameters in the beforeRender, you can set them in the method right after creating the material.
It should work though I do’nt really get what’s going on.

@nehon said: Sorry i missed that post.

You don’t have to set your parameters in the beforeRender, you can set them in the method right after creating the material.
It should work though I do’nt really get what’s going on.

No problem.

Funny enough, when I set the parameters right after I create the material the println statement works, printing out the variables I passed in, which means GLSL is registering the variables.

However it still acts like it is zero! If I use the code

    if(Size == 0 && Scale == 0){
        gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
    } else {
        gl_FragColor = sum;
    }

In any one of the blur passes it colors the screen red, which means inside the shader the variables are zero, even though the System.out.println statement prints the values that I set when using pass.getParam()/

What’s up with that? Honestly it’s starting to really irritate me, I just don’t get why the shader would act like these two variables are zero even when the program prints it out just fine!

Must be a different material instance then.

I don’t see how that could be happening, I’m only creating the materials in initFilter and that is just run once.

Edit: It would look like you are right pspeed however I have just inspected the code very closely and there really is no way another instance is being created, unless there is something inside the engine that is doing it.

Oh I get it. in the shader the variable has to be referred as m_Size and m_Scale. (the material parameter name has to remain Size and Scale)
All uniform coming from a material parameter are prefixed like this in a shader in JME.

1 Like

Well that’s an interesting rule. At least I know it now, thanks alot nehon :slight_smile: