Blurred 'glow' effect

I’ve been toying with a glow effect that I thought turned out rather nicely, but I was wondering if there was a faster/better way of going about it.



My process is pretty simple.  The scene is rendered once with normal objects present.  Then, all objects are rendered with a black texture save for the objects that are supposed to ‘glow’ (with no lighting of course, so the glowing parts of the texture stand out).  The bloom render pass is applied (making the glowing areas bloom slightly depending on their intensity) and that entire render pass is applied to the previous with an alpha blend.  The results end up looking like this (notice the glow even in dark areas, thats what i’m trying to accomplish):









I may end up simply clearing the color buffer, leaving the z buffer and only rendering the ‘glowing’ objects, rather than re-rendering the entire scene again…



Any comments and questions are welcomed, and any ideas on possibly making this process better would be appreciated.

first of all, very nice!



second, i dont know if this will work, but for an easier way, i think u can just turn off the light combine mode on the objects that glow and apply the blooming render pass to them. so the lighting really doesnt affect how shiny they r.  :smiley:

Hmm, that's an interesting idea.  It would give different results, but it might actually look pretty cool.



Is there a way to change the texture for a specific render pass?  Right now i have to have two versions of the object and apply one to the root scene node and one to the BloomRenderPass.  I have to update both of them with the same translation, rotation etc… and that's a little cumbersome (and i'm sure having two copies of the model doesn't help either).



Any suggestions?

You can use the Pass's setRenderState method to enforce a different texture state for a given pass… but it would be global.  You could also use PassNode instead to target a specific object.

In either case, would I be able to 'share' a scene? Lets say I want to draw a scene once, then render the entire scene where a few of the objects have glow textures.  I don't mind having to manually code in which objects have what glow textures, but can i use the same objects somehow, in order to avoid having two identical copies of the scene to manage?

Would you mind sharing the code for this? I am trying to learn how to accomplish bloom and do not understand how you can do it on one object but not another. My goal is to make an orb which appears as if light is coming from inside of it. Is this possible while keeping any of the other objects in the scene normal?

Sorry for the late reply.  Of course, I would be glad to share my code, though it's not really that good.  I'm still trying to find a way to change the texture of an object for a particular renderPass.  If I could do that, then this would be a piece of cake.  Right now, my technique is as follows:

  1. Create two nodes, one for the bloom pass and one for the regular render.
  2. Set the bloom pass node’s texture to the glow texture (light areas are glowy, dark areas not so much) like this:




  3. Set the regular renderPass node’s texture to the regular texture, like so:





    Then, make sure you got the correct alpha blending for the bloom pass, and render away!



    Here’s some code to play with.  Any constructive criticism is appreciated and welcomed-- I really need a better way to do this.


import com.jme.app.BaseGame;
import com.jme.bounding.BoundingBox;
import com.jme.image.Texture;
import com.jme.input.KeyBindingManager;
import com.jme.input.KeyInput;
import com.jme.light.DirectionalLight;
import com.jme.light.LightNode;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.renderer.Camera;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.renderer.pass.BasicPassManager;
import com.jme.renderer.pass.RenderPass;
import com.jme.scene.Node;
import com.jme.scene.Text;
import com.jme.scene.shape.Box;
import com.jme.scene.state.AlphaState;
import com.jme.scene.state.CullState;
import com.jme.scene.state.LightState;
import com.jme.scene.state.TextureState;
import com.jme.system.DisplaySystem;
import com.jme.system.JmeException;
import com.jme.util.TextureManager;
import com.jme.util.Timer;
import com.jmex.effects.glsl.BloomRenderPass;

public class GlowScene extends BaseGame {
   
   private int width, height, depth, freq;
   
      private boolean fullscreen;
      
      private Camera cam;
      
      private Node scene, gScene;
      
      protected Timer timer;
      
      float rot = 0;
      
      Quaternion rotation = new Quaternion();
      
   private TextureState ts;
   private TextureState ts2;
   
   float tpf;
   
    private BloomRenderPass bloomPass = null;
   
   protected BasicPassManager pManager;
      
   public static void main(String[] args) {
      GlowScene app = new GlowScene();
      app.setDialogBehaviour(ALWAYS_SHOW_PROPS_DIALOG, GlowScene.class.getClassLoader()
                .getResource("data/theproject.jpg"));
      app.start();
   }
 
   protected void update(float interpolation) {

      timer.update();
      interpolation = timer.getTimePerFrame();

      tpf = timer.getTimePerFrame();
     
      if (KeyBindingManager.getKeyBindingManager().isValidCommand("exit")) {
         finished = true;
      }
       if ( KeyBindingManager.getKeyBindingManager().isValidCommand(
               "screen_shot", false ) ) {
           display.getRenderer().takeScreenShot( "SimpleGameScreenShot" );
       }
      pManager.updatePasses(tpf);
   }
 
   protected void render(float interpolation) {

      Renderer r = display.getRenderer();
      r.clearBuffers();
     
      rotation = rotation.fromAngleAxis(rot, new Vector3f(0.25f,1,0.5f));
      scene.setLocalRotation(rotation);
      gScene.setLocalRotation(rotation);
      rot += 0.001f;
      if(rot > Math.PI * 2)
         rot = 0;
      scene.updateGeometricState(tpf, true);
      gScene.updateGeometricState(tpf, true);
     
      pManager.renderPasses(r);
   }
 
   protected void initSystem() {
      width = properties.getWidth();
      height = properties.getHeight();
      depth = properties.getDepth();
      freq = properties.getFreq();
      fullscreen = properties.getFullscreen();
      
      pManager = new BasicPassManager();
      
      try {
         display = DisplaySystem.getDisplaySystem(properties.getRenderer());
         display.createWindow(width, height, depth, freq, fullscreen);
 
         cam = display.getRenderer().createCamera(width, height);
      } catch (JmeException e) {
         e.printStackTrace();
         System.exit(1);
      }
 
      display.getRenderer().setBackgroundColor(ColorRGBA.black);
      
      cam.setFrustumPerspective(45.0f, (float)width / (float)height, 1, 1000);
      Vector3f loc = new Vector3f(0.0f, 45.0f, 90.0f);
      Vector3f left = new Vector3f(-1.0f, 0.0f, 0.0f);
      Vector3f up = new Vector3f(0.0f, 1.0f, 0.0f);
      Vector3f dir = new Vector3f(0.0f, -0.5f, -1.0f);

      cam.setFrame(loc, left, up, dir);

      cam.update();
      
        timer = Timer.getTimer();
 
      display.getRenderer().setCamera(cam);
 
      KeyBindingManager.getKeyBindingManager().set("exit",
            KeyInput.KEY_ESCAPE);
      KeyBindingManager.getKeyBindingManager().set("screen_shot",
            KeyInput.KEY_C);
      
   }
 
   protected void initGame() {
      scene = new Node("Scene graph node");
      gScene = new Node("Scene graph node");
     
      Box s = new Box("Box", new Vector3f(-25,-25,-25), new Vector3f(25,25,25));
      Box sGlow = new Box("Box2", new Vector3f(-25,-25,-25), new Vector3f(25,25,25));
      s.setModelBound(new BoundingBox());
      s.updateModelBound();

      sGlow.setModelBound(new BoundingBox());
      sGlow.updateModelBound();
     
      LightState ls = DisplaySystem.getDisplaySystem().getRenderer().createLightState();
      DirectionalLight dl = new DirectionalLight();
      dl.setDirection(new Vector3f(0.0f,-1.0f,0.5f));
      dl.setDiffuse(new ColorRGBA(0.9f, 0.9f, 0.9f, 1.0f));
      dl.setAmbient(new ColorRGBA(0.1f, 0.1f, 0.1f, 1.0f));
      dl.setEnabled(true);
      LightNode ln = new LightNode("light", ls);
      ls.setEnabled(true);
      ln.setLight(dl);
     
       CullState cs = display.getRenderer().createCullState();
       cs.setCullMode(CullState.CS_BACK);
       s.setRenderState(cs);
       sGlow.setRenderState(cs);
      
       AlphaState as = display.getRenderer().createAlphaState();
       as.setDstFunction(AlphaState.SB_ONE);
       as.setSrcFunction(AlphaState.DB_ONE);
       as.setBlendEnabled(true);
   
      ts = display.getRenderer().createTextureState();
      ts.setEnabled(true);
      ts.setTexture(TextureManager.loadTexture(GlowScene.class.getClassLoader()
               .getResource("data/ctex.jpg"),
               Texture.MM_LINEAR_LINEAR, Texture.FM_LINEAR));
     
      ts2 = display.getRenderer().createTextureState();
      ts2.setEnabled(true);
      ts2.setTexture(TextureManager.loadTexture(GlowScene.class.getClassLoader()
               .getResource("data/gtex.jpg"),
               Texture.MM_LINEAR_LINEAR, Texture.FM_LINEAR));
      s.setRenderState(ts);
      sGlow.setRenderState(ts2);
   
      scene.attachChild(s);
      gScene.attachChild(sGlow);
     
      bloomPass = new BloomRenderPass(cam, 4);
      
      bloomPass.add(sGlow);
      bloomPass.setEnabled(true);
   
      scene.updateGeometricState(0.0f, true);
      scene.setRenderState(ls);
      scene.updateRenderState();
     
      gScene.updateGeometricState(0.0f, true);
      gScene.updateRenderState();
     
      RenderPass pass1 = new RenderPass();
      pass1.add(scene);
      pManager.add(pass1);
     
      bloomPass.setBlurIntensityMultiplier(1.7f);
      bloomPass.setBlurSize(0.01f);
     
      RenderPass pass2 = new RenderPass();
      pass2.add(gScene);
      pass2.setPassState(as);
      pManager.add(pass2);
     
       if(!bloomPass.isSupported()) {
           Text t = new Text("Text", "GLSL Not supported on this computer.");
           t.setRenderQueueMode(Renderer.QUEUE_ORTHO);
           t.setLightCombineMode(LightState.OFF);
           t.setLocalTranslation(new Vector3f(0,20,0));
       } else {
          bloomPass.setUseCurrentScene(true);
           pManager.add(bloomPass);
       }
   }
   
   protected void reinit() {
      display.recreateWindow(width, height, depth, freq, fullscreen);
   }
 
   protected void cleanup() {
         ts.deleteAll();
         ts2.deleteAll();
   }
}



EDIT: be sure to disable lighting for your glow scene... otherwise it will just act like normal bloom.  With disabled lighting, the glow always effects the scene

Weird - the code crashed hard on my machine, giving:



#
# An unexpected error has been detected by Java Runtime Environment:
#
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x69243fad, pid=3288, tid=1080
#
# Java VM: Java HotSpot(TM) Client VM (10.0-b19 mixed mode, sharing windows-x86)
# Problematic frame:
# C  [atioglxx.dll+0x243fad]
#
# An error report file with more information is saved as:
# C:My WorkspaceRiseToTheStarshs_err_pid3288.log
#
# If you would like to submit a bug report, please visit:
#   http://java.sun.com/webapps/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#



Not really crucial to get this running... just letting you know :)

I am running with CVS version of jME

Mindgamer: Do you have the latest drivers? Does the regular bloom pass work for you?

Cool… new drivers fixed it :slight_smile:



I was already getting sad as I have a pretty old graphics card . Radeon 9600. But the tests ran with nice framerates with no problems



Thanks

rokkun, may you share your GlowScene example in jME Wiki as this SimplePassGame example was shared some time ago by a friend of mine?



http://www.jmonkeyengine.com/wiki/doku.php?id=simple_shadows_example



Your sample seems to be pretty good for wiki's :wink: