Recently I was contacted by Christoph Peters (one of the authors of Moment Shadow Mapping) regarding a blog post where I compared EVSM to MSM using my sample app. He noticed that I was incorrectly clamping the maximum exponential warp to 10.0 for the 16-bit variant of EVSM, which can result in values that are greater than what can be stored in a 16-bit floating point texture. Doing this has 2 effects: it causes incorrect results during filtering (clamping the moments can lead to negative variance, causing a reconstruction that resembles a step function), and it reduces the amount of light bleeding. Unfortunately all of my comparisons were done without any additional prefiltering, and so I didn’t notice my error. Even more unfortunate was that it misrepresented the extent of EVSM16’s light bleeding issues in my comparison images, making the test unfairly skewed in favor of EVSM.
To help make things right, I’ve uploaded a new version of the sample app to GitHub that correctly clamps the exponential warp factor to 5.54. The releases page has a zip file containing code and a compiled executable. I’ve also updated the original blog post in question with new comparison images, as well as new commentary on those images. You’ll notice that my thoughts on MSM have become quite a bit more positive now that I’ve taken a second look, and performed a more fair analysis. In fact, it now seems that MSM16 is hands-down the better option if you’re looking to stay in an 64bpp footprint for the shadow map.
Finally, I’d like to apologize to Christoph and Reinhard for my unfair comparison. The work they’ve presented (including some new research being presented at I3D 2016) is very promising, and it’s great to see research that’s immediately usable and practical for games. I also need to call out that they release sample code alongside their work, which is extremely helpful for evaluating and understanding their techniques. Hopefully we see more great things from them in the future!
I suggest a buildfix for VS2015: In Shadows.cpp (119-120), add “.AsEnum()” in both strings. So the result should be like Float4x4 meshWorld = Float4x4::ScaleMatrix(MeshScales[AppSettings::CurrentScene.AsEnum()]); meshRenderer.SetSceneMesh(context, &models[AppSettings::CurrentScene.AsEnum()], meshWorld);