BloomRenderPass and Camera Viewports

hey there,



i am rendering a scene to one half of the screen and want to apply a Bloom to that scene.



The result is very strange (the bloom texture appears scaled into a small column on the left of the viewport)



screenshot attached and here's the testcase:


/*
 * Copyright (c) 2003-2009 jMonkeyEngine
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
 *   may be used to endorse or promote products derived from this software
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package jmetest.effects.glsl;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.prefs.Preferences;

import jmetest.renderer.loader.TestMaxJmeWrite;

import com.jme.app.BaseGame;
import com.jme.app.SimplePassGame;
import com.jme.bounding.BoundingBox;
import com.jme.image.Texture;
import com.jme.input.KeyBindingManager;
import com.jme.input.KeyInput;
import com.jme.light.PointLight;
import com.jme.math.FastMath;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.renderer.pass.RenderPass;
import com.jme.scene.Controller;
import com.jme.scene.Node;
import com.jme.scene.Text;
import com.jme.scene.Spatial.LightCombineMode;
import com.jme.scene.shape.Box;
import com.jme.scene.shape.Torus;
import com.jme.scene.state.TextureState;
import com.jme.system.AbstractGameSettings;
import com.jme.system.GameSettings;
import com.jme.system.PreferencesGameSettings;
import com.jme.system.PropertiesGameSettings;
import com.jme.util.TextureManager;
import com.jme.util.export.binary.BinaryImporter;
import com.jmex.effects.glsl.BloomRenderPass;
import com.jmex.model.converters.MaxToJme;

/**
 * Bloom effect pass test
 *
 * @author Rikard Herlitz (MrCoder)
 */
public class TestBloom extends SimplePassGame {
    private static final Logger logger = Logger.getLogger(TestBloom.class
            .getName());
   
   private BloomRenderPass bloomRenderPass;
   private int screenshotIndex = 0;

   public static void main(String[] args) {
      TestBloom app = new TestBloom();
      app.setConfigShowMode(ConfigShowMode.AlwaysShow);
      app.start();
   }

   protected void cleanup() {
      super.cleanup();
        if (bloomRenderPass != null)
            bloomRenderPass.cleanup();
   }

   protected void simpleInitGame() {
      //Setup camera
      float aspect = 2f/3f;
      cam.setFrustumPerspective(40 / aspect, aspect, 1, 1000);
      cam.setViewPort(0, 0.5f, 0, 1);
      cam.apply();
      cam.update();
      
      //Setup lights
      PointLight light = new PointLight();
      light.setDiffuse(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
      light.setAmbient(new ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f));
      light.setLocation(new Vector3f(0, 30, 0));
      light.setEnabled(true);
      lightState.attach(light);

      //Add dummy objects to rootNode
      rootNode.attachChild(createObjects());
      
      try {
            MaxToJme C1=new MaxToJme();
            ByteArrayOutputStream BO=new ByteArrayOutputStream();
            URL maxFile=TestMaxJmeWrite.class.getClassLoader().getResource("jmetest/data/model/char.3ds");
            C1.convert(new BufferedInputStream(maxFile.openStream()),BO);
            Node r = (Node)BinaryImporter.getInstance().load(new ByteArrayInputStream(BO.toByteArray()));
            r.getController(0).setRepeatType(Controller.RT_WRAP);
            r.setLocalScale(.1f);
            if (r.getChild(0).getControllers().size()!=0)
                r.getChild(0).getController(0).setSpeed(20);
            Quaternion temp=new Quaternion();
            temp.fromAngleAxis(FastMath.PI/2,new Vector3f(-1,0,0));
            r.setLocalRotation(temp);
            r.setLocalTranslation(new Vector3f(0,3,0));
            rootNode.attachChild(r);
        } catch (IOException e) {
            logger.log(Level.SEVERE, "Error loading max file", e);
        }

      //Setup renderpasses
      RenderPass rootPass = new RenderPass();
      rootPass.add(rootNode);
      pManager.add(rootPass);

      bloomRenderPass = new BloomRenderPass(cam, 4);
             
       if(!bloomRenderPass.isSupported()) {
           Text t = Text.createDefaultTextLabel("Text", "GLSL Not supported on this computer.");
           t.setRenderQueueMode(Renderer.QUEUE_ORTHO);
           t.setLightCombineMode(LightCombineMode.Off);
           t.setLocalTranslation(new Vector3f(0,20,0));
           statNode.attachChild(t);
       } else {
           bloomRenderPass.add(rootNode);
           bloomRenderPass.setUseCurrentScene(false);
           pManager.add(bloomRenderPass);
       }

      RenderPass statPass = new RenderPass();
        statPass.add(statNode);
      pManager.add(statPass);

      //Initialize keybindings
      KeyBindingManager.getKeyBindingManager().set("1", KeyInput.KEY_1);
      KeyBindingManager.getKeyBindingManager().set("2", KeyInput.KEY_2);
      KeyBindingManager.getKeyBindingManager().set("3", KeyInput.KEY_3);
      KeyBindingManager.getKeyBindingManager().set("4", KeyInput.KEY_4);
      KeyBindingManager.getKeyBindingManager().set("5", KeyInput.KEY_5);
      KeyBindingManager.getKeyBindingManager().set("6", KeyInput.KEY_6);
      KeyBindingManager.getKeyBindingManager().set("7", KeyInput.KEY_7);
      KeyBindingManager.getKeyBindingManager().set("8", KeyInput.KEY_8);
      KeyBindingManager.getKeyBindingManager().set("9", KeyInput.KEY_9);
        KeyBindingManager.getKeyBindingManager().set("0", KeyInput.KEY_0);
        KeyBindingManager.getKeyBindingManager().set("`", KeyInput.KEY_GRAVE);
        KeyBindingManager.getKeyBindingManager().set("-", KeyInput.KEY_SUBTRACT);
        KeyBindingManager.getKeyBindingManager().set("+", KeyInput.KEY_ADD);
        KeyBindingManager.getKeyBindingManager().set("separate", KeyInput.KEY_F);

      KeyBindingManager.getKeyBindingManager().set("shot", KeyInput.KEY_F4);
    }

   protected void simpleUpdate() {
      if(KeyBindingManager.getKeyBindingManager().isValidCommand("1", false)) {
         bloomRenderPass.setEnabled(!bloomRenderPass.isEnabled());
      }

      if(KeyBindingManager.getKeyBindingManager().isValidCommand("2", false)) {
         bloomRenderPass.setBlurSize(bloomRenderPass.getBlurSize() - 0.001f);
      }
      if(KeyBindingManager.getKeyBindingManager().isValidCommand("3", false)) {
         bloomRenderPass.setBlurSize(bloomRenderPass.getBlurSize() + 0.001f);
      }

      if(KeyBindingManager.getKeyBindingManager().isValidCommand("4", false)) {
         bloomRenderPass.setExposurePow(bloomRenderPass.getExposurePow() - 1.0f);
      }
      if(KeyBindingManager.getKeyBindingManager().isValidCommand("5", false)) {
         bloomRenderPass.setExposurePow(bloomRenderPass.getExposurePow() + 1.0f);
      }

      if(KeyBindingManager.getKeyBindingManager().isValidCommand("6", false)) {
         bloomRenderPass.setExposureCutoff(bloomRenderPass.getExposureCutoff() - 0.1f);
      }
      if(KeyBindingManager.getKeyBindingManager().isValidCommand("7", false)) {
         bloomRenderPass.setExposureCutoff(bloomRenderPass.getExposureCutoff() + 0.1f);
      }

      if(KeyBindingManager.getKeyBindingManager().isValidCommand("8", false)) {
         bloomRenderPass.setBlurIntensityMultiplier(bloomRenderPass.getBlurIntensityMultiplier() - 0.1f);
      }
      if(KeyBindingManager.getKeyBindingManager().isValidCommand("9", false)) {
         bloomRenderPass.setBlurIntensityMultiplier(bloomRenderPass.getBlurIntensityMultiplier() + 0.1f);
      }

        if(KeyBindingManager.getKeyBindingManager().isValidCommand("0", false)) {
            bloomRenderPass.resetParameters();
            bloomRenderPass.setUseCurrentScene(true);
            bloomRenderPass.setThrottle(1/50f);
        }

        if(KeyBindingManager.getKeyBindingManager().isValidCommand("`", false)) {
            bloomRenderPass.setUseCurrentScene(!bloomRenderPass.useCurrentScene());
        }

        if(KeyBindingManager.getKeyBindingManager().isValidCommand("-", false)) {
            float throttle = bloomRenderPass.getThrottle() - 1/200f;
            if (throttle < 0) throttle = 0;
            logger.info("throttle: "+throttle);
            bloomRenderPass.setThrottle(throttle);
        }
        if(KeyBindingManager.getKeyBindingManager().isValidCommand("+", false)) {
            float throttle = bloomRenderPass.getThrottle() + 1/200f;
            logger.info("throttle: "+throttle);
            bloomRenderPass.setThrottle(throttle);
        }

      if(KeyBindingManager.getKeyBindingManager().isValidCommand("shot", false)) {
         display.getRenderer().takeScreenShot("shot" + screenshotIndex++);
      }

        if(KeyBindingManager.getKeyBindingManager().isValidCommand("separate", false)) {
            bloomRenderPass.setUseSeparateConvolution(!bloomRenderPass.isUseSeparateConvolution());
        }
   }

   private Node createObjects() {
      Node objects = new Node("objects");

      Torus torus = new Torus("Torus", 50, 50, 10, 20);
      torus.setLocalTranslation(new Vector3f(50, -5, 20));
      TextureState ts = display.getRenderer().createTextureState();
      Texture t0 = TextureManager.loadTexture(
            TestBloom.class.getClassLoader().getResource(
                  "jmetest/data/images/Monkey.jpg"),
            Texture.MinificationFilter.Trilinear,
            Texture.MagnificationFilter.Bilinear);
      Texture t1 = TextureManager.loadTexture(
            TestBloom.class.getClassLoader().getResource(
                  "jmetest/data/texture/north.jpg"),
            Texture.MinificationFilter.Trilinear,
            Texture.MagnificationFilter.Bilinear);
      t1.setEnvironmentalMapMode(Texture.EnvironmentalMapMode.SphereMap);
      ts.setTexture(t0, 0);
      ts.setTexture(t1, 1);
      ts.setEnabled(true);
      torus.setRenderState(ts);
      objects.attachChild(torus);

      ts = display.getRenderer().createTextureState();
      t0 = TextureManager.loadTexture(
            TestBloom.class.getClassLoader().getResource(
                  "jmetest/data/texture/wall.jpg"),
            Texture.MinificationFilter.Trilinear,
            Texture.MagnificationFilter.Bilinear);
      t0.setWrap(Texture.WrapMode.Repeat);
      ts.setTexture(t0);

      Box box = new Box("box1", new Vector3f(-10, -10, -10), new Vector3f(10, 10, 10));
      box.setLocalTranslation(new Vector3f(0, -7, 0));
      box.setRenderState(ts);
      objects.attachChild(box);

      box = new Box("box2", new Vector3f(-5, -5, -5), new Vector3f(5, 5, 5));
      box.setLocalTranslation(new Vector3f(15, 10, 0));
      box.setRenderState(ts);
      objects.attachChild(box);

      box = new Box("box3", new Vector3f(-5, -5, -5), new Vector3f(5, 5, 5));
      box.setLocalTranslation(new Vector3f(0, -10, 15));
      box.setRenderState(ts);
      objects.attachChild(box);

      box = new Box("box4", new Vector3f(-5, -5, -5), new Vector3f(5, 5, 5));
      box.setLocalTranslation(new Vector3f(20, 0, 0));
      box.setRenderState(ts);
      objects.attachChild(box);

      box = new Box("box5", new Vector3f(-50, -2, -50), new Vector3f(50, 2, 50));
      box.setLocalTranslation(new Vector3f(0, -15, 0));
      box.setRenderState(ts);
      box.setModelBound(new BoundingBox());
      box.updateModelBound();
      objects.attachChild(box);

      ts = display.getRenderer().createTextureState();
      t0 = TextureManager.loadTexture(
            TestBloom.class.getClassLoader().getResource(
                  "jmetest/data/texture/cloud_land.jpg"),
            Texture.MinificationFilter.Trilinear,
            Texture.MagnificationFilter.Bilinear);
      t0.setWrap(Texture.WrapMode.Repeat);
      ts.setTexture(t0);

      box = new Box("floor", new Vector3f(-1000, -10, -1000), new Vector3f(1000, 10, 1000));
      box.setLocalTranslation(new Vector3f(0, -100, 0));
      box.setRenderState(ts);
      box.setModelBound(new BoundingBox());
      box.updateModelBound();
      objects.attachChild(box);

      return objects;
   }
}

bump

I've been trying to learn more about shaders recently, so this one piqued my interest and … well I tried and failed, but I'll share my findings here even if they are useless - just incase they inspire ideas in someone else…



I changed tRenderer.setBackgroundColor(new ColorRGBA(0.0f, 0.0f, 0.0f, 1.0f)); at line 144 in BloomRenderPass.java to tRenderer.setBackgroundColor(new ColorRGBA(0.0f, 1.0f, 0.0f, 1.0f));  so that the colour was green. This resulted in a green overlay that fitted the background image exactly (dont know if this is really relevant - it might be tho).



I changed cam.setViewPort(0, 0.5f, 0, 0.1f);  to cam.setViewPort(0, 0.75f, 0, 0.75f); to see what effect that had - and it increased the size of the bloom overlay.



I spent ages debugging and trying stuff out (changing values all over the place)… but im out of my depth and found nothing…



sorry…


This might be a hard one to fix… I believe the BloomRenderPass uses the camera's width and height values to construct the fullscreen quad as well as read back the rendered scene into a texture so that it can be bloomed.

yes it does exactly what you say,but I can't find anywhere where changing values makes any difference…

everywhere down the pipe I have found a 1.0 I have changed it to a .5 - but nothing seems to make a difference.

I have just tried this out of a personal curiosity and an attempt to be helpful tho, so finding out the true solution would  be a bonus to me too.

As far as I see, the bug is in the shaders, i played around with the values in the BloomRenderPass and nothing changes, just as JOC says. I would really appreciate a fix from someone that knows his way around shaders, because I don't  :|



plz help  :)



EDIT: This patch lets BloomRenderPass take into account the width and height of the actual camera viewports as in the example above. like that, the texture that is rendered to is created with half the width in the example.



Index: src/com/jmex/effects/glsl/BloomRenderPass.java
===================================================================
--- src/com/jmex/effects/glsl/BloomRenderPass.java   (revision 4447)
+++ src/com/jmex/effects/glsl/BloomRenderPass.java   (working copy)
@@ -70,7 +70,7 @@
 
     private Quad fullScreenQuad;
 
-   private GLSLShaderObjectsState extractionShader;
+    private GLSLShaderObjectsState extractionShader;
     private GLSLShaderObjectsState blurShader;
     private GLSLShaderObjectsState blurShaderHorizontal;
     private GLSLShaderObjectsState blurShaderVertical;
@@ -86,6 +86,8 @@
    
     private boolean useSeparateConvolution = false;
 
+    private int displayWidth, displayHeight;
+
    public static String shaderDirectory = "com/jmex/effects/glsl/data/";
 
    /**
@@ -127,13 +129,14 @@
         }
 
         DisplaySystem display = DisplaySystem.getDisplaySystem();
-
+        this.displayWidth = (int)(display.getWidth() * (cam.getViewPortRight() - cam.getViewPortLeft()));
+        this.displayHeight = (int)(display.getHeight() * (cam.getViewPortTop() - cam.getViewPortBottom()));
       resetParameters();
 
       //Create texture renderers and rendertextures(alternating between two not to overwrite pbuffers)
         tRenderer = display.createTextureRenderer(
-                display.getWidth() / renderScale,
-                display.getHeight() / renderScale,
+                displayWidth / renderScale,
+                displayHeight / renderScale,
                 TextureRenderer.Target.Texture2D);
 
       if (!tRenderer.isSupported()) {
@@ -193,9 +196,9 @@
       finalShader.setEnabled(true);
 
       //Create fullscreen quad
-      fullScreenQuad = new Quad("FullScreenQuad", display.getWidth()/4, display.getHeight()/4);
+      fullScreenQuad = new Quad("FullScreenQuad", displayWidth / 4, displayHeight / 4);
       fullScreenQuad.getLocalRotation().set(0, 0, 0, 1);
-      fullScreenQuad.getLocalTranslation().set(display.getWidth() / 2, display.getHeight() / 2, 0);
+      fullScreenQuad.getLocalTranslation().set(displayWidth / 2, displayHeight / 2, 0);
       fullScreenQuad.getLocalScale().set(1, 1, 1);
       fullScreenQuad.setRenderQueueMode(Renderer.QUEUE_ORTHO);
 
@@ -253,7 +256,7 @@
         BlendState as = (BlendState) fullScreenQuad.states[RenderState.StateType.Blend.ordinal()];
 
         if (sinceLast > throttle) {
-            sinceLast = 0;
+            sinceLast -= throttle;
 
             as.setEnabled(false);
             TextureState ts = (TextureState) fullScreenQuad.states[RenderState.StateType.Texture.ordinal()];
@@ -261,9 +264,7 @@
             // see if we should use the current scene to bloom, or only things added to the pass.
             if (useCurrentScene) {
                 // grab backbuffer to texture
-                tRenderer.copyToTexture(screenTexture,
-                        DisplaySystem.getDisplaySystem().getWidth(),
-                        DisplaySystem.getDisplaySystem().getHeight());
+                tRenderer.copyToTexture(screenTexture, displayWidth, displayHeight);
                 ts.setTexture(screenTexture, 0);
             } else {
               //Render scene to texture

Ok, I have kinda found a fix (or at least the reason) - but its not complete (gotta leave you something to do :D) and I have no idea how safe it really would be…



The problem isn't to do with the shaders at all, it's to do with the repeated render to texture stages (which is pretty much what Momoko_fan said above).

Each one of these is reducing the size of the texture by the cam viewport settings.

To get around this I found the below works. . . (as I say its not a full fix, but possibly the start of one)



In LWJGLTextureRenderer, modify the method switchCameraIn(…)


    private void switchCameraIn(boolean doClear) {
        // grab non-rtt settings
        oldCamera = parentRenderer.getCamera();
        oldWidth = parentRenderer.getWidth();
        oldHeight = parentRenderer.getHeight();
        parentRenderer.setCamera(getCamera());

// My guess is this below somehow needs to be calculated based on the camera viewport setting
        int widthx = width *2;
        
        // swap to rtt settings
        parentRenderer.getQueue().swapBuckets();
        parentRenderer.reinit(widthx, height);

        // clear the scene
        if (doClear) {
            GL11.glDisable(GL11.GL_SCISSOR_TEST);
            parentRenderer.clearBuffers();
        }

        getCamera().update();
        getCamera().apply();
    }

thx JOC for the great hint. indeed this is a quick fix, i improved the multiplicator to work for every viewport width:



the LWJGLRenderer change takes into account the viewport position so not to just use the viewport width. the LWJGLTextureRenderer change is what you suggested above JOC. the rest is as in the old patch from me above.



this works now for viewports that start at the bottom 0 and left 0, for other bottom or left it wont. take a look at the attached screenies  :wink:



Now to tackle this little problem and we're done  ;) PLZ DONT STOP NOW, I CAN SEE THE LIGHT  :wink:



EDIT: removed the changes to LWJGLRenderer



Index: src/com/jme/renderer/lwjgl/LWJGLTextureRenderer.java
===================================================================
--- src/com/jme/renderer/lwjgl/LWJGLTextureRenderer.java   (revision 4447)
+++ src/com/jme/renderer/lwjgl/LWJGLTextureRenderer.java   (working copy)
@@ -979,9 +979,13 @@
         oldHeight = parentRenderer.getHeight();
         parentRenderer.setCamera(getCamera());
 
+
+        float viewportWidthFactor = camera.getViewPortRight() - camera.getViewPortLeft();
+        float viewportHeightFactor = camera.getViewPortTop() - camera.getViewPortBottom();
+        
         // swap to rtt settings
         parentRenderer.getQueue().swapBuckets();
-        parentRenderer.reinit(width, height);
+        parentRenderer.reinit((int)(width / viewportWidthFactor), (int)(height / viewportHeightFactor));
 
         // clear the scene
         if (doClear) {
Index: src/com/jmex/effects/glsl/BloomRenderPass.java
===================================================================
--- src/com/jmex/effects/glsl/BloomRenderPass.java   (revision 4447)
+++ src/com/jmex/effects/glsl/BloomRenderPass.java   (working copy)
@@ -70,7 +70,7 @@
 
     private Quad fullScreenQuad;
 
-   private GLSLShaderObjectsState extractionShader;
+    private GLSLShaderObjectsState extractionShader;
     private GLSLShaderObjectsState blurShader;
     private GLSLShaderObjectsState blurShaderHorizontal;
     private GLSLShaderObjectsState blurShaderVertical;
@@ -86,6 +86,8 @@
    
     private boolean useSeparateConvolution = false;
 
+    private int displayWidth, displayHeight;
+
    public static String shaderDirectory = "com/jmex/effects/glsl/data/";
 
    /**
@@ -127,13 +129,14 @@
         }
 
         DisplaySystem display = DisplaySystem.getDisplaySystem();
-
+        this.displayWidth = (int)(display.getWidth() * (cam.getViewPortRight() - cam.getViewPortLeft()));
+        this.displayHeight = (int)(display.getHeight() * (cam.getViewPortTop() - cam.getViewPortBottom()));
       resetParameters();
 
       //Create texture renderers and rendertextures(alternating between two not to overwrite pbuffers)
         tRenderer = display.createTextureRenderer(
-                display.getWidth() / renderScale,
-                display.getHeight() / renderScale,
+                displayWidth / renderScale,
+                displayHeight / renderScale,
                 TextureRenderer.Target.Texture2D);
 
       if (!tRenderer.isSupported()) {
@@ -193,9 +196,9 @@
       finalShader.setEnabled(true);
 
       //Create fullscreen quad
-      fullScreenQuad = new Quad("FullScreenQuad", display.getWidth()/4, display.getHeight()/4);
+      fullScreenQuad = new Quad("FullScreenQuad", displayWidth / 4, displayHeight / 4);
       fullScreenQuad.getLocalRotation().set(0, 0, 0, 1);
-      fullScreenQuad.getLocalTranslation().set(display.getWidth() / 2, display.getHeight() / 2, 0);
+      fullScreenQuad.getLocalTranslation().set(displayWidth / 2, displayHeight / 2, 0);
       fullScreenQuad.getLocalScale().set(1, 1, 1);
       fullScreenQuad.setRenderQueueMode(Renderer.QUEUE_ORTHO);
 
@@ -253,7 +256,7 @@
         BlendState as = (BlendState) fullScreenQuad.states[RenderState.StateType.Blend.ordinal()];
 
         if (sinceLast > throttle) {
-            sinceLast = 0;
+            sinceLast -= throttle;
 
             as.setEnabled(false);
             TextureState ts = (TextureState) fullScreenQuad.states[RenderState.StateType.Texture.ordinal()];
@@ -261,9 +264,7 @@
             // see if we should use the current scene to bloom, or only things added to the pass.
             if (useCurrentScene) {
                 // grab backbuffer to texture
-                tRenderer.copyToTexture(screenTexture,
-                        DisplaySystem.getDisplaySystem().getWidth(),
-                        DisplaySystem.getDisplaySystem().getHeight());
+                tRenderer.copyToTexture(screenTexture, displayWidth, displayHeight);
                 ts.setTexture(screenTexture, 0);
             } else {
               //Render scene to texture
Index: src/jmetest/effects/glsl/TestBloom.java
===================================================================
--- src/jmetest/effects/glsl/TestBloom.java   (revision 4447)
+++ src/jmetest/effects/glsl/TestBloom.java   (working copy)
@@ -47,6 +47,7 @@
 import com.jme.image.Texture;
 import com.jme.input.KeyBindingManager;
 import com.jme.input.KeyInput;
+import com.jme.input.MouseInput;
 import com.jme.light.PointLight;
 import com.jme.math.FastMath;
 import com.jme.math.Quaternion;
@@ -63,6 +64,7 @@
 import com.jme.scene.state.TextureState;
 import com.jme.util.TextureManager;
 import com.jme.util.export.binary.BinaryImporter;
+import com.jme.util.geom.Debugger;
 import com.jmex.effects.glsl.BloomRenderPass;
 import com.jmex.model.converters.MaxToJme;
 
@@ -91,9 +93,17 @@
    }
 
    protected void simpleInitGame() {
-      //Setup camera
-      cam.setFrustumPerspective(55.0f, (float) display.getWidth() / (float) display.getHeight(), 1, 5000);
-
+       
+       MouseInput.get().setCursorVisible(true);
+       
+        //Setup camera
+//        float aspect = 2f/3f;
+//        cam.setFrustumPerspective(40 / aspect, aspect, 1, 1000);
+//        cam.setViewPort(0, 0.5f, 0, 1);
+//        cam.apply();
+//        cam.update();
+//        
+        
       //Setup lights
       PointLight light = new PointLight();
       light.setDiffuse(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));



Its the same bahavior with Bottom and Top half rendering  :|