Shadow system refactoring

You may have got it but, i’m currently working on the shadow system.

I warn you that this post is quite long.



Right now we have only PSSMShadowRenderer for directional light and the BasicShadowRenderer for …directional lights :p.

Both of them are now deprecated.



Here is how the new system works :

There is now one ShadowRenderer and its Filter counterpart for each light type :

  • DirectionalLightShadowRenderer and DirectionalLightShadowFilter for DirectionalLight
  • PointLightShadowRenderer and PointLightShadowFilter for PointLight
  • SpotLightShadowRenderer and SpotLightShadowFilter for …wait for it…SpotLight



    Each of them takes a light of the according type as a parameter.



    The DirectionalLightShadowRenderer is basically the old PSSMShadowRenderer.

    with some small differences :

    I had to extract the CompareMode and FilterMode from the clas to make them independent enum.

    I changed the name of the FilterMode enum so that there are no confusion with the post filters.

    It’s now EdgeFilteringMode and the method to set it is setEdgeFilteringMode.

    the method to set the compareMode is setShadowCompareMode.



    I made an abstract shadow renderer that holds all the common things related to shadow rendering. It’s totally independent of the shadow technique used. This avoid to have duplicate code and should make it easier to extend for those that are willing to make their own shadow renderer but want to keep the compareMode, filtering, shadow intensity, etc… features.



    On the shader side, all the shadow code is now in the Shadow.glsllib and Shadow15.glsl libs, to also avoid duplicate code.



    It’s not really gonna change your life, it’s just gonna be a lot easier for me to maintain it.

    Of course there are bonus for you, I recently made shadows for point lights and just committed the spot light shadows



    http://i.imgur.com/400iq.jpg?1



    So some may ask, when do I have to use the Renderer, when do i have to use the Filter. so let’s go



    Renderer vs Filter?

    What’s ruining the shadow performance is the fact that basically an object that receive and cast shadows has to be rendered three times :
  • generating the shadow map (only depth rendered)
  • rendering the scene
  • rendering shadows over objects on the scene

    The idea behind the filter is to replace the last geometry pass by a full screen pass. So the only geometry rendered is a quad, and with some shader Voodoo the shadows are rendered over the objects on screen. So no matter how many objects to cast shadows onto the post pass has a constant cost. Of course this is mostly interesting when there are a fair amount of objects in the scene.

    the pros :
  • filter is faster on crowded scenes (around 20 objects from the test i made but that can vary depending on the hardware)
  • cons : filter render shadows to anything that renders depth, so the ShadowRecieve queue is ignored. This can be a real problem when you absolutely don’t want shadows over some objects that write depth.

    I recommend experimenting with both and see what’s best for your scene.



    There are new test cases for shadows : TestDirectionalLightShadows (old TestPssm) TestPointLightShadows, TestSpotLightShadows



    You have to make one processor or filter for each light you want to cast shadow.

    I’ll work on a way to combine all the post passes into one.



    Here is a list of enhancements I intend to do.

    future work :

    - optimization : proper frustum culling for point and spot lights post shadow pass.

    - proper serialization to be able to edit shadows in the SDK
  • test case for multiple lights with multiple type of lights.
  • cube maps for point lights
  • adaptative PCF
  • one pass post shadow with multiple lights
  • VSM? (as in Variance Shadow Maps)
  • VSM? (as in Volume Shadow Mapping)
14 Likes

Well, I think that if it is easier to maintain, it’s for the best =] Also, if the interface is easier, it’s also for the best ^^

Are you dreaming in shadows yet? This is beyond awesomeness. Anxious to pick through the post filter stuff and see how it came out.

Any idea of when this will make it into the stable build? Right now it seems it’s only in the nightly.

@jonatan.kilhamn said: Any idea of when this will make it into the stable build? Right now it seems it's only in the nightly.
This is the announcement that it goes to svn, look out for release posts in the blog to see new releases and their features. The content of this post is meant to be read as a straight information or question without an implicit dismissive stance or interest in having the other party feel offended unless there's emotes that hint otherwise or there's an increased use of exclamation marks and all-capital words.

Excelent!!! good work!

The test code in the file TestSpotlightShadows.java stopped working with a recent update of JME3. In particular it fails with a null pointer exception at line 116 fpp.addFilter(slsf); where a SpotLightShadowFilter is added to a FilterPostProcessor.

I have tested this on two different Windows 7 machines. If you download JME3, the test code (TestSpotlightShadows) runs fine. If you let JME3 install all the current updates the same code raises an exception.

I have been using a very literal copy of the example code in my application, Is there a revision to how I should be setting up the filter?

Thanks!

I don’t have the issue with the latest master (git) version what version do you use?

I am using the download version from the Main Page at jmonkeyengine.org

There is no problem with the the actual downloaded version. It occurs after the automatic “updates” are downloaded.

Thank you for looking at it.

@kcmoore said: The test code in the file TestSpotlightShadows.java stopped working with a recent update of JME3. In particular it fails with a null pointer exception at line 116 fpp.addFilter(slsf); where a SpotLightShadowFilter is added to a FilterPostProcessor.

I have tested this on two different Windows 7 machines. If you download JME3, the test code (TestSpotlightShadows) runs fine. If you let JME3 install all the current updates the same code raises an exception.

I have been using a very literal copy of the example code in my application, Is there a revision to how I should be setting up the filter?

Thanks!

That line cannot possibly be the NPE itself. Can you post the full stack trace?

Sorry, I should have done this at the beginning.

SEVERE: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]
java.lang.NullPointerException
at com.jme3.post.FilterPostProcessor.updateLastFilterIndex(FilterPostProcessor.java:365)
at com.jme3.post.FilterPostProcessor.setFilterState(FilterPostProcessor.java:340)
at com.jme3.post.FilterPostProcessor.addFilter(FilterPostProcessor.java:112)
at jme3test.light.TestSpotLightShadows.setupLighting(TestSpotLightShadows.java:116)
at jme3test.light.TestSpotLightShadows.simpleInitApp(TestSpotLightShadows.java:177)
at com.jme3.app.SimpleApplication.initialize(SimpleApplication.java:226)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.initInThread(LwjglAbstractDisplay.java:130)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:207)
at java.lang.Thread.run(Thread.java:744)

1 Like

Interesting… looks like the FilterPostProcessor has a case where it fails when it hasn’t been attached to a viewport yet.

The FilterPostProcessor bug was introduced in 3.0.7. Please direct follow-up for this issue to http://hub.jmonkeyengine.org/forum/topic/annoying-exception-in-some-examples/

So as I understand it, you only need to use a renderer OR a filter?

@fabsterpal said: So as I understand it, you only need to use a renderer OR a filter?
Correct.
1 Like