Hi folks! Sorry to post again, but this thing is driving me frustrated… I need some help in working lighting out: I built a simple scene with lighting (> 8 lights), and must be able to save/load the scene.
The problem is: when I load the scene, everything is dark. What I expected was, that I could load the scene including the lighting. But it doesn't. What is wrong, or respectively how can I get it to work?
the 1st code is based on the TestLightStateController.java from the CVS and shows many spheres with more than 8 active lights. you can save the scene with pressing "x" (filechooser opens up).
the 2nd is a simple program to load a scene (uses filechooser at startup)
public class CopyOfTestLightStateController extends SimpleGame {
final static float worldsize = 20;//The size of the world
Node colornode;
JFileChooser fileChooser;
InputHandler input;
public static void main(String[] args) {
CopyOfTestLightStateController app = new CopyOfTestLightStateController();
app.setDialogBehaviour(ALWAYS_SHOW_PROPS_DIALOG);
app.start();
}
void randomLight(int i) {
//Chose the color for the lights.
ColorRGBA LightColor = ColorRGBA.randomColor();
//Create a sphere to show where the light is in the demo.
Sphere LightSphere = new Sphere("lp" + i, 10, 10, .1f);
LightSphere.setModelBound(new BoundingSphere());
LightSphere.updateModelBound();
LightSphere.setLightCombineMode(com.jme.scene.state.LightState.OFF);
LightSphere.setDefaultColor(LightColor);
//Create a new point light and fill out the properties
PointLight pointLight = new PointLight();
pointLight.setAttenuate(true);
pointLight.setConstant(.1f);
pointLight.setLinear(.1f);
pointLight.setQuadratic(.1f);
pointLight.setEnabled(true);
pointLight.setDiffuse(LightColor);
pointLight.setAmbient(new com.jme.renderer.ColorRGBA(.1f, .1f, .1f, .1f));
//Add the light to the world part 1:
//Add the light to the state creator.
LightControllerManager.addLight(pointLight);
//Create a node to hold the light and add a light node with this light.
Node mnod = new Node("P" + i + " Light pos");
SimpleLightNode ln = new SimpleLightNode("ln" + i, pointLight);
mnod.setLocalTranslation(new Vector3f(FastMath.rand.nextFloat()
* worldsize * 2 - worldsize, FastMath.rand.nextFloat()
* worldsize * 2 - worldsize, FastMath.rand.nextFloat()
* worldsize * 2 - worldsize));
mnod.attachChild(LightSphere);
mnod.attachChild(ln);
colornode.attachChild(mnod);
rootNode.attachChild(colornode);
}
void randomSphere(int i) {
//Crate a sphere and position it.
Sphere newSphere = new Sphere("sp" + i, 10, 10, 1);
newSphere.setModelBound(new BoundingSphere());
newSphere.updateModelBound();
newSphere.setLocalTranslation(new Vector3f(FastMath.rand.nextFloat()
* worldsize * 2 - worldsize, FastMath.rand.nextFloat()
* worldsize * 2 - worldsize, FastMath.rand.nextFloat()
* worldsize * 2 - worldsize));
//Add a new state to the controller. We do not use createLightState
// because it would require that the world bounds be updated first.
LightState ls = com.jme.system.DisplaySystem.getDisplaySystem().getRenderer().createLightState();
ls.setEnabled(true);
newSphere.setRenderState(ls);
//Create a controller to update the lighting and set the combine modes
// to REPLACE. !!All other combine modes will not work!!
LightControllerManager.addSpatial(newSphere);
newSphere.setLightCombineMode(LightState.REPLACE);
public void simpleInitGame() {
//First we remove all the lights from the lightState
this.lightState.detachAll();
// create colornode
colornode = new Node();
for (int i = 0; i < 50; i++) {
this.randomLight(i);
}
//Add the spheres.
for (int i = 0; i < 40; i++) {
this.randomSphere(i);
}
rootNode.updateRenderState();
input = new InputHandler();
InputAction keyAction = new InputAction()
{
public void performAction( InputActionEvent iae )
{
if(iae.getTriggerPressed()) // MouseButton pressed
{
if(iae.getTriggerIndex()==KeyInput.KEY_X)
{
save();
}
}
}
};
input.addAction(keyAction,InputHandler.DEVICE_ALL,InputHandler.BUTTON_ALL,InputHandler.AXIS_NONE,false);
fileChooser = new JFileChooser();
}
public class Test extends SimpleGame {
final static float worldsize = 20;//The size of the world
Node loaded;
JFileChooser fileChooser;
public static void main(String[] args) {
Test app = new Test();
app.setDialogBehaviour(ALWAYS_SHOW_PROPS_DIALOG);
app.start();
}
public void simpleInitGame() {
// clear everything first
rootNode.detachAllChildren();
lightState.detachAll();
fileChooser = new JFileChooser();
int returnVal = fileChooser.showOpenDialog(null);
if(returnVal == JFileChooser.APPROVE_OPTION)
{
/*** Read File ***/
try
{
//Select the file you want to load
loaded = (Node) BinaryImporter.getInstance().load(fileChooser.getSelectedFile());
i was debugging a bit and with the mighty SceneMonitor you see that all LightStates are disabled.
The problem is the LightControllerManager / LightManagement / LightController which controls which lights are used.
After loading the Scene, the lightList in the LightManagement is empty, and thus all LightStates get disabled.
LightManagement is implementing Savable, but its never actually saved.
The LightManagement instance is only created inside the LightControllerManager which is a Singleton and is not Savable since its not part of the Scene:)
The LightStateController which updates the lights, already gets the Manager as a reference in its constructor but its not used yet and thus not saved.
If we hold the Manager as a reference in the LightStateController and also save it, your problem should be solved.
Thanks Core-Dump, this works! Also thanks for the hint with SceneMonitor
Though I have encountered one last problem: I want to have the lights being able to pick and move around like the guy in this topic. Momoko suggested to use a LightNode and attach geometry to it. Now that I already have a SimpleLightNode I tried to extract the light itself stepwise. Every step works except extracting the light… it always returns null, as if the light isn’t there. why is that? where is the light?
//Select the file you want to load
loaded = (Node) BinaryImporter.getInstance().load(fileChooser.getSelectedFile());
// e.g. get node on a fixed position
Node node = (Node)loaded.getChild(5);
System.out.println(node); //P5 Light pos (com.jme.scene.Node)
// get element on position 0 of node
Spatial spatial = node.getChild(0);
System.out.println(spatial); //lp5 (com.jme.scene.shape.Sphere)
// get element on position 1 of node
SimpleLightNode ln = (SimpleLightNode)node.getChild(1);
System.out.println(ln); //ln5 (com.jme.light.SimpleLightNode)
// get Light from this Node
System.out.println(ln.getLight()); // null ??
Wait… what? How will you know where the light is? If you wanted, you could put something like a sphere in the same position and drag it, and when you drag the actual sphere node, it moves the light with it.
Yes, that's the way it should be. I plan to use a billboard geometry to move the lightnode around and be able to change the light properties.
The problem however is: after loading the file in Test.java I assumed that the light should still be within the SimpleLightNode because of "SimpleLightNode ln = new SimpleLightNode("ln" + i, pointLight);" and I expected an output like that:
P5 Light pos (com.jme.scene.Node)
lp5 (com.jme.scene.shape.Sphere)
ln5 (com.jme.light.SimpleLightNode)
com.jme.light.PointLight@1d9fd51 // <- it should show this, but it instead it shows "null"
So when I check if the light is at the lightnode… it's not. There is no light anymore, although the scene is still being lit by the 40 lights! So where is the light?
yeah, a reason to move towards JME2 (I also read the irc chat log my friend copied ;). Currently I use this TestManyLights as a dummy for trying out saving/loading lights in XML format (using jdom). It's quite comfortable now because the lightState contains all lights and there is a nice function to get the lights.
ArrayList<Light> arrlights = new ArrayList<Light>();
arrlights = lightState.getLightList();
… // then some loop to get the properties of each light and save them in XML
I had to delete my last post, because they were some weird errors I had to solve first. So now I figured out that lights are definitely savable in a binary way. No need to use XML. Eventually I could clean up the code a bit and I have one last question (i hope it remains the last :p):
Since I am creating all lights with LightNodes, I experienced that when I'm adding a DirectionalLight, this DirectionalLight doesn't show up. PointLight and SpotLight work flawlessly.
I considered to add a DirectionalLight and a Quad to a LightNode, and rotating the Quad would rotate the LightNode and therefore the direction of the DirectionalLight (as written in the API). But now this does not seem to work because the DirectionalLight doesn't even show up. Why is that so?
static final float worldsize = 40;//The size of the world
public static void main(String[] args) {
BinaryTest app = new BinaryTest();
app.setConfigShowMode(ConfigShowMode.NeverShow);
app.start();
}
void randomLight(int i) {
//Chose the color for the lightSphere AND the lights
ColorRGBA LightColor = ColorRGBA.randomColor();
//Create a sphere to show where the light is in the demo.
Sphere LightSphere = new Sphere("lp" + i, 10, 10, .25f);
LightSphere.setModelBound(new BoundingSphere());
LightSphere.updateModelBound();
LightSphere.setLightCombineMode(Spatial.LightCombineMode.Off);//diese sollen nicht beleuchtet sein
LightSphere.setDefaultColor(LightColor);
//Create a new point light and fill out the properties
PointLight pointLight = new PointLight();
pointLight.setDiffuse(LightColor);
pointLight.setQuadratic(0.01f);
pointLight.setAttenuate(true);
pointLight.setShadowCaster(true);
pointLight.setEnabled(true);
lightState.attach(pointLight);
//Create a node to hold the light and add a light node with this light.
LightNode ln = new LightNode("ln");
ln.setLight(pointLight);
//also attach the lightsphere to the lightnode (so it can be selected via clicking on it
ln.attachChild(LightSphere);
void randomSphere(int i) {
//Crate the big spheres and position it.
Sphere newSphere = new Sphere("sp" + i, 8, 8, 2);
newSphere.setModelBound(new BoundingSphere());
newSphere.updateModelBound();
newSphere.setLocalTranslation(new Vector3f(FastMath.rand.nextFloat()
* worldsize * 2 - worldsize, FastMath.rand.nextFloat()
* worldsize * 2 - worldsize, FastMath.rand.nextFloat()
* worldsize * 2 - worldsize));
geometrieknoten.attachChild(newSphere);
}
protected void simpleInitGame() {
//First we remove all the lights
this.lightState.detachAll();
FastMath.rand.setSeed(1520);
lichtknoten = new Node("lichtknoten");
geometrieknoten = new Node("geometrieknoten");
for (int i = 0; i < 30; i++) {
this.randomLight(i);
}
for (int i = 0; i < 60; i++) {
this.randomSphere(i);
}
//We do not want to use lighting on the spheres
LightState nl = com.jme.system.DisplaySystem.getDisplaySystem().getRenderer().createLightState();
nl.setEnabled(false);
geometrieknoten.setRenderState(nl);
I considered to add a DirectionalLight and a Quad to a LightNode, and rotating the Quad would rotate the LightNode and therefore the direction of the DirectionalLight
You mean rotating the LightNode would rotate the Quad and DirectionalLight.
If you simply add a DirectionalLight to a lightNode, and rotate the node, does it behave correctly ?
Rotating a LightNode works without a problem (at least from what I've experienced by using a SpotLight instead). The problem however in here is with the "DirectionalLight" class itself (not the SpotLight and not the PointLight): JME doesn't show the DirectionalLight I added - and thats the issue.
I abbreviated the code to show what I mean: the green PointLight works (also would a SpotLight), but the DirectionalLight (the "Sunlight") is not visible. If you delete Line 75 (lichtknoten.attachChild(drn)) the DirectionalLight is visible! But this makes no sense to me.
It would mean, that I am not allowed to put DirectionalLight into a LightNode :?
public class LightNodeTest extends SimpleGame {
static Node lichtknoten;
static Node geometrieknoten;
static final float worldsize = 40;//The size of the world
public static void main(String[] args) {
LightNodeTest app = new LightNodeTest();
app.setConfigShowMode(ConfigShowMode.NeverShow);
app.start();
}
void randomSphere(int i) {
//Crate the big spheres and position it.
Sphere newSphere = new Sphere("sp" + i, 8, 8, 2);
newSphere.setModelBound(new BoundingSphere());
newSphere.updateModelBound();
newSphere.setLocalTranslation(new Vector3f(FastMath.rand.nextFloat()
* worldsize * 2 - worldsize, FastMath.rand.nextFloat()
* worldsize * 2 - worldsize, FastMath.rand.nextFloat()
* worldsize * 2 - worldsize));
geometrieknoten.attachChild(newSphere);
}
//Create a new PointLight
PointLight pl1 = new PointLight();
pl1.setDiffuse(ColorRGBA.green);
pl1.setQuadratic(0.01f);
pl1.setAttenuate(true);
pl1.setEnabled(true);
LightNode pln = new LightNode("pln");
pln.setLight(pl1);
lichtknoten.attachChild(pln);
lightState.attach(pl1);
//Create a new DirectionalLight
DirectionalLight dr = new DirectionalLight();
dr.setEnabled(true);
dr.setDiffuse(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
dr.setAmbient(new ColorRGBA(0.2f, 0.2f, 0.2f, 1.0f));
dr.setDirection(new Vector3f(0.5f, -0.5f, 0));
dr.setShadowCaster(true);
LightNode drn = new LightNode("drn");
drn.setLight(dr);
lichtknoten.attachChild(drn);
lightState.attach(dr);