Shadow Rendering - Additive too dark to produce shadows

Hello all,



I’m testing the Shadow renderer, and I can get okay results with the Modulative lighting method, but the contrast is a bit too high. However, when I switch to Additive lighting, the light becomes so faint that no shadows are produced. I have experimented with many variations on the diffuse and ambient lighting, the global ambient light, and even the attenuation settings in the hopes of brightening the light enough to cast a shadow in Additive mode, to no avail. (And I would prefer to continue to use a PointLight, rather than DirectionLight, to cast shadows.) I’ve searched through the forums, but I am at a loss; thus I turn to you, my fellow jMonkeyEngineers… any ideas on fixing the code below to cast nice shadows with Additive lighting?



Thanks!

Code:
import com.jme.app.SimpleGame; import com.jme.math.Vector3f; import com.jme.scene.shape.Box; import com.jme.scene.shape.Sphere; import com.jme.renderer.ColorRGBA; import com.jme.scene.state.MaterialState; import com.jme.input.*; import com.jme.scene.*; import com.jme.light.*; import com.jme.renderer.Renderer; import com.jme.renderer.pass.RenderPass; import com.jme.renderer.pass.ShadowedRenderPass; import com.jme.renderer.pass.ShadowedRenderPass.LightingMethod; import com.jme.renderer.pass.BasicPassManager;

/**

  • Shadow example.
  • @author Stemkoski
    */
    public class ShadowDemo extends SimpleGame
    {
    // a geometric shape that will be rendered
    Sphere mySphere;
    PointLight pl;
    Sphere lightBulb;
private ShadowedRenderPass shadowPass = new ShadowedRenderPass();
private BasicPassManager pManager;

public static void main(String[] args) 
{
    ShadowDemo app = new ShadowDemo();
    app.setConfigShowMode(ConfigShowMode.AlwaysShow);
    app.start();
}

protected void simpleInitGame() 
{
    stencilBits = 4;
    
    // make the standard cursor visible.
    org.lwjgl.input.Mouse.setGrabbed(false);
    // SimpleGame class defaults mouse behavior to rotate view; here we disable this.
    ((FirstPersonHandler)input).getMouseLookHandler().setEnabled(false);
    
    // reposition camera
    cam.setLocation( new Vector3f(1,1,12) );
    
    // create a material to apply to geometric objects, use objects' default color,
    //  apply to front and back, and assign rendering to root node
    MaterialState customMaterial = display.getRenderer().createMaterialState();
    customMaterial.setColorMaterial(MaterialState.ColorMaterial.AmbientAndDiffuse);
    customMaterial.setMaterialFace(MaterialState.MaterialFace.FrontAndBack);
    rootNode.setRenderState(customMaterial);
    
    mySphere = new Sphere("s", new Vector3f(0,0,0), 50, 50, 1 );
    mySphere.setSolidColor( ColorRGBA.blue );
    
    lightBulb = new Sphere("s", new Vector3f(0,0,0), 6, 6, 0.25f );
    lightBulb.setSolidColor( ColorRGBA.white );
    rootNode.attachChild(lightBulb);

    // create a floor structure
    Box floor = new Box("b", new Vector3f(-20,-2,-20), new Vector3f(20,-9.9f,20));
    floor.setSolidColor( ColorRGBA.gray );
    rootNode.attachChild( floor );

    // Another light so there is no full darkness.
    pl = new PointLight();
    pl.setEnabled(true);
    pl.setDiffuse( new ColorRGBA(0.9f, 0.9f, 0.9f, 0.0f) );
    pl.setAmbient( new ColorRGBA(0.2f, 0.2f, 0.2f, 0.6f) );
    pl.setLocation(new Vector3f(1, 5, 1));
    pl.setShadowCaster(true);
    
    lightState.detachAll();
    lightState.attach(pl);
    lightState.setGlobalAmbient(new ColorRGBA(0.3f, 0.3f, 0.3f, 0.1f));
   
    Node occluders = new Node("Occluders");
    rootNode.attachChild(occluders);
    occluders.attachChild( mySphere );

    // pass renderer setup
    pManager = new BasicPassManager();
    shadowPass.add(rootNode);
    shadowPass.addOccluder(occluders);
    shadowPass.setRenderShadows(true);
    // Modulative: contrast is too high.
    // Additive: results are too dark, resulting in no shadows
    // What to do?
    shadowPass.setLightingMethod(LightingMethod.Modulative); 
    pManager.add(shadowPass);

    // remove all pre-existing key assignments
    KeyBindingManager.getKeyBindingManager().removeAll();

    KeyBindingManager.getKeyBindingManager().set( "exit",    KeyInput.KEY_ESCAPE );
    KeyBindingManager.getKeyBindingManager().set( "toggle_wire",   KeyInput.KEY_F1 );
    KeyBindingManager.getKeyBindingManager().set( "toggle_bounds", KeyInput.KEY_F2 );
    
    KeyBindingManager.getKeyBindingManager().set( "sphereRed",   KeyInput.KEY_1 );
    KeyBindingManager.getKeyBindingManager().set( "sphereMulti",  KeyInput.KEY_2 );        
    KeyBindingManager.getKeyBindingManager().set( "+",  KeyInput.KEY_4 );        
    KeyBindingManager.getKeyBindingManager().set( "-",  KeyInput.KEY_5 ); 

    // light translation
    KeyBindingManager.getKeyBindingManager().set( "lightTranslateUp", KeyInput.KEY_I );
    KeyBindingManager.getKeyBindingManager().set( "lightTranslateDown", KeyInput.KEY_K );
    KeyBindingManager.getKeyBindingManager().set( "lightTranslateLeft", KeyInput.KEY_J );
    KeyBindingManager.getKeyBindingManager().set( "lightTranslateRight", KeyInput.KEY_L );
    KeyBindingManager.getKeyBindingManager().set( "lightTranslateForward", KeyInput.KEY_U );
    KeyBindingManager.getKeyBindingManager().set( "lightTranslateBackward", KeyInput.KEY_M );
    // node translation relative to camera
    KeyBindingManager.getKeyBindingManager().set( "nodeTranslateUp", KeyInput.KEY_W );
    KeyBindingManager.getKeyBindingManager().set( "nodeTranslateDown", KeyInput.KEY_S );
    KeyBindingManager.getKeyBindingManager().set( "nodeTranslateLeft", KeyInput.KEY_A );
    KeyBindingManager.getKeyBindingManager().set( "nodeTranslateRight", KeyInput.KEY_D );
    KeyBindingManager.getKeyBindingManager().set( "nodeTranslateForward", KeyInput.KEY_Q );
    KeyBindingManager.getKeyBindingManager().set( "nodeTranslateBackward", KeyInput.KEY_Z );
}

protected void simpleUpdate() 
{
    if (KeyBindingManager.getKeyBindingManager().isValidCommand("sphereRed", false)) 
        mySphere.setSolidColor( ColorRGBA.red ); 
    if (KeyBindingManager.getKeyBindingManager().isValidCommand("sphereMulti")) 
        mySphere.setRandomColors();  
   
    float speed = 2*tpf;
    if (KeyBindingManager.getKeyBindingManager().isValidCommand("nodeTranslateUp")) 
        mySphere.getLocalTranslation().addLocal( cam.getUp().clone().mult(speed) );
    if (KeyBindingManager.getKeyBindingManager().isValidCommand("nodeTranslateDown")) 
        mySphere.getLocalTranslation().addLocal( cam.getUp().clone().mult(-speed) );
    if (KeyBindingManager.getKeyBindingManager().isValidCommand("nodeTranslateLeft")) 
        mySphere.getLocalTranslation().addLocal( cam.getLeft().clone().mult(speed) );
    if (KeyBindingManager.getKeyBindingManager().isValidCommand("nodeTranslateRight")) 
        mySphere.getLocalTranslation().addLocal( cam.getLeft().clone().mult(-speed) );
    if (KeyBindingManager.getKeyBindingManager().isValidCommand("nodeTranslateForward")) 
        mySphere.getLocalTranslation().addLocal( cam.getDirection().clone().mult(speed) );
    if (KeyBindingManager.getKeyBindingManager().isValidCommand("nodeTranslateBackward")) 
        mySphere.getLocalTranslation().addLocal( cam.getDirection().clone().mult(-speed) );

    if (KeyBindingManager.getKeyBindingManager().isValidCommand("lightTranslateUp")) 
        pl.getLocation().addLocal( cam.getUp().clone().mult(speed) );
    if (KeyBindingManager.getKeyBindingManager().isValidCommand("lightTranslateDown")) 
        pl.getLocation().addLocal( cam.getUp().clone().mult(-speed) );
    if (KeyBindingManager.getKeyBindingManager().isValidCommand("lightTranslateLeft")) 
        pl.getLocation().addLocal( cam.getLeft().clone().mult(speed) );
    if (KeyBindingManager.getKeyBindingManager().isValidCommand("lightTranslateRight")) 
        pl.getLocation().addLocal( cam.getLeft().clone().mult(-speed) );
    if (KeyBindingManager.getKeyBindingManager().isValidCommand("lightTranslateForward")) 
        pl.getLocation().addLocal( cam.getDirection().clone().mult(speed) );
    if (KeyBindingManager.getKeyBindingManager().isValidCommand("lightTranslateBackward")) 
        pl.getLocation().addLocal( cam.getDirection().clone().mult(-speed) );
        
    lightBulb.setLocalTranslation( pl.getLocation() );
    pManager.updatePasses(tpf);
}

protected void simpleRender() 
{
    /** Have the PassManager render. */
    pManager.renderPasses( display.getRenderer() );
}

}

@stemkoski Have you tried with a directional light? This had seemed to produce the best results for me.



BTW, the shadow system(s) in jME3 are much better and easier to use. Both single and pssm implementations are available…