Zbuffer and Alpha

Sup all,

I have a missile model that can go through buildings, it has a tail of fire (jet, thx renanse) behind it. Now I need the zBuffer to be enabled, but if I do that, the black bg of each particle will appear giving me horrible effect. If I was to disable the ZBuffer, the bg will disappear as it will have a nice jet again.



Any ideas?

Sure. Set a default disabled zbuffer state on the manager.getParticles() itself, then set your enabled one on the rootnode or wherever you need it. You’ll probably also want to force off lighting on the particles. Here’s some lines from TestFireMilk that do that:


manager.getParticles().setLightCombineMode(LightState.REPLACE);
manager.getParticles().setRenderState(display.getRenderer().getLightState());
manager.getParticles().setRenderState(display.getRenderer().getZBufferState());



By adding a default light state (disabled by default) and setting the particles to REPLACE mode for lighting, no lights will ever be combined and used on the particles no matter what lights the parents might have.

For the zbuffer we are simply saying to use that default zbuffer state (also disabled by default as all renderstates are.)

yeah, ive already done that. But the particles still show through the building:







the plane is inside the building, but the jet/fire still show through the box (its meant to be a building btw! :stuck_out_tongue: ).



Any more ideas?

Ah, ok, so instead of the default state, set up the particle’s zbuffer state to be enabled but turn off writing to the depth buffer… setWritable(false)

thx renanse, got exactly what i wanted

Hi!



I had the same problem. I enabled the particles’ ZBuffer and set writable to false. The ZBuffer of rootNode is still writeable. The particles are shown correctly. They disappear behind other objects. But now it seems that the ZBuffer of the other objects is not cleared. The first frame is rendered correctly, but if I move my character all objects are drawn at their new position and at their old position in black.



protected void initGame() {
    rootNode = new Node("rootNode");
    ZBufferState buf1 = display.getRenderer().createZBufferState();
    buf1.setFunction(ZBufferState.CF_LEQUAL);
    buf1.setEnabled(true);
    rootNode.setRenderState(buf1);
    (...)
    ParticleManager manager = new ParticleManager(300, display.getRenderer().getCamera());
    (...)
    ZBufferState buf2 = display.getRenderer().createZBufferState();
    buf2.setWritable(false);
    buf2.setEnabled(true);
    manager.getParticles().setRenderState(buf2);
    rootNode.attachChild(manager.getParticles());
    rootNode.updateGeometricState(0f, true);
    rootNode.updateRenderState();
}



Sigi

Can you explain your scene more? You show a particle system, but what else do you have in there?

Hi!



My class is very big and not structured. I decided to delete all lines that are not important to solve this problem.

I changed FixedLogicrateGame to SimpleGame. That’s it. The scene was shown correct.

Now I deleted line for line in SimpleGame and found the solution.

I have to add the following code to my original class:


Box child = new Box("dummy", new Vector3f(0, 0, 0), new Vector3f(1, 1, 1));
child.setRenderQueueMode(Renderer.QUEUE_ORTHO); // or QUEUE_TRANSPARENT
rootNode.attachChild(child);


I'm new to jME. What does this mean?

Sigi

By using the renderqueue, jME knows how to sort your scene so that items are drawn in the correct order. The Opaque queue is drawn first, then the transparent and finally the ortho. Each queue is drawn in a sorted order based on distance and other parameters.



It’s hard to say how this fixed your issue without seeing the old code, but going with SimpleGame is better for starting out in any case. Many of the basic things are handled for you.

Hi!



Here is the code:


import java.net.URL;

import com.jme.app.FixedLogicrateGame;
import com.jme.effects.ParticleManager;
import com.jme.image.Texture;
import com.jme.input.FirstPersonHandler;
import com.jme.input.InputHandler;
import com.jme.input.InputSystem;
import com.jme.input.KeyInput;
import com.jme.input.action.KeyScreenShotAction;
import com.jme.light.PointLight;
import com.jme.math.Vector3f;
import com.jme.renderer.Camera;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.scene.Node;
import com.jme.scene.shape.Box;
import com.jme.scene.shape.Quad;
import com.jme.scene.state.AlphaState;
import com.jme.scene.state.LightState;
import com.jme.scene.state.TextureState;
import com.jme.scene.state.ZBufferState;
import com.jme.system.DisplaySystem;
import com.jme.util.TextureManager;

public class TestParticleEffect extends FixedLogicrateGame {

   private InputHandler input;

   private Node rootNode;

   public static void main(String[] args) {
      TestParticleEffect app = new TestParticleEffect();
      app.setDialogBehaviour(ALWAYS_SHOW_PROPS_DIALOG);
      app.start();
   }

   protected void update(float interpolation) {
      input.update(1f / 60f);
      rootNode.updateGeometricState(1f / 60f, true);
   }

   protected void render(float percentWithinTick) {
      display.getRenderer().clearBuffers();
      display.getRenderer().draw(rootNode);
   }

   protected void initSystem() {
      display = DisplaySystem.getDisplaySystem(properties.getRenderer());
      display.createWindow(properties.getWidth(),
            properties.getHeight(),
            properties.getDepth(),
            properties.getFreq(),
            properties.getFullscreen());
      Camera cam = display.getRenderer().createCamera(display.getWidth(),
            display.getHeight());
      cam.setFrustumPerspective(45.0f, (float) display.getWidth()
            / (float) display.getHeight(), 1, 1000);
      Vector3f loc = new Vector3f(0.0f, 0.0f, 25.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, 0f, -1.0f);
      cam.setFrame(loc, left, up, dir);
      cam.update();
      display.getRenderer().setCamera(cam);
      input = new FirstPersonHandler(this, cam, properties.getRenderer());
      input.addKeyboardAction("screenshot", KeyInput.KEY_Q,
            new KeyScreenShotAction());
   }

   protected void initGame() {
      // rootNode
      rootNode = new Node("rootNode");
      ZBufferState buf = display.getRenderer().createZBufferState();
      buf.setFunction(ZBufferState.CF_LEQUAL);
      buf.setEnabled(true);
      rootNode.setRenderState(buf);

      // light
      PointLight light = new PointLight();
      light.setDiffuse(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
      light.setLocation(new Vector3f(100, 100, 100));
      light.setEnabled(true);
      LightState lightState = display.getRenderer().createLightState();
      lightState.setEnabled(true);
      lightState.attach(light);
      rootNode.setRenderState(lightState);

      // plane in the background
      Quad quad = new Quad("Quad", 50, 50);
      quad.setLocalTranslation(new Vector3f(0, 0, -50));
      rootNode.attachChild(quad);

      // box
      Box box = new Box("Box", new Vector3f(-1, -1, -1),
            new Vector3f(1, 1, 1));
      rootNode.attachChild(box);

      // particle
      AlphaState as = display.getRenderer().createAlphaState();
      as.setBlendEnabled(true);
      as.setSrcFunction(AlphaState.SB_SRC_ALPHA);
      as.setDstFunction(AlphaState.DB_ONE);
      as.setTestEnabled(true);
      as.setTestFunction(AlphaState.TF_GREATER);
      as.setEnabled(true);

      TextureState ts = display.getRenderer().createTextureState();
      URL flareURL = TestParticleEffect.class.getClassLoader().getResource(
            "textures/flaresmall.jpg");
      ts.setTexture(TextureManager.loadTexture(flareURL,
            Texture.MM_LINEAR_LINEAR, Texture.FM_LINEAR, true));
      ts.setEnabled(true);

      ParticleManager manager = new ParticleManager(300,
            display.getRenderer().getCamera());
      manager.setParticlesOrigin(new Vector3f(0f, 2f, 0f));
      manager.setGravityForce(new Vector3f(0.0f, 0.0f, 0.0f));
      manager.setEmissionDirection(new Vector3f(1.0f, 0.0f, 0.0f));
      manager.setEmissionMaximumAngle(0.0f);
      manager.setSpeed(0.2f);
      manager.setParticlesMinimumLifeTime(54.0f);
      manager.setStartSize(0.7f);
      manager.setEndSize(0.7f);
      manager.setStartColor(new ColorRGBA(1.0f, 1.0f, 0.2f, 1.0f));
      manager.setEndColor(new ColorRGBA(0.8f, 0.0f, 0.0f, 0.0f));
      manager.setRandomMod(1.0f);
      manager.setControlFlow(false);
      manager.setReleaseRate(300);
      manager.setReleaseVariance(0.0f);
      manager.setInitialVelocity(0.07f);
      manager.setParticleSpinSpeed(0.0f);
      manager.warmUp(1000);

      manager.getParticles().addController(manager);
      manager.getParticles().setRenderState(ts);
      manager.getParticles().setRenderState(as);
      manager.getParticles().setLightCombineMode(LightState.REPLACE);
      manager.getParticles().setTextureCombineMode(TextureState.REPLACE);

      buf = display.getRenderer().createZBufferState();
      buf.setWritable(false);
      buf.setEnabled(true);
      manager.getParticles().setRenderState(buf);
      rootNode.attachChild(manager.getParticles());

      // if you make this a comment the scene isn't rendered properly
      Box dummy = new Box("dummy", new Vector3f(0, 0, 0),
            new Vector3f(1, 1, 1));
      dummy.setRenderQueueMode(Renderer.QUEUE_ORTHO); // or QUEUE_TRANSPARENT
      rootNode.attachChild(dummy);

      rootNode.updateGeometricState(0f, true);
      rootNode.updateRenderState();
   }

   protected void reinit() {
   }

   protected void cleanup() {
      input.getKeyBindingManager().getKeyInput().destroy();
      InputSystem.getMouseInput().destroy();
      display.close();
   }
}


I commented the line "rootNode.attachChild(dummy);", started the game, moved a little in the scene and saved the first two screenshots.
Then I compiled the code with this line. The scene is shown correct as you can see in the third screenshot.


Sigi

Basically OpenGL has an issue with leaving the zbuffer non writeable right before displaying the back buffer. Talked this out a bit with Mojo and have put in a check and fix for this condition into the renderer and your code (even minus the dummy box) seems to work fine now. Please update from CVS to get these two fixes (Spatial and LWJGLRenderer.)