Hy there,
it seems that the parallax-mapped wall does not 'react' with a directional light.
I extended the TestFragmentProgramState class a bit so the light-states can be switched with KEY_1.
There is also a cube as a reference besides it, where the light-switches seem to work correctly.
If you zoom in and out after switching to DirectionalLight you can see another strange effect (The last two PointLights still light the parallaxed texture when zooming out, when zooming in I don't know exaclty what I see … a single light, but somehow at the wrong position).
The current LightState-Type LSType, which containing two types (TwoCirclingLights / OneDirectionalLight) is logged as an info.
Either my switching is not correctly implemented, or the parallax mapped wall does not behave correctly with DirectionalLight.
My questions are therefore:
- Is it my state-switching implementation (see toggleLightState()) which causes that problem ?
- Is DirectionalLight "supported" ?
Thank you
/*
* Copyright (c) 2003-2009 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 jmetest.renderer.state;
import java.nio.FloatBuffer;
import java.util.logging.Logger;
import com.jme.app.SimpleGame;
import com.jme.image.Texture;
import com.jme.light.PointLight;
import com.jme.light.DirectionalLight;
import com.jme.math.FastMath;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.Spatial;
import com.jme.scene.TexCoords;
import com.jme.scene.shape.Quad;
import com.jme.scene.shape.Box;
import com.jme.scene.state.*;
import com.jme.util.TextureManager;
import com.jme.util.geom.BufferUtils;
import com.jme.input.KeyBindingManager;
import com.jme.input.KeyInput;
import com.jme.bounding.BoundingBox;
/**
* Demonstrates the use of the GL_ARB_fragment_program extension in jME. Uses a parallax
* mapping technique outlined in the paper "Parallax Mapping with Offset Limiting:
* A PerPixel Approximation of Uneven Surfaces".
*
* @author Eric Woroshow
* @version $Id: TestFragmentProgramState.java 4130 2009-03-19 20:04:51Z blaine.dev $
* @modified by maxx_981 for testing a light-state switch ... which fails.
* -> it seems that the parallax-mapped wall does not react on the directional light. The light-states can be
* switched with KEY_1. If you zoom in and out after switching to DirectionalLight you can see another strange effect.
*
* Either my switching is not correctly implemented, or the parallax mapped wall does
* not behave correctly with DirectionalLight. Is it supposed to ?
*
*/
public class TestFragmentProgramStateSwitchLightState extends SimpleGame
{
private static final Logger logger = Logger.getLogger(TestFragmentProgramStateSwitchLightState.class.getName());
private final static String BRICK_TEX = "jmetest/data/images/rockwall2.jpg";
private final static String BRICK_HEIGHT = "jmetest/data/images/rockwall_height2.jpg";
private final static String BRICK_NRML = "jmetest/data/images/rockwall_normal2.jpg";
private final static String BRICK_VP = "jmetest/data/images/bump_parallax.vp";
private final static String BRICK_FP = "jmetest/data/images/bump_parallax.fp";
protected LightState[] lightStates = new LightState[LSType.values().length]; //holds the lightStates
private LSType currentLightState = LSType.OneDirectionalLight; // the currently active LightState, we start with two circling lights...
private long lastSwitchTime = 0;
private long minSwitchTimeMilllis = 1000;
/**
* The LightState Type
*/
public static enum LSType
{
TwoCirclingLights,
OneDirectionalLight;
private LightState lightState;
public void setLightState(LightState lightState)
{
this.lightState = lightState;
}
public LightState getLightState()
{
return lightState;
}
public LSType getNextLightStateType()
{
if (this.ordinal() + 1 >= LSType.values().length)
{
return values()[0];
}
else
{
return values()[this.ordinal() + 1];
}
}
}
/**
* Light positioning
*/
private float angle0 = 0.0f, angle1 = 0.0f;
/**
* Entry point for the test.
*
* @param args command line arguments; unused
*/
public static void main(String[] args)
{
TestFragmentProgramStateSwitchLightState app = new TestFragmentProgramStateSwitchLightState();
app.setConfigShowMode(ConfigShowMode.AlwaysShow);
app.start();
}
private void initLightStates()
{
{
// initialize directional light
DirectionalLight dr = new DirectionalLight();
dr.setAmbient(new ColorRGBA(0.8f, 0.8f, 0.8f, 1));
dr.setDiffuse(new ColorRGBA(1f, 1f, 1f, 1));
dr.setEnabled(true);
dr.setDirection(new Vector3f(-1, -1, -1));
LightState lightState = display.getRenderer().createLightState();
lightState.detachAll();
lightState.setEnabled(true);
lightState.attach(dr);
lightState.setGlobalAmbient(new ColorRGBA(0, 0, 0, 1));
LSType.OneDirectionalLight.setLightState(lightState);
}
{
// initialize moving lights
//Set up two lights in the scene
PointLight light0 = new PointLight();
light0.setDiffuse(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
light0.setLocation(new Vector3f(2f, 4f, 1f));
light0.setEnabled(true);
PointLight light1 = new PointLight();
light1.setDiffuse(new ColorRGBA(1.0f, 0.5f, 0.0f, 1.0f));
light1.setLocation(new Vector3f(2f, 2f, 1f));
light1.setEnabled(true);
LightState lightState = display.getRenderer().createLightState();
lightState.detachAll();
lightState.setEnabled(true);
lightState.attach(light0);
lightState.attach(light1);
lightState.setGlobalAmbient(new ColorRGBA(0, 0, 0, 1));
LSType.TwoCirclingLights.setLightState(lightState);
}
toggleLightState();
}
private void toggleLightState()
{
// disable current state
currentLightState.getLightState().setEnabled(false);
// get the new state
currentLightState = currentLightState.getNextLightStateType();
// enable the state
currentLightState.getLightState().setEnabled(true);
// set the state on the root node
rootNode.setRenderState(currentLightState.getLightState());
// update the render state
rootNode.updateRenderState();
logger.info("Switching to Light State : " + currentLightState);
}
protected void simpleInitGame()
{
//Set up cull state
CullState cs = display.getRenderer().createCullState();
cs.setCullFace(CullState.Face.Back);
cs.setEnabled(true);
//Basic brick texture
TextureState brick = display.getRenderer().createTextureState();
Texture tex = TextureManager.loadTexture(TestFragmentProgramStateSwitchLightState.class.getClassLoader().getResource(BRICK_TEX), Texture.MinificationFilter.Trilinear, Texture.MagnificationFilter.Bilinear);
tex.setWrap(Texture.WrapMode.Repeat);
//Height map of the brick wall
Texture height = TextureManager.loadTexture(TestFragmentProgramStateSwitchLightState.class.getClassLoader().getResource(BRICK_HEIGHT), Texture.MinificationFilter.Trilinear, Texture.MagnificationFilter.Bilinear);
height.setWrap(Texture.WrapMode.Repeat);
//Normal map of the brick wall
Texture normal = TextureManager.loadTexture(TestFragmentProgramStateSwitchLightState.class.getClassLoader().getResource(BRICK_NRML), Texture.MinificationFilter.Trilinear, Texture.MagnificationFilter.Bilinear);
normal.setWrap(Texture.WrapMode.Repeat);
brick.setTexture(tex, 0);
brick.setTexture(normal, 1);
brick.setTexture(height, 2);
brick.setEnabled(true);
VertexProgramState vert = display.getRenderer().createVertexProgramState();
FragmentProgramState frag = display.getRenderer().createFragmentProgramState();
//Ensure the extensions are supported, else exit immediately
if (!vert.isSupported() || !frag.isSupported())
{
logger.severe("Your graphics card does not support vertex or fragment programs, and thus cannot run this test.");
quit();
}
//Load vertex program
vert.load(TestFragmentProgramStateSwitchLightState.class.getClassLoader().getResource(BRICK_VP));
vert.setEnabled(true);
//Load fragment program
frag.load(TestFragmentProgramStateSwitchLightState.class.getClassLoader().getResource(BRICK_FP));
frag.setEnabled(true);
Quad q = new Quad("wall", 10f, 10f);
//Set up textures
q.setRenderState(brick);
FloatBuffer tex1 = BufferUtils.createVector2Buffer(4);
for (int x = 0; x < 4; x++)
{
tex1.put(1.0f).put(0.0f);
}
q.setTextureCoords(new TexCoords(tex1), 1);
FloatBuffer tex2 = BufferUtils.createVector2Buffer(4);
for (int x = 0; x < 4; x++)
{
tex2.put(0.0f).put(1.0f);
}
q.setTextureCoords(new TexCoords(tex2), 2);
//Set up ARB programs
q.setRenderState(vert);
q.setRenderState(frag);
q.setRenderState(cs);
// initialize all the light-states
initLightStates();
// create a reference box to see the effect of the light
createReferenceBox();
initKeyBindings();
rootNode.attachChild(q);
rootNode.setCullHint(Spatial.CullHint.Never);
}
public void createReferenceBox()
{
// I create a box and attach it too my lightnode. This lets me see where my light is
Box b = new Box("Reference", new Vector3f(10f, 0f, 0f), 3f, 3f, 3f);
// Give the box bounds
b.setModelBound(new BoundingBox());
b.setRandomColors();
b.updateModelBound();
rootNode.attachChild(b);
}
private void initKeyBindings()
{
KeyBindingManager manager = KeyBindingManager.getKeyBindingManager();
manager.set("toggleLight", KeyInput.KEY_1);
}
protected void simpleUpdate()
{
KeyBindingManager manager = KeyBindingManager.getKeyBindingManager();
long curTime = System.currentTimeMillis();
if (manager.isValidCommand("toggleLight") && curTime - lastSwitchTime > minSwitchTimeMilllis)
{
toggleLightState();
lastSwitchTime = curTime;
}
switch (currentLightState)
{
case OneDirectionalLight:
{
//Nothing to do ...
break;
}
case TwoCirclingLights:
{
angle0 += 2 * tpf;
angle1 += 4 * tpf;
((PointLight) currentLightState.getLightState().get(0)).setLocation(new Vector3f(2.0f * FastMath.cos(angle0), 2.0f * FastMath.sin(angle0), 1.5f));
((PointLight) currentLightState.getLightState().get(1)).setLocation(new Vector3f(2.0f * FastMath.cos(angle1), 2.0f * FastMath.sin(angle1), 1.5f));
break;
}
}
}
}