I got TestIsland to work with StandardGame as a GameState (extends DebugGameState).
I had the same problem with transparent terrain and the water was being drawn on top of the terrain.
I was just about to give up and post my the code for help, but I try one last thing and it worked perfectly. Just needed to used the rootNode from DebugGameState, instead of creating a new rootNode.
This might not be the best way to implement it. I hope this helps with your problem.
/*
* Copyright (c) 2003-2007 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package jmetests;
import java.nio.FloatBuffer;
import java.util.concurrent.Callable;
import java.util.logging.Logger;
import java.util.prefs.Preferences;
import com.jme.image.Texture;
import com.jme.input.MouseInput;
import com.jme.math.Plane;
import com.jme.math.Vector3f;
import com.jme.renderer.Camera;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.pass.BasicPassManager;
import com.jme.renderer.pass.RenderPass;
import com.jme.scene.Node;
import com.jme.scene.PassNode;
import com.jme.scene.PassNodeState;
import com.jme.scene.SceneElement;
import com.jme.scene.Skybox;
import com.jme.scene.Spatial;
import com.jme.scene.shape.Quad;
import com.jme.scene.state.AlphaState;
import com.jme.scene.state.CullState;
import com.jme.scene.state.FogState;
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.system.PreferencesGameSettings;
import com.jme.util.TextureManager;
import com.jmex.editors.swing.settings.GameSettingsPanel;
import com.jmex.effects.water.WaterRenderPass;
import com.jmex.game.StandardGame;
import com.jmex.game.state.BasicGameState;
import com.jmex.game.state.DebugGameState;
import com.jmex.game.state.GameStateManager;
import com.jmex.terrain.TerrainPage;
import com.jmex.terrain.util.RawHeightMap;
/**
* TestIslandGameState shows multipass texturesplatting(6 passes) through usage of the
* PassNode together with jME's water effect and a skybox. A simpler version of
* the terrain without splatting is created and used for rendering into the
* reflection/refraction of the water.
*
* @author Heightmap and textures originally from Jadestone(but heavily
* downsampled)
* @author Rikard Herlitz (MrCoder)
*/
public class TestIslandGameState extends DebugGameState {
private static final Logger logger = Logger.getLogger(TestIslandGameState.class
.getName());
private StandardGame game = null;
private WaterRenderPass waterEffectRenderPass;
private Quad waterQuad;
private Spatial splatTerrain;
private Spatial reflectionTerrain;
private Skybox skybox;
private Camera cam = null;
private Node rootNode = null;
private DisplaySystem display = null;
private boolean started = false;
protected BasicPassManager pManager = null;
private float farPlane = 10000.0f;
private float textureScale = 0.07f;
private float globalSplatScale = 90.0f;
public TestIslandGameState(StandardGame game) {
super();
this.pManager = new BasicPassManager();
this.game = game;
}
public void update(float interpolation) {
super.update(interpolation);
if(!started) return;
skybox.getLocalTranslation().set(cam.getLocation());
skybox.updateGeometricState(0.0f, true);
Vector3f transVec = new Vector3f(cam.getLocation().x, waterEffectRenderPass
.getWaterHeight(), cam.getLocation().z);
setTextureCoords(0, transVec.x, -transVec.z, textureScale);
setVertexCoords(transVec.x, transVec.y, transVec.z);
}
@Override
public void render(float tpf) {
//super.render(tpf); Don't call super.render();
pManager.renderPasses(DisplaySystem.getDisplaySystem().getRenderer());
}
protected void initGame() {
display = DisplaySystem.getDisplaySystem();
pManager = new BasicPassManager();
cam = game.getCamera();
rootNode = getRootNode();// Don't create a new rootNode use the parent classes root node.
MouseInput.get().setCursorVisible(true);
setupEnvironment();
createTerrain();
createReflectionTerrain();
buildSkyBox();
rootNode.attachChild(skybox);
rootNode.attachChild(splatTerrain);
waterEffectRenderPass = new WaterRenderPass(cam, 6, false, true);
waterEffectRenderPass.setWaterPlane(new Plane(
new Vector3f(0.0f, 1.0f, 0.0f), 0.0f));
waterEffectRenderPass.setClipBias(-1.0f);
waterEffectRenderPass.setReflectionThrottle(0.0f);
waterEffectRenderPass.setRefractionThrottle(0.0f);
waterQuad = new Quad("waterQuad", 1, 1);
FloatBuffer normBuf = waterQuad.getNormalBuffer(0);
normBuf.clear();
normBuf.put(0).put(1).put(0);
normBuf.put(0).put(1).put(0);
normBuf.put(0).put(1).put(0);
normBuf.put(0).put(1).put(0);
waterEffectRenderPass.setWaterEffectOnSpatial(waterQuad);
rootNode.attachChild(waterQuad);
waterEffectRenderPass.setReflectedScene(skybox);
waterEffectRenderPass.addReflectedScene(reflectionTerrain);
waterEffectRenderPass.setSkybox(skybox);
pManager.add(waterEffectRenderPass);
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);
// } else {
// bloomRenderPass.setExposurePow(2.0f);
// bloomRenderPass.setBlurIntensityMultiplier(0.5f);
//
// bloomRenderPass.add(rootNode);
// bloomRenderPass.setUseCurrentScene(true);
// pManager.add(bloomRenderPass);
// }
// RenderPass fpsPass = new RenderPass();
// fpsPass.add(fpsNode);
// pManager.add(fpsPass);
rootNode.setCullMode(SceneElement.CULL_NEVER);
rootNode.updateRenderState();
started = true;
}
private void createTerrain() {
RawHeightMap heightMap = new RawHeightMap(TestIslandGameState.class.getClassLoader()
.getResource("jmetest/data/texture/terrain/heights.raw").getFile(),
129, RawHeightMap.FORMAT_16BITLE, false);
Vector3f terrainScale = new Vector3f(5, 0.003f, 6);
heightMap.setHeightScale(0.001f);
TerrainPage page = new TerrainPage("Terrain", 33, heightMap.getSize(),
terrainScale, heightMap.getHeightMap(), false);
page.getLocalTranslation().set(0, -9.5f, 0);
page.setDetailTexture(1, 1);
// create some interesting texturestates for splatting
TextureState ts1 = createSplatTextureState(
"jmetest/data/texture/terrain/baserock.jpg", null);
TextureState ts2 = createSplatTextureState(
"jmetest/data/texture/terrain/darkrock.jpg",
"jmetest/data/texture/terrain/darkrockalpha.png");
TextureState ts3 = createSplatTextureState(
"jmetest/data/texture/terrain/deadgrass.jpg",
"jmetest/data/texture/terrain/deadalpha.png");
TextureState ts4 = createSplatTextureState(
"jmetest/data/texture/terrain/nicegrass.jpg",
"jmetest/data/texture/terrain/grassalpha.png");
TextureState ts5 = createSplatTextureState(
"jmetest/data/texture/terrain/road.jpg",
"jmetest/data/texture/terrain/roadalpha.png");
TextureState ts6 = createLightmapTextureState("jmetest/data/texture/terrain/lightmap.jpg");
// alpha used for blending the passnodestates together
AlphaState as = display.getRenderer().createAlphaState();
as.setBlendEnabled(true);
as.setSrcFunction(AlphaState.SB_SRC_ALPHA);
as.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA);
as.setTestEnabled(true);
as.setTestFunction(AlphaState.TF_GREATER);
as.setEnabled(true);
// alpha used for blending the lightmap
AlphaState as2 = display.getRenderer().createAlphaState();
as2.setBlendEnabled(true);
as2.setSrcFunction(AlphaState.SB_DST_COLOR);
as2.setDstFunction(AlphaState.DB_SRC_COLOR);
as2.setTestEnabled(true);
as2.setTestFunction(AlphaState.TF_GREATER);
as2.setEnabled(true);
// //////////////////// PASS STUFF START
// try out a passnode to use for splatting
PassNode splattingPassNode = new PassNode("SplatPassNode");
splattingPassNode.attachChild(page);
PassNodeState passNodeState = new PassNodeState();
passNodeState.setPassState(ts1);
splattingPassNode.addPass(passNodeState);
passNodeState = new PassNodeState();
passNodeState.setPassState(ts2);
passNodeState.setPassState(as);
splattingPassNode.addPass(passNodeState);
passNodeState = new PassNodeState();
passNodeState.setPassState(ts3);
passNodeState.setPassState(as);
splattingPassNode.addPass(passNodeState);
passNodeState = new PassNodeState();
passNodeState.setPassState(ts4);
passNodeState.setPassState(as);
splattingPassNode.addPass(passNodeState);
passNodeState = new PassNodeState();
passNodeState.setPassState(ts5);
passNodeState.setPassState(as);
splattingPassNode.addPass(passNodeState);
passNodeState = new PassNodeState();
passNodeState.setPassState(ts6);
passNodeState.setPassState(as2);
splattingPassNode.addPass(passNodeState);
// //////////////////// PASS STUFF END
// lock some things to increase the performance
splattingPassNode.lockBounds();
splattingPassNode.lockTransforms();
splattingPassNode.lockShadows();
splatTerrain = splattingPassNode;
}
private void createReflectionTerrain() {
RawHeightMap heightMap = new RawHeightMap(TestIslandGameState.class.getClassLoader()
.getResource("jmetest/data/texture/terrain/heights.raw").getFile(),
129, RawHeightMap.FORMAT_16BITLE, false);
Vector3f terrainScale = new Vector3f(5, 0.003f, 6);
heightMap.setHeightScale(0.001f);
TerrainPage page = new TerrainPage("Terrain", 33, heightMap.getSize(),
terrainScale, heightMap.getHeightMap(), false);
page.getLocalTranslation().set(0, -9.5f, 0);
page.setDetailTexture(1, 1);
// create some interesting texturestates for splatting
TextureState ts1 = display.getRenderer().createTextureState();
Texture t0 = TextureManager.loadTexture(TestIslandGameState.class.getClassLoader()
.getResource("jmetest/data/texture/terrain/terrainlod.jpg"),
Texture.MM_LINEAR_LINEAR, Texture.FM_LINEAR);
t0.setWrap(Texture.WM_WRAP_S_WRAP_T);
t0.setApply(Texture.AM_MODULATE);
t0.setScale(new Vector3f(1.0f, 1.0f, 1.0f));
ts1.setTexture(t0, 0);
// //////////////////// PASS STUFF START
// try out a passnode to use for splatting
PassNode splattingPassNode = new PassNode("SplatPassNode");
splattingPassNode.attachChild(page);
PassNodeState passNodeState = new PassNodeState();
passNodeState.setPassState(ts1);
splattingPassNode.addPass(passNodeState);
// //////////////////// PASS STUFF END
// lock some things to increase the performance
splattingPassNode.lockBounds();
splattingPassNode.lockTransforms();
splattingPassNode.lockShadows();
reflectionTerrain = splattingPassNode;
initSpatial(reflectionTerrain);
}
private void setupEnvironment() {
cam.setFrustumPerspective(45.0f, (float) display.getWidth()
/ (float) display.getHeight(), 1f, farPlane);
cam.setLocation(new Vector3f(-320, 80, -270));
cam.lookAt(new Vector3f(0, 0, 0), Vector3f.UNIT_Y);
cam.update();
CullState cs = display.getRenderer().createCullState();
cs.setCullMode(CullState.CS_BACK);
rootNode.setRenderState(cs);
rootNode.setLightCombineMode(LightState.OFF);
FogState fogState = display.getRenderer().createFogState();
fogState.setDensity(1.0f);
fogState.setEnabled(true);
fogState.setColor(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
fogState.setEnd(farPlane);
fogState.setStart(farPlane / 10.0f);
fogState.setDensityFunction(FogState.DF_LINEAR);
fogState.setApplyFunction(FogState.AF_PER_VERTEX);
rootNode.setRenderState(fogState);
}
private void addAlphaSplat(TextureState ts, String alpha) {
Texture t1 = TextureManager.loadTexture(TestIslandGameState.class.getClassLoader()
.getResource(alpha), Texture.MM_LINEAR_LINEAR, Texture.FM_LINEAR);
t1.setWrap(Texture.WM_WRAP_S_WRAP_T);
t1.setApply(Texture.AM_COMBINE);
t1.setCombineFuncRGB(Texture.ACF_REPLACE);
t1.setCombineSrc0RGB(Texture.ACS_PREVIOUS);
t1.setCombineOp0RGB(Texture.ACO_SRC_COLOR);
t1.setCombineFuncAlpha(Texture.ACF_REPLACE);
ts.setTexture(t1, ts.getNumberOfSetTextures());
}
private TextureState createSplatTextureState(String texture, String alpha) {
TextureState ts = display.getRenderer().createTextureState();
Texture t0 = TextureManager.loadTexture(TestIslandGameState.class.getClassLoader()
.getResource(texture), Texture.MM_LINEAR_LINEAR, Texture.FM_LINEAR);
t0.setWrap(Texture.WM_WRAP_S_WRAP_T);
t0.setApply(Texture.AM_MODULATE);
t0.setScale(new Vector3f(globalSplatScale, globalSplatScale, 1.0f));
ts.setTexture(t0, 0);
if (alpha != null) {
addAlphaSplat(ts, alpha);
}
return ts;
}
private TextureState createLightmapTextureState(String texture) {
TextureState ts = display.getRenderer().createTextureState();
Texture t0 = TextureManager.loadTexture(TestIslandGameState.class.getClassLoader()
.getResource(texture), Texture.MM_LINEAR_LINEAR, Texture.FM_LINEAR);
t0.setWrap(Texture.WM_WRAP_S_WRAP_T);
ts.setTexture(t0, 0);
return ts;
}
private void buildSkyBox() {
skybox = new Skybox("skybox", 10, 10, 10);
String dir = "jmetest/data/skybox1/";
Texture north = TextureManager.loadTexture(TestIslandGameState.class
.getClassLoader().getResource(dir + "1.jpg"), Texture.MM_LINEAR,
Texture.FM_LINEAR);
Texture south = TextureManager.loadTexture(TestIslandGameState.class
.getClassLoader().getResource(dir + "3.jpg"), Texture.MM_LINEAR,
Texture.FM_LINEAR);
Texture east = TextureManager.loadTexture(TestIslandGameState.class.getClassLoader()
.getResource(dir + "2.jpg"), Texture.MM_LINEAR, Texture.FM_LINEAR);
Texture west = TextureManager.loadTexture(TestIslandGameState.class.getClassLoader()
.getResource(dir + "4.jpg"), Texture.MM_LINEAR, Texture.FM_LINEAR);
Texture up = TextureManager.loadTexture(TestIslandGameState.class.getClassLoader()
.getResource(dir + "6.jpg"), Texture.MM_LINEAR, Texture.FM_LINEAR);
Texture down = TextureManager.loadTexture(TestIslandGameState.class.getClassLoader()
.getResource(dir + "5.jpg"), Texture.MM_LINEAR, Texture.FM_LINEAR);
skybox.setTexture(Skybox.NORTH, north);
skybox.setTexture(Skybox.WEST, west);
skybox.setTexture(Skybox.SOUTH, south);
skybox.setTexture(Skybox.EAST, east);
skybox.setTexture(Skybox.UP, up);
skybox.setTexture(Skybox.DOWN, down);
skybox.preloadTextures();
CullState cullState = display.getRenderer().createCullState();
cullState.setCullMode(CullState.CS_NONE);
cullState.setEnabled(true);
skybox.setRenderState(cullState);
ZBufferState zState = display.getRenderer().createZBufferState();
zState.setEnabled(false);
skybox.setRenderState(zState);
FogState fs = display.getRenderer().createFogState();
fs.setEnabled(false);
skybox.setRenderState(fs);
skybox.setLightCombineMode(LightState.OFF);
skybox.setCullMode(SceneElement.CULL_NEVER);
skybox.setTextureCombineMode(TextureState.REPLACE);
skybox.updateRenderState();
skybox.lockBounds();
skybox.lockMeshes();
}
private void setVertexCoords(float x, float y, float z) {
FloatBuffer vertBuf = waterQuad.getVertexBuffer(0);
vertBuf.clear();
vertBuf.put(x - farPlane).put(y).put(z - farPlane);
vertBuf.put(x - farPlane).put(y).put(z + farPlane);
vertBuf.put(x + farPlane).put(y).put(z + farPlane);
vertBuf.put(x + farPlane).put(y).put(z - farPlane);
}
private void setTextureCoords(int buffer, float x, float y, float textureScale) {
x *= textureScale * 0.5f;
y *= textureScale * 0.5f;
textureScale = farPlane * textureScale;
FloatBuffer texBuf;
texBuf = waterQuad.getTextureBuffer(0, buffer);
texBuf.clear();
texBuf.put(x).put(textureScale + y);
texBuf.put(x).put(y);
texBuf.put(textureScale + x).put(y);
texBuf.put(textureScale + x).put(textureScale + y);
}
private void initSpatial(Spatial spatial) {
ZBufferState buf = display.getRenderer().createZBufferState();
buf.setEnabled(true);
buf.setFunction(ZBufferState.CF_LEQUAL);
spatial.setRenderState(buf);
CullState cs = display.getRenderer().createCullState();
cs.setCullMode(CullState.CS_BACK);
spatial.setRenderState(cs);
spatial.setCullMode(SceneElement.CULL_NEVER);
spatial.updateGeometricState(0.0f, true);
spatial.updateRenderState();
}
public static void main(String[] args) {
// Load user preferences
PreferencesGameSettings settings = new PreferencesGameSettings(Preferences
.userRoot().node("TestIslandGameState"));
StandardGame game = new StandardGame("Test Island", StandardGame.GameType.GRAPHICAL,
settings);
// Show settings screen
try {
if (!GameSettingsPanel.prompt(game.getSettings())) {
return;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
game.start();
final TestIslandGameState testIslandGameState = new TestIslandGameState(game);
try {
game.executeInGL(new Callable<Object>() {
public Object call() {
testIslandGameState.initGame();
// setup PassManagerGameState
GameStateManager.getInstance().attachChild(testIslandGameState);
testIslandGameState.setActive(true);
return null;
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}