Bloom effect on viewports with setClearEnabled(false)

Hi, I’m trying to get a bloom filter working on a viewport with setClearEnabled(false) (so that viewports underneath show up).

It is currently possible to add a bloom filter on such a viewport, but since it is not cleared, the bloom effect “blooms itself”, meaning that the brightness added by the bloom filter itself is taken into consideration in the next render.



One solution to this would be to keep a viewport offscreen and have everything non-bloomed there, and on each frame, pass the bloom filter over it and paint the result to another (on-screen) viewport. But I guess this is quite costly. Is there any solution? Thanks.

The thing is, the FilterPostProcessor uses a separate offscreen buffer to do the bloom, that means you need to somehow clear that buffer before all your viewports render …

Okay, but… how would I do that?

could you post a test case so I could look into it.

I don’t really get what you’re trying to do though, could you elaborate please?

Okay, here is an example:



[java]import com.jme3.app.SimpleApplication;

import com.jme3.material.Material;

import com.jme3.math.ColorRGBA;

import com.jme3.math.FastMath;

import com.jme3.math.Vector3f;

import com.jme3.post.FilterPostProcessor;

import com.jme3.post.filters.BloomFilter;

import com.jme3.post.filters.BloomFilter.GlowMode;

import com.jme3.renderer.Camera;

import com.jme3.renderer.ViewPort;

import com.jme3.renderer.queue.RenderQueue.Bucket;

import com.jme3.scene.Geometry;

import com.jme3.scene.Node;

import com.jme3.scene.Spatial.CullHint;

import com.jme3.scene.shape.Box;



public class TestBloom extends SimpleApplication

{

public static void main(final String[] args)

{

new TestBloom().start();

}



Geometry geom;

float geomX = 320;

float geomY = 240;

Node testRoot = new Node();



@Override

public void simpleInitApp()

{

viewPort.setBackgroundColor(ColorRGBA.Brown);

flyCam.setEnabled(false);

// Create custom camera/viewport

final Camera c = new Camera(640, 480);

final ViewPort v = renderManager.createMainView(“test”, c);

v.setClearEnabled(false);

v.attachScene(testRoot);

c.setFrustum(-Float.MAX_VALUE, Float.MAX_VALUE, -320, 320, 240, -240);

c.setLocation(new Vector3f(320, 240, 0));

// Create box

final Box b = new Box(Vector3f.ZERO, 60, 60, 1);

geom = new Geometry(“Box”, b);

geom.setLocalTranslation(geomX, geomY, 0);

final Material mat = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);

mat.setColor(“Color”, ColorRGBA.Green);

geom.setMaterial(mat);

testRoot.attachChild(geom);

testRoot.setQueueBucket(Bucket.Gui);

testRoot.setCullHint(CullHint.Never);

// Now add bloom

final FilterPostProcessor fpp = new FilterPostProcessor(assetManager);

final BloomFilter bloom = new BloomFilter(GlowMode.Scene);

bloom.setDownSamplingFactor(4);

bloom.setBloomIntensity(1.2f);

fpp.addFilter(bloom);

// Comment this line to remove the bloom

v.addProcessor(fpp);

}



@Override

public void simpleUpdate(final float tpf)

{

// Move box randomly

geomX += (FastMath.rand.nextFloat() * 2f - 1f);

geomY += (FastMath.rand.nextFloat() * 2f - 1f);

geom.setLocalTranslation(geomX, geomY, 0);

// Update state

testRoot.updateLogicalState(tpf);

testRoot.updateGeometricState();

}

}[/java]

(Please run at 640x480)



This creates a viewport and puts a 64x64x1 green box on it. The SimpleApplication’s ViewPort, underneath, has a brown background color.

On each frame, the box moves randomly on the screen.

Compare the result with “v.addProcessor(fpp);” commented and non-commented.

When commented, everything works fine: We can see the brown background of the SimpleApplication’s ViewPort, and the box moves.

When non-commented, we cannot see the brown background (there is black instead), and the box leaves trails.

The background is black because th brown color is set on the main viewport.

The processor can be applied only on one viewport so even if you clear the viewport others viewport won’t display in the filter.



I’m afraid there is no easy solution to this.

You would need to somehow merge the different viewports renders into one texture.



How many viewports have you got? only 2?



maybe you could render the first viewport as an offscreen viewport and put the resulting texture on a fullscreen quad in the skybucket (so it’s always in the background) in the second viewport.

Then apply the bloom on the 2nd viewport

Ok here is a workaround to your issue

What I did is creating an offscreen preview rendered to a frame buffer.

this preview has a brown background and I added a blue cube at the center



Then in the mainviewport I add the box in the gui bucket (like in your example) and a quad in the sky bucket with a material using the offscreen buffer texture with a particular material.

Then i add the bloom filter to the main viewport

here is the result





here is the code :

main class



import com.jme3.app.SimpleApplication;

import com.jme3.material.Material;

import com.jme3.math.ColorRGBA;

import com.jme3.math.FastMath;

import com.jme3.math.Vector3f;

import com.jme3.post.FilterPostProcessor;

import com.jme3.post.filters.BloomFilter;

import com.jme3.post.filters.BloomFilter.GlowMode;

import com.jme3.renderer.ViewPort;

import com.jme3.renderer.queue.RenderQueue;

import com.jme3.renderer.queue.RenderQueue.Bucket;

import com.jme3.scene.Geometry;

import com.jme3.scene.Node;

import com.jme3.scene.Spatial;

import com.jme3.scene.Spatial.CullHint;

import com.jme3.scene.shape.Box;

import com.jme3.scene.shape.Quad;

import com.jme3.texture.FrameBuffer;

import com.jme3.texture.Image.Format;

import com.jme3.texture.Texture2D;



public class TestBloom extends SimpleApplication {



public static void main(final String[] args) {

new TestBloom().start();

}

Geometry geom;

float geomX = 320;

float geomY = 240;

Node testRoot = new Node();



@Override

public void simpleInitApp() {

// Create custom camera/viewport

final ViewPort v = renderManager.createPreView(“test”, cam);

v.setBackgroundColor(ColorRGBA.Brown);

v.setClearEnabled(true);

flyCam.setEnabled(false);



FrameBuffer fb = new FrameBuffer(640, 480, 1);

fb.setColorBuffer(Format.RGBA8);

Texture2D tex = new Texture2D(640, 480, Format.RGBA8);

fb.setColorTexture(tex);

v.setOutputFrameBuffer(fb);





Geometry geom1 = new Geometry(“Box”, new Box(Vector3f.ZERO, 1, 1, 1));

geom1.setLocalTranslation(0, 0, 0);

final Material mat1 = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);

mat1.setColor(“Color”, ColorRGBA.Blue);

geom1.setMaterial(mat1);

testRoot.attachChild(geom1);

v.attachScene(testRoot);



//Creating the background

//a full screen quad in the sky bucket with the offscren texture on it

Quad q = new Quad(1, 1);

Geometry bg = new Geometry(“bg”, q);

Material bgMaterial = new Material(assetManager, “Shaders/fixedBg/BackGround.j3md”);

bgMaterial.setTexture(“BackGroundMap”, tex);

bg.setMaterial(bgMaterial);

bg.setQueueBucket(RenderQueue.Bucket.Sky);

bg.setCullHint(Spatial.CullHint.Never);

rootNode.attachChild(bg);





// Create box

final Box b = new Box(Vector3f.ZERO, 60, 60, 1);

geom = new Geometry(“Box”, b);

geom.setLocalTranslation(geomX, geomY, 0);

final Material mat = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);

mat.setColor(“Color”, ColorRGBA.Green);

geom.setMaterial(mat);

rootNode.attachChild(geom);

geom.setQueueBucket(Bucket.Gui);

rootNode.setCullHint(CullHint.Never);

// Now add bloom

final FilterPostProcessor fpp = new FilterPostProcessor(assetManager);

final BloomFilter bloom = new BloomFilter(GlowMode.Scene);

bloom.setDownSamplingFactor(4);

bloom.setBloomIntensity(1.2f);

fpp.addFilter(bloom);

// fpp.addFilter(new ColorOverlayFilter(ColorRGBA.White));

// Comment this line to remove the bloom

viewPort.addProcessor(fpp);

}



@Override

public void simpleUpdate(final float tpf) {

// Move box randomly

geomX += (FastMath.rand.nextFloat() * 2f - 1f);

geomY += (FastMath.rand.nextFloat() * 2f - 1f);

geom.setLocalTranslation(geomX, geomY, 0);

// Update state

testRoot.updateLogicalState(tpf);

testRoot.updateGeometricState();

}

}





the background shader files

backGround.j3md



MaterialDef Gradient {



MaterialParameters {

Texture2D BackGroundMap

}



Technique {

VertexShader GLSL100: Shaders/fixedBg/BackGround.vert

FragmentShader GLSL100: Shaders/fixedBg/BackGround.frag



WorldParameters {

WorldViewProjectionMatrix

}

}



Technique FixedFunc {

}



}





BackGround.vert



uniform mat4 g_WorldViewProjectionMatrix;



attribute vec4 inPosition;

attribute vec4 inTexCoord;



varying vec2 texCoord;



void main() {

texCoord=inTexCoord.xy;

gl_Position = inPosition* 2.0 - 1.0;

}





BackGround.frag



uniform sampler2D m_BackGroundMap;



varying vec2 texCoord;



void main() {

gl_FragColor = texture2D(m_BackGroundMap,texCoord);

}

That’s an interesting way to do it, but then the bloom will be applied to the entire quad in the skybucket, right? Thus, objects in the gui viewport would all be bloomed. In the test case, I set the GlowMode to “Scene”, but ideally it should be “Objects” in order to selectively bloom objects and assign them different glow colors.

Though it would be possible to add another viewport (yeah, so that’d be 3 viewports) where bloom is not enabled, and draw it on top of everything. Then, put every object to be bloomed inside the rendered-on-a-framebuffer viewport, and put every object to not be bloomed in that top viewport However, this would prevent bloom from “leaking over” the top viewport (which is a desirable effect for bloom). It also doesn’t address the issue of specifying different bloom colors for each object on the scene. But I guess that can’t really be helped without creating one extra viewport per object, assigning it a quad on the root, and setting that quad’s bloom color. But I’m guessing this would be horribly slow, so yeah… I’ll look into another solution.

windpower said:
That's an interesting way to do it, but then the bloom will be applied to the entire quad in the skybucket, right? Thus, objects in the gui viewport would all be bloomed

hmm wait?
Wasn't it the purpose of the whole thing?

windpower said:
It also doesn't address the issue of specifying different bloom colors for each object on the scene.

As you said you can use the Object glow mode, and you even can use a Bloom filter on the offscreen viewport

I didn’t specify it in the original post, but I’d like to use GlowMode.Objects so that certain objects can be selected for glow. However, using GlowMode.Objects:

  • If we use bloom on the main ViewPort, it has no effect because BackGround.j3md has no Glow technique.
  • If we add the Glow technique to BackGround.j3md, then the whole quad gets bloomed (with glitches, it seems, as blotches of green stay on the screen); then, we can’t select which objects to glow and which not to glow
  • If we use bloom on the custom viewport instead, then using GlowMode.Objects causes it to have a black background for some reason (preventing from seeing the main viewport underneath)



    A workaround for this is to add yet another viewport (so we have 2 custom viewports), having both being rendered on a quad, and having bloom on one only.