Multi-Texturing with Transparency

Hello everyone,



I am currently taking a video game design course. We have free range on what type of game to make, language to use, genre, etc. My group and I have decided to make a 3d java game.



Some of you might be familiar with the book “Ender’s Game”. We are going to be making a game based loosely on that material.



I would like to have a spacestation arena in earth-orbit. The hull of the station would be constructed out of some sort of metal framing with “glass” as the main surface. I will be using a skybox that has space backgrounds, so I want the stars and Earth to show through these glass surfaces.



My question is how do I create a surface that has both a RGB texture (so that the framing can be seen) and an alpha texture to allow the skybox to show through?



Here are some screenshots of what I’ve been able to do so far…











Here are the textures I want to apply.



RGB:





Alpha:







I can sort of do one or the other. When I say sort of, I mean that when I set up only the alpha map, the objects in the scene blend with one another, but the image on the skybox will not show through the textures.



Here is my code thus far:

protected void simpleInitGame() {
      display.setTitle("Ender's Game");
      cam.setLocation(new Vector3f(0.0f, 10.0f, 0.0f));
      cam.update();

      createSkyBox();

      Texture glass = TextureManager.loadTexture(EndersGame.class
            .getClassLoader().getResource("textures/glass.jpg"),
            Texture.MM_LINEAR, Texture.FM_LINEAR, true);      
      Texture glassAlpha = TextureManager.loadTexture(EndersGame.class
            .getClassLoader().getResource("texture/glassAlpha.jpg"),
            Texture.MM_LINEAR, Texture.FM_LINEAR, true);      
      TextureState glassTexture = display.getRenderer().createTextureState();
      glassTexture.setTexture(glass, 0);
      glassTexture.setTexture(glassAlpha, 1);
      glassTexture.setEnabled(true);

      URL modelURL = null;
      model = new MilkshapeASCIIModel("Milkshape Model");
      modelURL = EndersGame.class.getClassLoader().getResource(
            "models/map.txt");
      model.load(modelURL, "models/");
      model.setLocalScale(.5f);
      
      // Something with an alpha state here!

      // model.setRenderState(alphaState);
      model.setRenderState(glassTexture);
      rootNode.attachChild(model);

      createLights();
   }



I realize that this is rather large question/topic, but any advice would be greatly appreciated.

typically I do this by having the rgb and aplha info all in one image and then using an alphastate. If you dig around with that and get no results let me know and I’ll look into some code for ya. There’s probably a way to do what you are saying (2 seperate image method) using stencils or something like that, but I don’t know it. :slight_smile:

The Alpha Strikes Back:



It seems that unless the alpha channel is exactly 0 on my “station” texture, none of the background (skybox) will show through. I’ve tried converting the images used in the skybox to PNGs as well, but that did not help.



I’m using the same AlphaState and ZBufferState for both my model and skybox. I have added the model to the rootnode before the skybox (although I have tried the opposite as well).



Do I need to set up something with the blending function for the textures (or textureStates) for either (or both) the model and skybox?



Here is a pic of the behavior. Notice you can see the station through the spot top spot, but not the skybox:







Here is the relevent code for the model and skybox:



protected void simpleInitGame() {
      display.setTitle("Ender's Game");
      cam.setLocation(new Vector3f(0.0f, 10.0f, 0.0f));
      cam.update();
      
      //createSound();

      TextureState ts = display.getRenderer().createTextureState();

      Texture tex = TextureManager.loadTexture("textures/glass.png",
            Texture.MM_LINEAR_LINEAR, Texture.FM_LINEAR, true);
      tex.setWrap(Texture.WM_WRAP_S_WRAP_T);

      ts.setTexture(tex, 0);

      AlphaState as1 = display.getRenderer().createAlphaState();
      as1.setBlendEnabled(true);
      as1.setSrcFunction(AlphaState.SB_SRC_ALPHA);
      as1.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA);
      as1.setTestEnabled(true);
      as1.setTestFunction(AlphaState.TF_GREATER);
      as1.setEnabled(true);

      ZBufferState normalZBuffer = display.getRenderer().createZBufferState();
      normalZBuffer.setFunction(ZBufferState.CF_LEQUAL);
      normalZBuffer.setEnabled(true);

      URL modelURL = null;
      model = new MilkshapeASCIIModel("Milkshape Model");
      modelURL = EndersGame.class.getClassLoader()
            .getResource("models/map3.txt");
      model.load(modelURL, "models/");
      model.setLocalScale(.5f);

      model.setRenderState(ts);
      model.setRenderState(as1);
      model.setRenderState(normalZBuffer);
      rootNode.attachChild(model);
      
      createSkyBox();
      m_skybox.setRenderState(as1);
      m_skybox.setRenderState(normalZBuffer);

      createLights();
   }   

   public void createSkyBox() {
      m_skybox = new Skybox("skybox", 570, 570, 570);
      Texture north = TextureManager.loadTexture(EndersGame.class
            .getClassLoader().getResource("textures/space2-small.png"),
            Texture.MM_LINEAR, Texture.FM_LINEAR, true);
      Texture south = TextureManager.loadTexture(EndersGame.class
            .getClassLoader().getResource("textures/space3-small.png"),
            Texture.MM_LINEAR, Texture.FM_LINEAR, true);
      Texture earth = TextureManager.loadTexture(EndersGame.class
            .getClassLoader().getResource("textures/earth-small.png"),
            Texture.MM_LINEAR, Texture.FM_LINEAR, true);

      m_skybox.setTexture(Skybox.NORTH, south);
      m_skybox.setTexture(Skybox.WEST, earth);
      m_skybox.setTexture(Skybox.SOUTH, south);
      m_skybox.setTexture(Skybox.EAST, north);
      m_skybox.setTexture(Skybox.UP, south);
      m_skybox.setTexture(Skybox.DOWN, south);

      rootNode.attachChild(m_skybox);
   }



Also, I do have lighting turned on at the rootnode. Any suggestions?

Just off the top of my head, but have you played around with the settings on your AlphaState?

Yes. I have experimented with numerous permutations, but none have yeilded the desired result. I must be missing something fundamental here, but I do not understand how the textures of the station will show through the transparency, but the texture of the skybox will not.



I will continue to research.

Are you making use of RenderQueue? You could have a problem with alpha sorting (RenderQueue sorts for you).



Edit: If you are using version 0.6 and not the CVS version you do not have RenderQueue.

I believe I have found the cause.



Looking through the SkyBox code, I found this…


// We don't want the light to effect our skybox
    LightState lightState = display.getRenderer().createLightState();
    lightState.setEnabled(false);
    setRenderState(lightState);
    setLightCombineMode(LightState.REPLACE);
    setTextureCombineMode(TextureState.REPLACE);

    // We don't want it making our skybox disapear, so force view
    setForceView(true);

    for (int i = 0; i < 6; i++) {
      // Make sure texture is only what is set.
      skyboxQuads[i].setTextureCombineMode(TextureState.REPLACE);

      // Make sure no lighting on the skybox
      skyboxQuads[i].setLightCombineMode(LightState.REPLACE);

      // Make sure the quad is viewable
      skyboxQuads[i].setForceView(true);

      // Set a bounding volume
      skyboxQuads[i].setModelBound(new BoundingBox());
      skyboxQuads[i].updateModelBound();


      skyboxQuads[i].setRenderQueueMode(Renderer.QUEUE_OPAQUE);
      skyboxQuads[i].setVBOVertexEnabled(true);
      skyboxQuads[i].setVBONormalEnabled(true);
      skyboxQuads[i].setVBOTextureEnabled(true);
      skyboxQuads[i].setVBOColorEnabled(true);

      // And attach the skybox as a child
      attachChild(skyboxQuads[i]);
    }



I am assuming that something to do with this texture combine mode or light combine mode is causing the behavior.

If I make a new quad and apply my same earth texture without messing with these flags, I get the correct results (note: the lighting is not correct in this picture, but I was able to correct that as well):



What do I need to disable in the skyBox code to get back to what a default quad would have? Thanks.

The default setting is INHERIT, but if it were those flags then you would have to have multitexturing or lighting on the skybox itself, which is not what is happening. Actually, that code was written before we had the OFF mode which is what it is emulating for LightState.



Something else is causing the issue, like the renderqueue usage as Mojo was mentioning. Just making a quad and throwing it in is not a valid test because you are sticking it in a different place in the scenegraph and their are other factors going on as well.

You guys were right (of course) :slight_smile:



I thought I had set up the render queue properly with this call…


display.getRenderer().getQueue().addToQueue(model,
            Renderer.QUEUE_TRANSPARENT);



When I really should have been doing this...

model.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT);



The results:

Heh, much better! :slight_smile:

Thanks for your help! jME rocks!