GameStates and BloomPass

Hello again,



I'm trying to switch my game from SimplePassGame to StandardGame but is having some issues with the BloomPass. In the SimplePassGame everything works as expected but in the StandardGame I'm having something that looks like z-fighting (on the objects that should be bloomed). I hade some z-fighting between other passes before but that was because I forgot to add ZBufferStates to all rootNodes. So maybe I've forgot something else too?



The RenderPasses is handled by a BasicPassManager that is created in the GameState I'm using.



It's a lot of code so I post some parts only:



This is the stateRender in my GameState.

protected void stateRender(float tpf)
   {
      Renderer r = display.getRenderer();
      pManager.renderPasses(r);
      
      SceneMonitor.getMonitor().renderViewer(r);
   }



This is part of my GameState constructor

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

        BloomRenderPass bloomRenderPass = new BloomRenderPass(cam, 4);
        if (!bloomRenderPass.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));
            fpsNode.attachChild(t);
            */
           
           // bad luck
        } else
        {
            bloomRenderPass.setExposurePow(2.0f);
            bloomRenderPass.setBlurIntensityMultiplier(0.55f);
           
            bloomRenderPass.add(rootNode);
            bloomRenderPass.setUseCurrentScene(true); // FIXME: try with false, big perf diff?
            pManager.add(bloomRenderPass);
        }



If I disable the BloomPass then everthing is rendered fine but obviously I don't get any Bloom.

It's probably something I've missed when converting?

Thanks for helping!

Well, I made it work today by adding a ZBufferState to the fullScreenQuad in the BloomRenderPass. But should that be needed? Why is that needed when having gamestates but not in the normal SimplePassGame?



The constructor of the BloomRenderPass now looks like this:


/**
    * Creates a new bloom renderpass
    *
    * @param cam       Camera used for rendering the bloomsource
    * @param renderScale Scale of bloom texture
    */
   public BloomRenderPass(Camera cam, int renderScale) {
      DisplaySystem display = DisplaySystem.getDisplaySystem();

      resetParameters();

      //Create texture renderers and rendertextures(alternating between two not to overwrite pbuffers)
        tRenderer = display.createTextureRenderer(
                display.getWidth() / renderScale,
                display.getHeight() / renderScale,
                TextureRenderer.RENDER_TEXTURE_2D);

      if (!tRenderer.isSupported()) {
         supported = false;
         return;
      }
      tRenderer.setMultipleTargets(true);
        tRenderer.setBackgroundColor(new ColorRGBA(0.0f, 0.0f, 0.0f, 1.0f));
        tRenderer.setCamera(cam);

      mainTexture = new Texture();
      mainTexture.setWrap(Texture.WM_CLAMP_S_CLAMP_T);
      mainTexture.setFilter(Texture.FM_LINEAR);
        tRenderer.setupTexture(mainTexture);

        secondTexture = new Texture();
        secondTexture.setWrap(Texture.WM_CLAMP_S_CLAMP_T);
        secondTexture.setFilter(Texture.FM_LINEAR);
        tRenderer.setupTexture(secondTexture);

        screenTexture = new Texture();
        screenTexture.setWrap(Texture.WM_CLAMP_S_CLAMP_T);
        screenTexture.setFilter(Texture.FM_LINEAR);
        tRenderer.setupTexture(screenTexture);

      //Create extract intensity shader
      extractionShader = display.getRenderer().createGLSLShaderObjectsState();
      if(!extractionShader.isSupported()) {
         supported = false;
         return;
      } else {
         extractionShader.load(BloomRenderPass.class.getClassLoader().getResource(shaderDirectory + "bloom_extract.vert"),
               BloomRenderPass.class.getClassLoader().getResource(shaderDirectory + "bloom_extract.frag"));
         extractionShader.setEnabled(true);
            extractionShader.setUniform("RT", 0);
      }

      //Create blur shader
      blurShader = display.getRenderer().createGLSLShaderObjectsState();
      if(!blurShader.isSupported()) {
         supported = false;
         return;
      } else {
         blurShader.load(BloomRenderPass.class.getClassLoader().getResource(shaderDirectory + "bloom_blur.vert"),
               BloomRenderPass.class.getClassLoader().getResource(shaderDirectory + "bloom_blur.frag"));
         blurShader.setEnabled(true);
            blurShader.setUniform("RT", 0);
      }

      //Create final shader(basic texturing)
      finalShader = display.getRenderer().createGLSLShaderObjectsState();
      if(!finalShader.isSupported()) {
         supported = false;
         return;
      } else {
         finalShader.load(BloomRenderPass.class.getClassLoader().getResource(shaderDirectory + "bloom_final.vert"),
               BloomRenderPass.class.getClassLoader().getResource(shaderDirectory + "bloom_final.frag"));
         finalShader.setEnabled(true);
      }

      //Create fullscreen quad
      fullScreenQuad = new Quad("FullScreenQuad", display.getWidth()/4, display.getHeight()/4);
        fullScreenQuadBatch = fullScreenQuad.getBatch(0);
      fullScreenQuad.getLocalRotation().set(0, 0, 0, 1);
      fullScreenQuad.getLocalTranslation().set(display.getWidth() / 2, display.getHeight() / 2, 0);
      fullScreenQuad.getLocalScale().set(1, 1, 1);
      fullScreenQuad.setRenderQueueMode(Renderer.QUEUE_ORTHO);

      fullScreenQuad.setCullMode(SceneElement.CULL_NEVER);
      fullScreenQuad.setTextureCombineMode(TextureState.REPLACE);
      fullScreenQuad.setLightCombineMode(LightState.OFF);
       
      // my change start
      ZBufferState buf = display.getRenderer().createZBufferState();
        buf.setEnabled( true );
        buf.setFunction( ZBufferState.CF_LEQUAL );
        fullScreenQuad.setRenderState( buf );
        // my change end
      
      TextureState ts = display.getRenderer().createTextureState();
      ts.setEnabled(true);
        fullScreenQuadBatch.setRenderState(ts);

      AlphaState as = display.getRenderer().createAlphaState();
      as.setBlendEnabled(true);
      as.setSrcFunction(AlphaState.SB_ONE);
      as.setDstFunction(AlphaState.DB_ONE);
      as.setEnabled(true);
        fullScreenQuadBatch.setRenderState(as);

        fullScreenQuad.updateRenderState();
        fullScreenQuad.updateGeometricState(0.0f, true);
   }

You need a ZBufferState most of the time, in SimplePassGame, the rootNode already has a ZBufferstate.  (see BaseSimpleGame)

When you attach something to the rootNode and call updateRenderState() on it, the childs attached to this node, will inherit the renderstates from the node.

OK thanks, but I thought adding a ZBufferState to the rootNode that is sent to the BloomRenderPass should be enough. I do have a updateRenderState(). The terrain is rendered fine so it's surely inheriting the state.



Does things rendered in ortho need to have a ZBufferState?

ah now i see your problem :slight_smile:

hmm well no then it shouldn't be necessary to aff the ZBufferState i think.



Maybe someone else can shed a bit more light on the zfighting issue.

As far as I remember, the BloomRenderPass has to be created in the OpenGL thread (use GameTaskQueueManager to do this). If it isnt created in the OpenGL thread you can get ANY kind of effects ranging from nothing to an exception.



so long,

Okey thanks. but it is already created in the OpenGl thread.



I found the problem. When looking deeper in the hierarchy of the gamestate that i derived (CameraGameState) then creating mine I found this:


/**
    * Calls stateRender(float), then renders the rootNode.
    *
    * @param tpf The elapsed time since last frame.
    * @see GameState#render(float)
    * @see CameraGameState#stateRender(float)
    */
   public final void render(float tpf) {
      stateRender(tpf);
      super.render(tpf);
   }



and deeper down this:

/**
    * Draws the rootNode.
    *
    * @see GameState#render(float)
    */
   public void render(float tpf) {
      super.render(tpf);
      DisplaySystem.getDisplaySystem().getRenderer().draw(rootNode);
   }
   



So I was actually rendering the rootNode twice. That was why I needed a ZBufferState on the fullScreenQuad in the BloomRenderPass.

I thought I had looked through all derives but must have missed this. By making a new class with that derived directly from GameState I could make it work as I wanted and now I don't need that extra ZBufferState. :)