DirectionalLightShadowRenderer and edge-on surface

I’m wondering what causes the black bars on some of the vertical surfaces in my game when they are lit by directional light from above plus ambient light. I’m also wondering if there’s a fix for this problem, short of tweaking the light direction.

Here’s a test app which demonstrates the problem I’m talking about:

[java]
package shadows;

import com.jme3.app.SimpleApplication;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
import com.jme3.shadow.DirectionalLightShadowRenderer;
import com.jme3.shadow.EdgeFilteringMode;
import com.jme3.texture.Texture;

/**

  • A simple JME3 app to demonstrate shadow rendering issues.
    */
    public class Main
    extends SimpleApplication {

    public static void main(String[] args) {
    Main app = new Main();
    app.setShowSettings(false);
    app.start();
    }

    @Override
    public void simpleInitApp() {
    /*
    * background
    /
    viewPort.setBackgroundColor(ColorRGBA.Gray);
    /

    * camera
    /
    cam.setLocation(new Vector3f(4f, 2f, 0f));
    Quaternion startRotation = new Quaternion(0.2f, -0.6f, 0.2f, 0.7f);
    cam.setRotation(startRotation);
    flyCam.setMoveSpeed(10f);
    /

    * lighting
    */
    DirectionalLight mainLight = new DirectionalLight();
    mainLight.setColor(ColorRGBA.White);
    mainLight.setDirection(Vector3f.UNIT_Y.negate());
    rootNode.addLight(mainLight);

     AmbientLight ambientLight = new AmbientLight();
     ambientLight.setColor(ColorRGBA.White.mult(4f));
     rootNode.addLight(ambientLight);
     /*
      * cubic box with logo
      */
     Material logoMaterial = new Material(assetManager,
             "Common/MatDefs/Light/Lighting.j3md");
     Texture logo =
             assetManager.loadTexture("Textures/Terrain/splat/road.jpg");
     logoMaterial.setTexture("DiffuseMap", logo);
    
     Box boxMesh = new Box(1f, 1f, 1f);
     Geometry logoBox = new Geometry("box", boxMesh);
     logoBox.rotate(0f, FastMath.PI / 4, 0f);
     logoBox.setLocalTranslation(Vector3f.ZERO);
     logoBox.setMaterial(logoMaterial);
     logoBox.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
     rootNode.attachChild(logoBox);
     /*
      * shadow renderer
      */
     DirectionalLightShadowRenderer dlsr =
             new DirectionalLightShadowRenderer(assetManager, 512, 3);
     dlsr.setEdgeFilteringMode(EdgeFilteringMode.Nearest);
     dlsr.setLight(mainLight);
     dlsr.setShadowIntensity(0.8f);
     viewPort.addProcessor(dlsr);
    

    }
    }
    [/java]

When I run this, the top face of the cube (which is horizontal) shows the texture clearly, but the sides (which are vertical but not axis-aligned) shows narrow vertical black bars superimposed on the texture.

The test case is good but screenshots are good too :slight_smile:

It sounds like it could be the shadow renderer - try removing that and see what happens.

Yes, it is the shadow renderer. If I disable the renderer the scene look the way I expect.

Here’s a screenshot illustrating the issue:
dropbox link

that’s a rasterization issue inherent to the shadow mapping technique.
usually it’s hidden by some shadow edge convolution (try PCF4, PCFPOISSON or PCF8). Note that the issue will still be visible to some extend.

1 Like

Looks like a severe case of shadow acne :slight_smile:
Shadow acne is an aliasing error and highlighted because the shadow map has limited number of pixels.
To create shadows the scene is rendered from the lights point of view. Since these sides of the cube are almost not visible from the light it will be a little hit or miss if the shadow map should create a shadow or not. And since the shadow map is course-grained the parts it decides should be in shadow will appear as stripes.

Or maybe it isn’t shadow acne but something else, just guessing.

Edit: Doh, ninjad by the shadow master himself :slight_smile:

1 Like

This is one of the reason that games are very rarely set at Noon. (And even at noon the sun is not directly ahead).

  1. Directly overhead looks boring anyway.

  2. Light direction parallel with polygons (which is most likely to happen with vertical lights) causes all sorts of problems.

1 Like

Thanks to all. By the way, the JavaDoc for PCFPOISSON in com.jme3.shadow.EdgeFilteringMode appears to be incorrect – copy/pasted from PCF8. Does anyone know what PCFPOISSON actually does?

I’ve created a new issue #606 to track the apparent copy-paste error in the com.jme3.shadow.EdgeFilteringMode javadoc.

Yeah that is a copy-pasta :slight_smile:
But what it does is a Poisson disc sampling of the edge

https://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/core-data/Common/ShaderLib/Shadows.glsllib#127

This explained Poisson to me: Poisson Disk Sampling – Dev.Mag
This is pretty good to I think: Tutorial 16 : Shadow mapping

1 Like

Thanks for the links.