BloomRenderPass with canvas [SOLVED]

Hi,

in my program whole scene is renderd using SimpleCanvasImpl (based moste of the code on RenParticleEditor). I need to apply a BloomRenderPass to one of nodes.

To do this I modified the class that extends SimpleCanvasImpl in the following way:



private class MyImplementor extends SimpleCanvasImpl
{
   // added BasicPassManager
   protected BasicPassManager pManager;
   
   // added BloomRenderPass
   private BloomRenderPass bloomRenderPass;
   
   public void simpleSetup()
   {
      // initializing pManager in simpleSetup
      pManager = new BasicPassManager();
      
      // etc.
   }

   // calling BasicPassManager.updatePasses in doUpdate
   public void doUpdate()
   {
      super.doUpdate();
      pManager.updatePasses(tpf);
   }
   
   // calling BasicPassManager.renderPasses in simpleRender
   public void simpleRender()
   {
      pManager.renderPasses(renderer);
   }




In simpleSetup for a purpose of testing I've created a sphere and applied BloomRenderPass:


Node testNode = new Node("testNode");
testNode.attachChild(new Sphere("testSphere", new Vector3f(10, 10, 10), 10, 10, 10f));
rootNode.attachChild(testNode);

RenderPass rootPass = new RenderPass();
rootPass.add(testNode);
pManager.add(rootPass);

bloomRenderPass = new BloomRenderPass(cam, 4);

bloomRenderPass.add(testNode);
bloomRenderPass.setUseCurrentScene(true);
pManager.add(bloomRenderPass);



The effects are really bizarre - the sphere and it's bloomed representation are displaced. The more I zoom towards the sphere the closer bloomed representation is.



What am I doing wrong?

Btw: in the simpleSetup I attach lots of other nodes that should not be affected by bloom effect. Should I add rootNode to the RenderPass or should I add only the node that has to be affected by bloom?
And if I add rootNode to the RenderPass will it be rendered twice - SimpleCanvasImpl.doRender looks like this:


public void doRender() {
   renderer.clearBuffers();
        renderer.draw(rootNode);
        simpleRender();
        renderer.displayBackBuffer();
}



Perhaps all the fuss is because of my misunderstanding how RenderPasses works.

Once again thank you for your time.

new Sphere("testSphere", new Vector3f(10, 10, 10), 10, 10, 10f));



The 2nd parameter is the spheres center, usually it should be 0,0,0. Not sure if that's causing havoc.

No, changing centrer to 0,0,0 didn’t help.

If you could spare me some of your precious time than you can download the demo class from http://dl.getdropbox.com/u/296382/DemoStatePanel.java.

For your convenience I removed all the unnecessary parts of the code and left only things necessary to reproduce this behaviour. As I wrote I based my implementation on RenParticleEditor so most of the code is just a “copy/paste”. What was changed in this demo class is the Sphere in simpleSetup and stuff with BloomRenderPass in SimpleCanvasImpl.

Thank you in advance for help!

        not sure but DIsplaySystem.getDisplaySystem.getWidth() ( used by the bloom pass to get the "screen" size) returns width 640 whereas DIsplaySystem.getDisplaySystem.getRenderer().getWidth() returns 485 …



Hope this helps  :slight_smile:

kine said:

Hope this helps  :)


Indeed - this is it - if I resize the window I can see that the bloom visualisation is moving - eventually when I make the window smaller the visualisation of the sphere starts to overlap the bloom visualisation.
Kine thank you very much!

But now the question is how to solve this problem  :?

The mechanism used in RenParticleEditor to update canvas size looks like this:


// add a listener... if window is resized, we can do something about it.
glCanvas.addComponentListener(new ComponentAdapter() {
   public void componentResized(ComponentEvent ce) {
      doResize();
   }
});



protected void doResize() {
   if (impl != null) {
      impl.resizeCanvas(glCanvas.getWidth(), glCanvas.getHeight());
      if (impl.getCamera() != null) {
         Callable<Void> exe = new Callable<Void>() {
            public Void call() {
               impl.getCamera().setFrustumPerspective(45.0f, (float) glCanvas.getWidth() / (float) glCanvas.getHeight(), 1, 10000);
               return null;
            }
         };
         GameTaskQueueManager.getManager().getQueue(GameTaskQueue.RENDER).enqueue(exe);
      }
   }
}



Where the impl is the instance of the class that extends the SimpleCanvasImpl. I don't know if it's worth pasting jMe sourcecode but JMECanvasImplementor.resizeCanvas looks like this:


public void resizeCanvas(int newWidth, int newHeight) {
   final int fWidth = newWidth <= 0 ? 1 : newWidth;
   final int fHeight = newHeight <= 0 ? 1 : newHeight;
   Callable<?> exe = new Callable<Object>() {
      public Object call() {
         if (renderer != null) {
            renderer.reinit(fWidth, fHeight);
            height = fHeight;
            width = fWidth;
         }
         return null;
      }
   };
   GameTaskQueueManager.getManager().getQueue(GameTaskQueue.RENDER).enqueue(exe);
}



So the question what do I have to do update DisplaySystem width and height properly?

The best way to handle this is probably to remove the calls getWidth and getHeight from DisplaySystem as they don't really belong there. I guess a hack around this issue would be to update the DisplaySystem width/height when the reinit method is called on Renderer.

I replaced all display.getWidth()/getHeight() with display.getRenderer().getWidth()/getHeight() in BloomRenderPass and now it works perfectly!



Thank you very much for help!!!

Maybe this should be treated as a bug and fixed in jME?

when dealing with applets i was also confused that the width and height ca be get from the DisplaySystem and Renderer.



In the applets we added a resize listener, which updates the DisplaySystems values.

http://code.google.com/p/jmonkeyengine/source/browse/trunk/src/com/jmex/awt/applet/AppletResizeListener.java?r=4390

I renamed the AppletResizeListener to a ComponentResizeListener. So its usable for any component.

This new version also uses the currently set near and far frustum when resizing.





package com.jmex.awt.applet;

import java.awt.Component;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.util.concurrent.Callable;

import com.jme.system.DisplaySystem;
import com.jme.util.GameTaskQueue;
import com.jme.util.GameTaskQueueManager;

/**
 * ComponentListener for use with Applets or Canvas.<br>
 * Listens for resize events from an awt Component and reinitializes the Renderer.
 */
public class ComponentResizeListener implements ComponentListener {
   private Component component;
   
   public ComponentResizeListener(Component component) {
      this.component = component;
   }
   
   public void componentHidden(ComponentEvent ce) {

   }

   public void componentMoved(ComponentEvent ce) {

   }

   /**
    * Reinitializes the renderer based on the applets new size.<br>
    * Sets the new width and height in the displaysystem.
    */
   public void componentResized(final ComponentEvent ce) {
      Callable<?> exe = new Callable<Object>() {
         int w = component.getWidth();
         int h = component.getHeight();
         
          public Object call() {
             DisplaySystem display = DisplaySystem.getDisplaySystem();
             display.getRenderer().reinit(w, h);
             display.getRenderer().getCamera().setFrustumPerspective(45.0f,
                   (float) component.getWidth() / (float)component.getHeight(),
                   display.getRenderer().getCamera().getFrustumNear(),
                   display.getRenderer().getCamera().getFrustumFar());
             display.setWidth(w);
             display.setHeight(h);
             return null;
          }
      };
      GameTaskQueueManager.getManager()
         .getQueue(GameTaskQueue.RENDER).enqueue(exe);
   }

   public void componentShown(ComponentEvent ce) {

   }
}