Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve shadow quality (currently shadow map is underused) #262

Closed
galmiza opened this issue Nov 27, 2019 · 6 comments · Fixed by godotengine/godot#37678
Closed

Improve shadow quality (currently shadow map is underused) #262

galmiza opened this issue Nov 27, 2019 · 6 comments · Fixed by godotengine/godot#37678
Milestone

Comments

@galmiza
Copy link

galmiza commented Nov 27, 2019

Describe the project you are working on:

I am working on a first person shooter for mobile. It involves rendering shadows.

Describe the problem or limitation you are having in your project:

I need to keep the shadow map resolution low (say 1024x1024) to run at full speed on mobile.
At this resolution, the quality of the Godot shadows is much lower than what we could expect.

Below the quality with the Godot shadow rendering pipeline

godot

Below the quality with a custom shadow rendering pipeline (written in GDScript)
custom

Describe how this feature / enhancement will help you overcome this problem or limitation:

An improvement of the shadow quality to an acceptable level will allow me not to tinker with the rendering pipeline ;)

Show a mock up screenshots/video or a flow diagram explaining how your proposal will work:

Describe implementation detail for your proposal (in code), if possible:

Source code of the custom implementation: https://github.com/galmiza/godot-custom-shadow-mapping

If this enhancement will not be used often, can it be worked around with a few lines of script?:

Is there a reason why this should be core and not an add-on in the asset library?:

This enhancement is expected to replace the current implementation.

@Calinou
Copy link
Member

Calinou commented Nov 27, 2019

You can change the depth range used for directional shadows in the DirectionalLight node (Directional Shadow > Depth Range). If you set it to Optimized instead of Stable, the shadow will be sharper but will flicker around as the camera moves. This is a good option for games where the camera is expected to move constantly, but it's not suited for games where the camera will often stand still.

Still, it's known there are possible optimizations to directional shadow culling and rendering. These will be researched in the upcoming Vulkan renderer.

@galmiza
Copy link
Author

galmiza commented Nov 27, 2019

I actually played a lot with all the parameters in an attempt to have decent quality. The result shown here for Godot is already optimised. It is the best I could get with this simple scene.

I am a bit shocked of the gap compared to a minimalist implementation.

@Calinou
Copy link
Member

Calinou commented Nov 27, 2019

@galmiza Have you tested your implementation in larger, more complex scenes? Try adding extra geometry and rotate the directional light so it uses a more "grazing" angle compared to the ground.

@galmiza
Copy link
Author

galmiza commented Nov 27, 2019

The current code was more to show what we get vs what we could expect with the same performance impact and without serious optimisations.

It is all about computing an optimal light view matrix that encapsulates objects that could cast/receive shadow on the visible scene.
I updated the code to compute automatically an efficient orthogonal light view matrix (currently taking all objects into account).
Indeed the quality decreases as the objects are spread around because a bigger volume is projected onto the shadow map.

To solve this problem, the best approach would be using a light space perspective shadow map that allocates more space on the shadow map for objects near the viewer. I tried to implement in Godot but didn't succeed (yet?) due to various limitations of Godot (which I raised in earlier proposal requests today).

@lawnjelly
Copy link
Member

I didn't write any of the shadow code but I had a little look at it not that long ago.
Two things which will affect this:

  1. The shadow map has to be stable over time, if something popped into view and increased the size that was needed for the frustum, this could lead to big popping in the shadows.
  2. Somewhat unexpectedly, Godot currently caches shadow maps as an optimization to deal with the situation when the light / shadow casters don't change.

The problem with (2) is that I believe it means shadow maps are rendered for the ENTIRE VIEW of the light, and cached. This is suboptimal both in terms of the number of casters rendered (which particularly interested me at the time), but also in terms of the shadow map resolution.

You can, as you say get a much tighter shadow map fit if you clip the shadow frustum against the camera frustum. I actually do this in my LPortal module, you can have a look at the source if this would help calculate a tight shadow matrix:

https://github.com/lawnjelly/godot-lportal
(look in lmain_camera.cpp)

I tried integrating this into the core in fact, and it worked perfectly except it conflicted with the shadow caching approach, so I closed the PR:
godotengine/godot#33340

I did bring up this caching problem with reduz. Although caching can theoretically help in some situations (and especially in demos, where maybe the viewer is the only thing moving), I wondered how often this actually occurred in real games, where there are usually things like animated objects, which will require redrawing the shadow maps anyway.

The caching is an optimization for situations where there is no dynamics, but unfortunately is a de-optimization for most other situations because there will be casters rendered that are not affecting the camera view. And the shadow map resolution might not be ideal, as you have found.

@Calinou
Copy link
Member

Calinou commented Dec 10, 2019

@lawnjelly I agree, even games that make use of an hybrid lightmap + real-time lighting system won't be able to cache the directional light shadows (as moving objects like players will require continuous shadow updates).

On the other hand, caching shadows makes sense for omni/spot lights if you configure them to only cast static shadows. This is a common optimization for smaller lights; I'm not sure if Godot currently supports this though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants