Obviously the whole light&shadow thing is very important. Therefore I got 3 questions about it in which I am not clear and need some explanation.
- This is a scene just put into the scenegraph with 1 DirectionalLight.
- The same scene, but now I activated Additive lighting to cast shadows. Two things are dazzling me in here:
a) Unfortunately the whole scene darkens enormously! How come that? I used a directional Light, which should be something like a sun! The light can't be that dark all out of a sudden - not that dark. In this case I would need 2 directional lights on the same position to cast an appropriate amount of brightness(the code posted below is the sample to that. Press "H" to toggle shadows)
b) I am not clear about the shadows: even if I set the Ambient Color to "black" I can't get really dark shadows. Or is this just the way it works?
- This thing confuses me most. What you see here is a cleanly modelled house in blender which I imported into the scene. In the middle of the house I put in a red light. Below the house is a box. Additive lighting/shadows is activated in the scene. What I do not understand here is: why does the box below the house receive a red light? Shouldn't it be completely dark?? There is absolutely no way that light shall shine through walls. I also tried it out with multiple boxes instead of the house
Any hints :?
import com.jme.input.InputHandler;
import com.jme.input.KeyBindingManager;
import com.jme.input.KeyInput;
import com.jme.light.DirectionalLight;
import com.jme.light.LightNode;
import com.jme.light.PointLight;
import com.jme.math.FastMath;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.renderer.pass.ShadowedRenderPass;
import com.jme.scene.Line;
import com.jme.scene.Node;
import com.jme.scene.Spatial;
import com.jme.scene.Spatial.LightCombineMode;
import com.jme.scene.shape.Box;
import com.jme.scene.shape.Quad;
import com.jme.scene.shape.Sphere;
import com.jme.app.SimpleGame;
import com.jme.bounding.BoundingBox;
import com.jme.bounding.BoundingSphere;
import com.jme.renderer.pass.BasicPassManager;
import com.jme.scene.state.BlendState;
import com.jme.scene.state.CullState;
import com.jme.scene.state.MaterialState;
import com.jme.system.DisplaySystem;
import com.jme.scene.state.BlendState;
import com.jme.scene.state.BlendState.DestinationFunction;
import com.jme.scene.state.BlendState.SourceFunction;
class TestSimpleShadoPass extends SimpleGame {
static ShadowedRenderPass sPass = new ShadowedRenderPass();
static ShadowedRenderPass sPass2 = new ShadowedRenderPass();
BasicPassManager pManager;
Node unlit;
boolean showShadows = false;
InputHandler input;
public static void main(String[] args) {
TestSimpleShadoPass app = new TestSimpleShadoPass();
app.setConfigShowMode(ConfigShowMode.NeverShow);
app.start();
}
TestSimpleShadoPass() {
stencilBits = 8;
}
public void simpleInitGame()
{
display.getRenderer().setBackgroundColor(ColorRGBA.black);
input = new InputHandler();
// A rotated quad that sits on x-z plane.
Quad floor = new Quad("Floor", 15, 15);
rootNode.attachChild(floor);
Quaternion r = new Quaternion();
r.fromAngleAxis(-FastMath.PI / 2, new Vector3f(1, 0, 0));
floor.setLocalRotation(r);
// A box and a sphere to occlude the light.
Node occluders = new Node("Occluders");
Box b = new Box("Box", new Vector3f(-2, 0, -2), new Vector3f(1, 8, 0.5f));
occluders.attachChild(b);
Sphere s = new Sphere("Sphere", 24, 24, 1.5f);
s.setLocalTranslation(new Vector3f(3, 1.5f, 0));
occluders.attachChild(s);
rootNode.attachChild(occluders);
// The light that cast shadows.
DirectionalLight dr = new DirectionalLight();
dr.setEnabled(true);
dr.setDiffuse(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
dr.setAmbient(new ColorRGBA(0f, 0f, 0f, 0.0f));
dr.setDirection(new Vector3f(-15, 20, -15).negate());
dr.setShadowCaster(true);
//Create a sphere to show where the light is in the demo.
Sphere LightSphere = new Sphere("lp", 10, 10, 1.0f);
LightSphere.setModelBound(new BoundingBox());
LightSphere.updateModelBound();
LightSphere.setLightCombineMode(Spatial.LightCombineMode.Off);//diese sollen nicht beleuchtet sein
LightSphere.setSolidColor(ColorRGBA.red);
LightSphere.setLocalTranslation(new Vector3f(20,10,10));
rootNode.attachChild(LightSphere);
//Create a new PointLight
PointLight pl = new PointLight();
pl.setDiffuse(ColorRGBA.red);
pl.setQuadratic(0.0001f);
pl.setAttenuate(true);
pl.setEnabled(true);
pl.setAmbient(new ColorRGBA(0f, 0f, 0f, 0.0f));
pl.setShadowCaster(true);
pl.setLocation(new Vector3f(20,10,10));
LightNode pln = new LightNode("pln");
pln.setLight(pl);
pln.setLocalTranslation(LightSphere.getLocalTranslation());
rootNode.attachChild(pln);
lightState.detachAll();
lightState.attach(dr);
lightState.attach(pl);
cam.setLocation(new Vector3f(0, 15, -15));
cam.lookAt(new Vector3f(0, 0, 0), new Vector3f(0, 1, 0));
rootNode.setRenderQueueMode(Renderer.QUEUE_OPAQUE);
createInput();
createUnlit();
unlit.setLightCombineMode(LightCombineMode.Off);
rootNode.attachChild(unlit);
CullState cs = DisplaySystem.getDisplaySystem().getRenderer().createCullState();
cs.setCullFace(CullState.Face.Back);
cs.setEnabled(true);
rootNode.setRenderState(cs);
// new jmetest.renderer.ShadowTweaker(sPass).setVisible(true);
sPass.add(rootNode);
sPass.addOccluder(occluders);
sPass.setRenderShadows(true);
sPass.setLightingMethod(ShadowedRenderPass.LightingMethod.Additive);
sPass.setEnabled(true);
pManager = new BasicPassManager();
pManager.add(sPass);
sPass2.add(rootNode);
sPass2.addOccluder(unlit);
sPass2.setRenderShadows(false);
sPass2.setEnabled(true);
pManager.add(sPass2);
}
@Override
public void simpleUpdate()
{
input.update(tpf);
if (KeyBindingManager.getKeyBindingManager().isValidCommand("toggleShadows", false)) {
if(!showShadows)
showShadows = true;
else
showShadows = false;
}
pManager.updatePasses(tpf);
}
@Override
public void simpleRender()
{
if(showShadows)
{
pManager.renderPasses(DisplaySystem.getDisplaySystem().getRenderer());
ShadowedRenderPass.blended.setSourceFunction(BlendState.SourceFunction.One);
ShadowedRenderPass.blended.setDestinationFunction(BlendState.DestinationFunction.One);
ShadowedRenderPass.blendTex.setSourceFunction(BlendState.SourceFunction.Zero);
ShadowedRenderPass.blendTex.setDestinationFunction(BlendState.DestinationFunction.One);
}
}
public void createInput()
{
KeyBindingManager.getKeyBindingManager().set("toggleShadows", KeyInput.KEY_H);
}
public void createUnlit()
{
unlit = new Node();
// create Grid
for (int x = -300; x <= 300; x=x+10) {
Line l = new Line("lineYGridx" + x, new Vector3f[]{new Vector3f((float) x, 0f, -300f), new Vector3f((float) x, 0f, 300f)}, null, null, null);
l.setSolidColor(ColorRGBA.darkGray);
l.setModelBound(new BoundingBox());
l.updateModelBound();
l.setCastsShadows(false);
unlit.attachChild(l);
}
for (int z = -300; z <= 300; z=z+10) {
Line l = new Line("lineYGridz" + z, new Vector3f[]{new Vector3f(-300f, 0f, (float) z), new Vector3f(300f, 0f, (float) z)}, null, null, null);
l.setSolidColor(ColorRGBA.darkGray);
l.setModelBound(new BoundingBox());
l.updateModelBound();
l.setCastsShadows(false);
unlit.attachChild(l);
}
}
}