# Light and Shadow

Lighting means that an object is brighter on the side facing the light direction, and darker on the backside. A light source with a direction or location is required for lit Materials to be visible. Lighting does not automatically mean that objects cast a shadow on the floor or other objects: Activating shadow processing is an extra step described below.

## Light Sources

You can add several light sources to a scene using `rootNode.addLight()`. All Lighting.j3md- based Materials require a light source to be visible. The available light sources in `com.​jme3.​light` are SpotLight, PointLight, AmbientLight, and DirectionalLight. You can set the color of the light – normally, it is white. You can choose to set other colors to influence the scene's atmosphere. A PointLight has a location and shines from there in all directions as far as its radius reaches, like a lamp. The light intensity decreases with increased distance from the light source.

    PointLight lamp_light = new PointLight();
    lamp_light.setColor(ColorRGBA.Yellow);
    lamp_light.setRadius(4f);
    lamp_light.setPosition(new Vector3f(lamp_geo.getLocalTranslation()));
    rootNode.addLight(lamp_light);

A DirectionalLight has no position, only a direction. It is considered "infinitely" far away and sends out parallel beams of light. It can cast shadows. You typically use it to simulate sun light:

    DirectionalLight sun = new DirectionalLight();
    sun.setColor(ColorRGBA.White);
    sun.setDirection(new Vector3f(-1, -1, -1).normalizeLocal());
    rootNode.addLight(sun);

An AmbientLight influences the brightness of the whole scene globally. It has no direction and no location, and does not cast any shadow.

    AmbientLight al = new AmbientLight();
    al.setColor(ColorRGBA.White.mult(1.3f));
    rootNode.addLight(al);

A SpotLight is like a flashlight that sends a distinct beam of light. (Still work in progress, as of alpha-3.)

## Simple Lighting

- TestSimpleLighting.java
- TestLightRadius.java

Here we use a material based on Lighting.j3md (More info about Materials). Lighting.j3md-based materials dynamically support Shininess, and Ambient, Diffuse, and Specular Colors.

    Geometry teapot = (Geometry) assetManager.loadModel("Models/Teapot/Teapot.obj");
    TangentBinormalGenerator.generate(teapot.getMesh(), true);
    Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
    mat.setBoolean("m_UseMaterialColors", true);
    mat.setColor("m_Ambient",  ColorRGBA.Black);
    mat.setColor("m_Diffuse",  ColorRGBA.Blue);
    mat.setColor("m_Specular", ColorRGBA.White);
    mat.setFloat("m_Shininess", 12);
    rootNode.attachChild(teapot);

In this example, we use material colors instead of textures. But you can equally well use Lighting.j3md to create a Material that uses texture maps, such as the Diffuse and Normal map used here, but also Specular and Paralax Maps:

        Sphere rock = new Sphere(32,32, 2f);
        Geometry shiny_rock = new Geometry("Shiny rock", rock);
        rock.setTextureMode(Sphere.TextureMode.Projected); // better quality on spheres
        TangentBinormalGenerator.generate(rock);           // for lighting effect
        Material mat_lit = new Material(
            assetManager, "Common/MatDefs/Light/Lighting.j3md");
        mat_lit.setTexture("m_DiffuseMap",
            assetManager.loadTexture("Textures/Terrain/Pond/Pond.png"));
        mat_lit.setTexture("m_NormalMap",
            assetManager.loadTexture("Textures/Terrain/Pond/Pond_normal.png"));
        mat_lit.setFloat("m_Shininess", 5f); // [0,128]
        shiny_rock.setMaterial(mat_lit);
        rootNode.attachChild(shiny_rock);

This lighting updates live when the object or light source moves. If you shine a colored PointLight at this object, you will see a light reflection in the color of the PointLight. This lighting method doesn't make the node cast a shadow onto other nodes.

## BasicShadowRenderer

- TestShadow.java

Use the Shadow Renderer to make textured scene nodes cast and receive shadows. Switch off the default shadow mode, and add a jME SceneProcessor named com.jme3.shadow.BasicShadowRenderer to the viewPort.

    BasicShadowRenderer bsr;
    ...
    public void simpleInitApp() {
        ...
        rootNode.setShadowMode(ShadowMode.Off);
        bsr = new BasicShadowRenderer(assetManager, 256);
        bsr.setDirection(new Vector3f(-1, -1, -1).normalizeLocal());
        viewPort.addProcessor(bsr);
        ...

For every scene node that needs shadows, individually specify the shadow behaviour: Whether it cast shadows, receive shadows, both, or neither.

    wall.setShadowMode(ShadowMode.CastAndReceive);
    ...
    floor.setShadowMode(ShadowMode.Receive);
    ...
    airplane.setShadowMode(ShadowMode.Cast);
    ...
    ghost.setShadowMode(ShadowMode.Off);
    ...

## Parallel-Split Shadow Map

- TestPssmShadow.java

The PSSM shadow renderer can cast real-time shadows on curved surfaces. To activate it, add a jME SceneProcessor named `com.jme3.shadow.PssmShadowRenderer` to the viewPort.

    private PssmShadowRenderer pssmRenderer;
    ...
    public void simpleInitApp() {
        ....
        pssmRenderer = new PssmShadowRenderer(
            assetManager,1024,4,PssmShadowRenderer.EDGE_FILTERING_PCF);
        pssmRenderer.setDirection(new Vector3f(-1, -1, -1).normalizeLocal());
        viewPort.addProcessor(pssmRenderer);

The constructor expects the following values:

- Your assetManager object
- The size of the rendered shadowmaps (512, 1024, 2048, etc…)
- The number of shadow maps rendered (the more shadow maps, the more quality, the less FPS).
- The type of filtering for shadow edge smoothing:
  - PSSMShadowRenderer.EDGE_FILTERING_DITHER
  - PSSMShadowRenderer.EDGE_FILTERING_PCF (default).

You can set the following properties on the `pssmRenderer` object:

- setDirection(Vector3f) – the direction of the light
- setLambda(0.65f) – Factor to use to reduce the split size
- setShadowIntensity(0.7f) – shadow darkness (1 black, 0 invisible)
- setShadowZextend() – distance how far away from camera shadows will still be computed

As usual, specify the shadow behaviour for every scene node.

    ...
    teapot.setShadowMode(ShadowMode.CastAndReceive);
    ...
    soil.setShadowMode(ShadowMode.Receive);
    ...

view online version