Volumetric Fog

a) Is this already available?



b)If not I was going to port this over from another example…this example is written using lwgl, knowing that jME uses lwgl I was wondering if there are any important points to consider in making the conversion.  Especially, as far as incorporating the needed extension is concerned.  :stuck_out_tongue:

waits for the result, whatever it will be

a) Is this already available?

No; Take plan B.

Probably needs 3D textures? These will be in jME 2.0



Though there are some approaches that don't need this (both old fashioned and probably something with fancy new shaders).

Kira said:

I was wondering if there are any important points to consider in making the conversion.  Especially, as far as incorporating the needed extension is concerned.  :P


None answered...hehe

no need for 3d texxtures...from what I've read it's really more of a blending effect?  I can't say I quite understand all of the stuff I've read about it...I get it conceptually but I don't know quite how or where to apply it.  So then I saw that opengl supported fog and figured lwgl might too...I was right...however I'm unsure of how to represent things such as glextentions in jME in a way that is compatible.

A quick explaination or even better an example would be great.  :wink:

Here are some links for those interested...

http://www.jcabs-rumblings.com/GDC2001.html (best one imho)

http://www.gamasutra.com/features/20011003/boyd_02.htm

LWJGL supports everything OpenGL does, but jME supports only a small portion. If you want to use an extension jME does not support you have to contact the devs and tell them to add it somewhere or use render-system specific code.

or write a patch to support these features!

I see…that is rather inflexible given the lack of documentation…



I need to use org.lwjgl.opengl.EXTFogCoord.



Is there a way I can reference this directly in my app?



If not can you point me towards what I need to look at in jME in order to add this functionality?



Can someone point me in the right direction 'cause going through the jME classes I really have no idea…

Sure… just make sure LWJGL is on the classpath of your own project, that's all you have to do.



For making it a jME feature you should think about how it could best be accesed in a jME way, and make a method or class or renderstate etc. for it.

I feel stupid…wasn't thinking that lwjgl wasn't in the classpath…thanks I'll post my results here soon.

I keep getting nullpointerexceptions when trying to use the static classes in lwjgl (ie. EXTFogCoord, GL11).



I'm not sure what's going on has anyone that has run in to this maybe tell…if I'm doing something wrong?





import com.jme.bounding.*;
import com.jme.math.*;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.shape.Box;
import com.jmex.terrain.TerrainBlock;
import com.jmex.terrain.util.ImageBasedHeightMap;
import com.jmex.terrain.util.ProceduralTextureGenerator;
import com.jme.util.geom.BufferUtils;
import com.jme.bounding.BoundingBox;
import com.jme.scene.state.TextureState;
import com.jme.util.TextureManager;
import com.jme.image.Texture;
import java.net.URL;
import com.jmex.editors.swing.settings.*;
import com.jmex.game.*;
import com.jmex.game.state.*;
import javax.swing.*;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.EXTFogCoord;
import java.nio.FloatBuffer;

public class Happy {

   /**
    * @param args
    */
   
   public static void main(String[] args) {
      ColorRGBA g = new ColorRGBA(0.6f, 0.3f, 0.0f, 1.0f);
      FloatBuffer fogColor = BufferUtils.createFloatBuffer(g.getColorArray());
      
      
      
      
      // TODO Auto-generated method stub
//       Instantiate StandardGame
      StandardGame game = new StandardGame("A Simple Test");
      // Show settings screen
      
         // Start StandardGame, it will block until it has initialized successfully, then return
         game.start();
         
         // Create a DebugGameState - has all the built-in features that SimpleGame provides
         // NOTE: for a distributable game implementation you'll want to use something like
         // BasicGameState instead and provide control features yourself.
         DebugGameState state = new DebugGameState();
         
         
           GL11.glEnable(GL11.GL_FOG);                     // Enable Fog
             GL11.glFogi(GL11.GL_FOG_MODE, GL11.GL_LINEAR);                  // Fog Fade Is Linear
             GL11.glFog(GL11.GL_FOG_COLOR, fogColor);               // Set The Fog Color
            GL11.glFogf(GL11.GL_FOG_START,  0.0f);                  // Set The Fog Start (Least Dense)
            GL11.glFogf(GL11.GL_FOG_END,    1.0f);                  // Set The Fog End (Most Dense)
            GL11.glHint(GL11.GL_FOG_HINT, GL11.GL_NICEST);                  // Per-Pixel Fog Calculation
            GL11.glFogi(EXTFogCoord.GL_FOG_COORDINATE_SOURCE_EXT, EXTFogCoord.GL_FOG_COORDINATE_EXT);
         
         
         // Put our box in it
         //Box box = new Box("my box", new Vector3f(0, 0, 0), 2, 2, 2);
         // box.setModelBound(new BoundingSphere());
         // box.updateModelBound();
          // We had to add the following line because the render thread is already running
          // Anytime we add content we need to updateRenderState or we get funky effects
         // box.setRandomColors();
         // box.updateRenderState();
         
/////////////////////////////////////////////////////////////////////   
//          This grayscale image will be our terrain
         URL grayscale = GameStateManager.
         class.getClassLoader(). getResource("terrain.jpg");
//          These will be the textures of our terrain.
         URL waterImage=GameStateManager.
         class.getClassLoader().
         getResource("water.jpg");
         URL dirtImage=GameStateManager.
         class.getClassLoader().
         getResource("dirt.jpg");
         URL highest=GameStateManager.
         class.getClassLoader().
         getResource("grass.jpg");
//          Create an image height map based on the gray scale of our image.
         ImageBasedHeightMap ib=new ImageBasedHeightMap(
         new ImageIcon(grayscale).getImage()
         );
//          Create a terrain block from the image's grey scale
         TerrainBlock tb=new TerrainBlock("image icon",ib.getSize(),
         new Vector3f(.5f,.05f,.5f),ib.getHeightMap(),
         new Vector3f(0,0,0),false);
//          Create an object to generate textured terrain from the
//          image based height map.
         ProceduralTextureGenerator pg=new ProceduralTextureGenerator(ib);
//          Look like water from height 0-60 with the strongest
//          "water look" at 30
         pg.addTexture(new ImageIcon(waterImage),0,30,60);
//          Look like dirt from height 40-120 with the strongest
//          "dirt look" at 80
         pg.addTexture(new ImageIcon(dirtImage),40,80,120); // Look like highest (pure white) from height 110-256
//          with the strongest "white look" at 130
         pg.addTexture(new ImageIcon(highest),110,130,256);
//          Tell pg to create a texture from the ImageIcon's it has recieved.
         pg.createTexture(256);
         TextureState ts=game.getDisplay().getRenderer().createTextureState();
//          Load the texture and assign it.
         ts.setTexture(
         TextureManager.loadTexture(
         pg.getImageIcon().getImage(),
         Texture.MM_LINEAR_LINEAR,
         Texture.FM_LINEAR,
         true
         )
         );
         tb.setRenderState(ts);
//          Give the terrain a bounding box
         tb.setModelBound(new BoundingBox());
         tb.updateModelBound();
//          Move the terrain in front of the camera
         tb.setLocalTranslation(new Vector3f(0,0,-50));
         tb.updateRenderState();
//          Attach the terrain to our rootNode.
         state.getRootNode().attachChild(tb);
         
////////////////////////////////////////////////////////////////////////////   //
         
      
      
         
          //state.getRootNode().attachChild(box);
         
         
       
         
         EXTFogCoord.glFogCoordfEXT(1.0f);
         // Add it to the manager
         GameStateManager.getInstance().attachChild(state);
         // Activate the game state
         state.setActive(true);
      

      
      
      
      

   }
   
   
   
      

   
}

   
 
   
   
   
   
   



Yes, I know the code is ugly...  :'(

Dude, you can't just put it in the beginning of the main() method!



You have to put it in the render loop, or somewhere in the draw() method of a scene object.

One way to achieve, what llama suggests is: you create your own GameState and do the GL11 stuff in the GameStates render() method.



StandardGame creates a separate OpenGL thread, because of that all calls to G11 etc. need to be executed in this OpenGL thread (this is the reason for the Nullpointerexceptons).

This is either done by using a GameStates render/update Methods or by using the GameTaskQueueManager.

Hmmm…my terrain turns orange with LoadIdentity commented out…otherwise it's as it's always been.  But no fog.



And looking at this I'n not quite sure of where jme and lwjgl separate.





import com.jme.bounding.*;
import com.jme.math.*;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.shape.Box;
import com.jmex.terrain.TerrainBlock;
import com.jmex.terrain.util.ImageBasedHeightMap;
import com.jmex.terrain.util.ProceduralTextureGenerator;
import com.jme.util.geom.BufferUtils;
import com.jme.bounding.BoundingBox;
import com.jme.scene.state.TextureState;
import com.jme.util.TextureManager;
import com.jme.image.Texture;
import java.net.URL;
import com.jmex.editors.swing.settings.*;
import com.jmex.game.*;
import com.jmex.game.state.*;
import javax.swing.*;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.EXTFogCoord;
import java.nio.FloatBuffer;
import com.jme.util.GameTaskQueueManager;
import java.util.concurrent.*;
import com.jme.util.Timer;
public class Happy {

   /**
    * @param args
    */
   
   public static void main(String[] args) {
      
      
      
      
      
      // TODO Auto-generated method stub
//       Instantiate StandardGame
      StandardGame game = new StandardGame("A Simple Test");
      // Show settings screen
      
         // Start StandardGame, it will block until it has initialized successfully, then return
         game.start();
         
         
         // Create a DebugGameState - has all the built-in features that SimpleGame provides
         // NOTE: for a distributable game implementation you'll want to use something like
         // BasicGameState instead and provide control features yourself.
         DebugGameState state = new DebugGameState();
         
         
//          Add it to the manager
         GameStateManager.getInstance().attachChild(state);
         // Activate the game state
         state.setActive(true);
            
         
         
         
            GameTaskQueueManager.getManager().render(new Callable<Object>() {
               public Object call() throws Exception {
                  GL11.glClear (GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
                  //GL11.glLoadIdentity ();                     // Reset The Modelview Matrix

                  
                  
                  ColorRGBA g = new ColorRGBA(0.6f, 0.3f, 0.0f, 1.0f);
                  FloatBuffer fogColor = BufferUtils.createFloatBuffer(g.getColorArray());
                  GL11.glEnable(GL11.GL_FOG);                     // Enable Fog
                   GL11.glFogi(GL11.GL_FOG_MODE, GL11.GL_LINEAR);                  // Fog Fade Is Linear
                   GL11.glFog(GL11.GL_FOG_COLOR, fogColor);               // Set The Fog Color
                  GL11.glFogf(GL11.GL_FOG_START,  0.0f);                  // Set The Fog Start (Least Dense)
                  GL11.glFogf(GL11.GL_FOG_END,    1.0f);                  // Set The Fog End (Most Dense)
                  GL11.glHint(GL11.GL_FOG_HINT, GL11.GL_NICEST);                  // Per-Pixel Fog Calculation
                  GL11.glFogi(EXTFogCoord.GL_FOG_COORDINATE_SOURCE_EXT, EXTFogCoord.GL_FOG_COORDINATE_EXT);
                  
                  GL11.glBegin(GL11.GL_QUADS);                     // Back Wall
                  EXTFogCoord.glFogCoordfEXT(1.0f); GL11.glTexCoord2f(0.0f, 0.0f);  GL11.glVertex3f(-2.5f,-2.5f,-15.0f);
                  EXTFogCoord.glFogCoordfEXT(1.0f); GL11.glTexCoord2f(1.0f, 0.0f); GL11.glVertex3f( 2.5f,-2.5f,-15.0f);
                  EXTFogCoord.glFogCoordfEXT(1.0f); GL11.glTexCoord2f(1.0f, 1.0f); GL11.glVertex3f( 2.5f, 2.5f,-15.0f);
                  EXTFogCoord.glFogCoordfEXT(1.0f); GL11.glTexCoord2f(0.0f, 1.0f); GL11.glVertex3f(-2.5f, 2.5f,-15.0f);
                  GL11.glEnd();
                  
                  GL11.glBegin(GL11.GL_QUADS);                     // Back Wall
                  EXTFogCoord.glFogCoordfEXT(1.0f); GL11.glTexCoord2f(0.0f, 0.0f);  GL11.glVertex3f(-2.5f,-2.5f,-15.0f);
                  EXTFogCoord.glFogCoordfEXT(1.0f); GL11.glTexCoord2f(1.0f, 0.0f); GL11.glVertex3f( 2.5f,-2.5f,-15.0f);
                  EXTFogCoord.glFogCoordfEXT(1.0f); GL11.glTexCoord2f(1.0f, 1.0f); GL11.glVertex3f( 2.5f,-2.5f, 15.0f);
                  EXTFogCoord.glFogCoordfEXT(1.0f); GL11.glTexCoord2f(0.0f, 1.0f); GL11.glVertex3f(-2.5f,-2.5f, 15.0f);
                  GL11.glEnd();
                  
                  GL11.glBegin(GL11.GL_QUADS);                     // Back Wall
                  EXTFogCoord.glFogCoordfEXT(1.0f); GL11.glTexCoord2f(0.0f, 0.0f);  GL11.glVertex3f(-2.5f, 2.5f,-15.0f);
                  EXTFogCoord.glFogCoordfEXT(1.0f); GL11.glTexCoord2f(1.0f, 0.0f); GL11.glVertex3f( 2.5f, 2.5f,-15.0f);
                  EXTFogCoord.glFogCoordfEXT(1.0f); GL11.glTexCoord2f(1.0f, 1.0f); GL11.glVertex3f( 2.5f, 2.5f, 15.0f);
                  EXTFogCoord.glFogCoordfEXT(1.0f); GL11.glTexCoord2f(0.0f, 1.0f); GL11.glVertex3f(-2.5f, 2.5f, 15.0f);
                  GL11.glEnd();
                  
                  GL11.glBegin(GL11.GL_QUADS);                     // Back Wall
                  EXTFogCoord.glFogCoordfEXT(1.0f); GL11.glTexCoord2f(0.0f, 0.0f);  GL11.glVertex3f( 2.5f,-2.5f, 15.0f);
                  EXTFogCoord.glFogCoordfEXT(1.0f); GL11.glTexCoord2f(0.0f, 1.0f); GL11.glVertex3f( 2.5f, 2.5f, 15.0f);
                  EXTFogCoord.glFogCoordfEXT(1.0f); GL11.glTexCoord2f(1.0f, 1.0f); GL11.glVertex3f( 2.5f, 2.5f,-15.0f);
                  EXTFogCoord.glFogCoordfEXT(1.0f); GL11.glTexCoord2f(1.0f, 0.0f); GL11.glVertex3f( 2.5f,-2.5f,-15.0f);
                  GL11.glEnd();
                  GL11.glFlush();
                  return null;
               }
              });
/////////////////////////////////////////////////////////////////////   
//          This grayscale image will be our terrain
         URL grayscale = GameStateManager.
         class.getClassLoader(). getResource("terrain.jpg");
//          These will be the textures of our terrain.
         URL waterImage=GameStateManager.
         class.getClassLoader().
         getResource("water.jpg");
         URL dirtImage=GameStateManager.
         class.getClassLoader().
         getResource("dirt.jpg");
         URL highest=GameStateManager.
         class.getClassLoader().
         getResource("grass.jpg");
//          Create an image height map based on the gray scale of our image.
         ImageBasedHeightMap ib=new ImageBasedHeightMap(
         new ImageIcon(grayscale).getImage()
         );
//          Create a terrain block from the image's grey scale
         TerrainBlock tb=new TerrainBlock("image icon",ib.getSize(),
         new Vector3f(.5f,.05f,.5f),ib.getHeightMap(),
         new Vector3f(0,0,0),false);
//          Create an object to generate textured terrain from the
//          image based height map.
         ProceduralTextureGenerator pg=new ProceduralTextureGenerator(ib);
//          Look like water from height 0-60 with the strongest
//          "water look" at 30
         pg.addTexture(new ImageIcon(waterImage),0,30,60);
//          Look like dirt from height 40-120 with the strongest
//          "dirt look" at 80
         pg.addTexture(new ImageIcon(dirtImage),40,80,120); // Look like highest (pure white) from height 110-256
//          with the strongest "white look" at 130
         pg.addTexture(new ImageIcon(highest),110,130,256);
//          Tell pg to create a texture from the ImageIcon's it has recieved.
         pg.createTexture(256);
         TextureState ts=game.getDisplay().getRenderer().createTextureState();
//          Load the texture and assign it.
         ts.setTexture(
         TextureManager.loadTexture(
         pg.getImageIcon().getImage(),
         Texture.MM_LINEAR_LINEAR,
         Texture.FM_LINEAR,
         true
         )
         );
         tb.setRenderState(ts);
//          Give the terrain a bounding box
         tb.setModelBound(new BoundingBox());
         tb.updateModelBound();
//          Move the terrain in front of the camera
         tb.setLocalTranslation(new Vector3f(0,0,-50));
         tb.updateRenderState();
//          Attach the terrain to our rootNode.
         state.getRootNode().attachChild(tb);
         
////////////////////////////////////////////////////////////////////////////   //
         
   }
      
}

It seems that line doesn't matter the terrain is now rendering normally…