Shadow implementation problems

Hi all,

I am trying to implement shadows into my game, but it results into really bad performance (around 19 fps) and casting shadows not correctly regarding the possible area which could receive the light/cast the shadow (only a part of the geometry is visible). It also seems that the light direction is wrong, but should be correct because I am using the cam direction. Here’s my code I used to enable the shadows:

private void initLighting() {
        g_ambient = new AmbientLight();
        g_ambient.setColor(ColorRGBA.White);
        rootNode.addLight(g_ambient);

        g_sun = new DirectionalLight();
        g_sun.setColor(ColorRGBA.White);
        g_sun.setDirection(new Vector3f(g_gameCam.getCam().getDirection().normalizeLocal()));
        rootNode.addLight(g_sun);
    }

    private void initShadow() {
        final int SHADOWMAP_SIZE = 512;
        DirectionalLightShadowRenderer dlsr = new DirectionalLightShadowRenderer(assetManager, SHADOWMAP_SIZE, 3);
        dlsr.setLight(g_sun);
        viewPort.addProcessor(dlsr);

        DirectionalLightShadowFilter dlsf = new DirectionalLightShadowFilter(assetManager, SHADOWMAP_SIZE, 3);
        dlsf.setLight(g_sun);
        dlsf.setEnabled(true);
        FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
        SSAOFilter ssaoFilter = new SSAOFilter(12.94f, 43.92f, 0.33f, 0.61f);
        fpp.addFilter(ssaoFilter);
        viewPort.addProcessor(fpp);
}

I’ve also tried to use the shader post shadow of Lighting (shader) but it seems to not work in my project :confused:

I don’t have experience with that but according to my knowledge you could either use DLSRenderer or DLSFilter.
The First one actually renders the Shadow the other one is a less accurate post processor.
Try only using one of them to see how it works, atleast this should improve fps :slight_smile:

1 Like

Indeed my fps are better only using the filter, but then there wouldn’t be any shadows. Anyone has a clue how to use the shader post shadow stuff?

http://wiki.jmonkeyengine.org/doku.php/jme3:advanced:light_and_shadow

I guess you took your code from there, huh? :stuck_out_tongue:
The Code is to demonstrate both and switch between it, that explains your performance issues :stuck_out_tongue:

So the ShadowFilter yields bad results, have you tried rootNode.setShadowMode(ShadowMode.CastAndReceive); ?
Or any other Modes? (See the Wiki for what does what)

Sure :wink:

        geo = new Geometry(id, mesh);

        mat = new Material(GameManager.g_assetManager,
                "Common/MatDefs/Light/Lighting.j3md");
        mat.setReceivesShadows(true);
        mat.setBoolean("UseMaterialColors", true);
        mat.setColor("Ambient", activeColor);
        mat.preload(GameManager.g_simpleApplication.getRenderManager());
        mat.setBoolean("HardwareShadows", true);

        geo.setShadowMode(ShadowMode.CastAndReceive);
        geo.addLight(GameManager.g_sun);
        geo.addLight(GameManager.g_ambient);
        geo.setMaterial(mat);
        geo.setLocalTranslation(position.x, position.y, position.z);
        geo.updateModelBound();

        node.attachChild(geo);

Well then you have to wait for the pros to reply :stuck_out_tongue:
Or take the “ShadowRenderer Test” and take the code there as an example.

Btw: You shouldn’t add the light to each Geometry but instead to the rootNode (because a Light illuminates every spatial under it’s node)

you have 15000 objects rendered, that’s too much.
Shadows add several geometry passes so that’s crucial that your scene is correctly partitionned, and have as few objects as necessary.
The filter remove one of the passes so that’s why it’s faster, but it has several drawbacks.
Of course it should work and idk why it doesn’t work for you.

How many objects do you have in the scene when you remove the shadows?
My guess is around 3000, and it’s too much.
Look into “batching” or “optimizing your scene” in the documentation or on the forum and you’ll see how you can drastically optimize your scene and bump up the fps.

1 Like

If you want to use the filter, you also have to call fpp.addFilter(dlsf); But as Darkchaos said, just use one of the two. You can find information about which one to use in which situations in the wiki.

Well it’s way more than 3000. ^^
My problem is that I cannot batch the geometries because each geometry should be able to be changed regarding its material any time.

What about the post shadow technique of a shader?

Then you are going to have a bad time because you are killing your graphics card. This will never ever perform well. It’s like if you had to ship a 500 page document to someone but rather than put the whole document in a box, you send it a page at a time… and wait for them to e-mail you that they got the page before you send the next one. It’s just horribly inefficient.

If you need custom colors that change… use vertex attributes and a custom shader. The number of objects you have is never going to work well.

I think we’re going to need to see the latest code… and possibly more than you’ve provided.

You are using a copy of the cam direction at the time of the initLighting call.
So the direction should be static (“copy of the cam direction”) and not change.
And the direction is the one that the cam object had (“at the time of the call”).

Seems like you are rendering in windowed mode and I can’t see whether AA is on (and how much).

What kind of computer do you have? I recently found out that there are those expensive cards … you know … those that make other people’s computers 5 times faster than mine. And I’ve read that almost all Macbooks have integrated Intel Graphics. And then there are CPUs that have double the cores and an extra Megahertz in each of those cores. :chimpanzee_wink:

+all the stuff that the others pointed out :chimpanzee_smile:

Ok, I am trying to put everything important together:

@Override
public void simpleInitApp() {
        //(...) init stuff for cam, gui

        initLighting();
        initShadow();
        rootNode.setShadowMode(ShadowMode.CastAndReceive);
}

private void initLighting() {
    g_ambient = new AmbientLight();
    g_ambient.setColor(ColorRGBA.White);
    rootNode.addLight(g_ambient);

    g_sun = new DirectionalLight();
    g_sun.setColor(ColorRGBA.White);
    g_sun.setDirection(new Vector3f(0, 0.2f, 0.6f));
    rootNode.addLight(g_sun);
}

private void initShadow() {
    final int SHADOWMAP_SIZE = 512;
    DirectionalLightShadowRenderer dlsr = new DirectionalLightShadowRenderer(assetManager, SHADOWMAP_SIZE, 3);
    dlsr.setLight(g_sun);
    viewPort.addProcessor(dlsr);

    DirectionalLightShadowFilter dlsf = new DirectionalLightShadowFilter(assetManager, SHADOWMAP_SIZE, 3);
    dlsf.setLight(g_sun);
    dlsf.setEnabled(true);
    FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
    SSAOFilter ssaoFilter = new SSAOFilter(12.94f, 43.92f, 0.33f, 0.61f);
    fpp.addFilter(dlsf);
    fpp.addFilter(ssaoFilter);
    viewPort.addProcessor(fpp);
}

That’s how I init my geo:

private void initMesh() {
    Vector3f[] vertices = new Vector3f[12];
    vertices[0] = new Vector3f(8, 0, 0);
    vertices[1] = new Vector3f(24, 0, 0);
    vertices[2] = new Vector3f(32, 0, 12);
    vertices[3] = new Vector3f(24, 0, 24);
    vertices[4] = new Vector3f(8, 0, 24);
    vertices[5] = new Vector3f(0, 0, 12);

    vertices[6] = new Vector3f(8, -64, 0);
    vertices[7] = new Vector3f(24, -64, 0);
    vertices[8] = new Vector3f(32, -64, 12);
    vertices[9] = new Vector3f(24, -64, 24);
    vertices[10] = new Vector3f(8, -64, 24);
    vertices[11] = new Vector3f(0, -64, 12);

    Vector2f[] texCoord = new Vector2f[12];
    texCoord[0] = new Vector2f(1, 0);
    texCoord[1] = new Vector2f(1, 0);
    texCoord[2] = new Vector2f(1, 1);
    texCoord[3] = new Vector2f(1, 1);
    texCoord[4] = new Vector2f(1, 1);
    texCoord[5] = new Vector2f(0, 1);

    texCoord[6] = new Vector2f(1, 0);
    texCoord[7] = new Vector2f(1, 0);
    texCoord[8] = new Vector2f(1, 1);
    texCoord[9] = new Vector2f(1, 1);
    texCoord[10] = new Vector2f(1, 1);
    texCoord[11] = new Vector2f(0, 1);

    int[] indexes = {
        2, 0, 1, 
        5, 0, 2,
        4, 5, 2,
        3, 4, 2,

        0, 6, 7,
        0, 7, 1,
        1, 7, 8,
        1, 8, 2,
        2, 8, 9,
        2, 9, 3,
        3, 9, 10,
        3, 10, 4,
        4, 10, 11,
        4, 11, 5,
        5, 11, 6,
        5, 6, 0
    };

    mesh = new Mesh();
    mesh.setBuffer(Type.Position, 3, BufferUtils.createFloatBuffer(vertices));
    mesh.setBuffer(Type.TexCoord, 2, BufferUtils.createFloatBuffer(texCoord));
    mesh.setBuffer(Type.Index, 3, BufferUtils.createIntBuffer(indexes));
    mesh.updateBound();

    resource = new Resource(Resource.EMPTY, 0);
    activeColor = resource.getRGBAValue(); //color is white

    geo = new Geometry(id, mesh);
    mat = new Material(GameManager.g_assetManager,
            "Common/MatDefs/Light/Lighting.j3md");
    mat.setBoolean("UseMaterialColors", true);
    mat.setColor("Ambient", activeColor);
    mat.preload(GameManager.g_simpleApplication.getRenderManager());
    geo.setMaterial(mat);
    geo.setLocalTranslation(position.x, position.y, position.z);
    geo.updateModelBound();

    node.attachChild(geo);
}

Each geo will be init by a object manager called terrain. And the node of this object manager is attached to the rootNode.

That’s the current status:

Somehow there’s also a problem with the camera casting a shadow itself. Is there some kind of special way to disable this?

As has been said a few times in this thread already, use either the shadow renderer OR the shadow filter. Not both. As in use just one. Pick one and don’t use the other.

So if you want to use the renderer. Don’t use the filter. And if you want to use the filter. Don’t use the renderer. (Given the over-density of your scene, filter is probably the better choice until you fix that issue.)

I don’t know what you mean by “camera shadow”… but maybe you are detecting the issues with using two different kinds of shadow rendering at once.

Also, you probably want to normalize that vector because it’s not currently a direction vector. I don’t remember if DirectionalLight force normalizes or not but better to be safe.

Edit: also, your light is pointing up towards the sky… so everything will be lit from underneath. The light direction is the direction the light rays are pointing.

1 Like

it doesn’t. So yeah, normalize your direction

…since your scene seems to be created out of hexagons, just with different color/material, then instancing will be your friend…

What do you mean by instancing?

Google “openGL instancing” but it will not help your performance problems. Given the limited number of triangles per object, batching is what you want to fix your scene performance issues. Instancing would still incur per-object overhead.

That’s kind of another topic, though, and unrelated to your shadow issues.