godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
86.6k stars 19.3k forks source link

SDFGI Is Splotchy On Large Uniform Surfaces #50773

Open WickedInsignia opened 2 years ago

WickedInsignia commented 2 years ago

Godot version

Godot 4 nightly build

System information

Windows 10 v20H2, Intel i7 6700, Nvidia GTX1080, 16GB RAM

Issue description

SDFGI displays severe splotching and pockmarking artifacts in low-light environments and especially on large uniform surfaces with little texture or model breakup. Although this splotching seems to always be present, it is mostly present in these circumstances.

Steps to reproduce

In the following examples I have a room with a single thin window letting directional light in as well as skylight. This scenario has been recreated in the attached project file below. Here, we can observe severe splotching of light and dark tones in a large bare room: SDFGI Splotchy 05 SDFGI Splotchy 01

Even on smaller-scale surfaces and those with low detail frequency the splotching can be observed. Although it may look smooth from a distance: SDFGI Splotchy 02

Splotching occurs when the camera moves closer and GI detail is increased in the area: SDFGI Splotchy 03

Minimal reproduction project

I have provided an example file with a couple basic meshes and a capsule to represent the size of a regular player: SDFGI_Splotchy_Bug.zip

Here are some screenshots of the effects that may be observed: The leftmost structure is only partially enclosed with plenty of light spilling in. Although the effect is hardly noticeable close to the light, further into the structure where the light has difficulty reaching there are highly visible artifacts: SDFGI Splotchy 06

The rightmost structure is considerably larger with a thinner opening for light to enter. Although there is no detail frequency in the space, the GI lighting artifacts are chaotic: SDFGI Splotchy 07

All shots taken with 8 cascades, Y scale at 50% and Occlusion and Sky Influence active.

Calinou commented 2 years ago

You can increase SDFGI's Probe Ray Count and Frames To Converge in the Project Settings to improve this. See also https://github.com/godotengine/godot/pull/39965.

Increasing Probe Ray Count has a performance cost, whereas increasing Frames To Converge doesn't but will make indirect lighting take longer to update. For mostly static scenes, we could add an option to increase Frames To Converge even further (e.g. over 60 frames), but this will increase the delay for moving lights quite a lot.

Edit: Done in https://github.com/godotengine/godot/pull/50796.

WickedInsignia commented 2 years ago

Thanks! Will check this out and record the results if they’re significant. It might be worth making a proposal to be able to restrict SDFGI to a probe domain like GI Probe? I understand if it’s not possible since the systems are inherently different. Also I haven’t tested lightmaps and SDFGI in unison, but if lightmapping is used in a specific space would it be possible to stop SDFGI from influencing the same area?

Calinou commented 2 years ago

It might be worth making a proposal to be able to restrict SDFGI to a probe domain like GI Probe? I understand if it’s not possible since the systems are inherently different.

SDFGI is designed to be used in open world scenes first and foremost. For this use case, bounds don't really make sense and aren't really feasible on a technical level.

Lightmaps are generally meant to be used exclusively for performance reasons, rather than blending them with other GI techniques (other than ReflectionProbe). If you use lightmaps, it's likely because GIProbe and SDFGI are too expensive for the hardware you're targeting.

WickedInsignia commented 2 years ago

Ah good to know. Just trying to think of ways to reach the most flexible and good-looking compromise, but it seems like with some extra elbow grease SDFGI is the way to go on the whole.

clayjohn commented 2 years ago

It might be worth making a proposal to be able to restrict SDFGI to a probe domain like GI Probe?

@WickedInsignia If you need more detail on an area, specifically and indoor area with a small but bright light source (like your test case), you can add a VoxelGIProbe. The VoxelGIProbe can blend over, or outright replace the GI contribution from SDFGI.

Calinou commented 2 years ago

If you want to play around the the number of SDFGI frames to converge associated to each setting, you can change this line and recompile the editor: https://github.com/godotengine/godot/blob/9b034c930467606a7696d93020838c4f0c5f01e2/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp#L65

Note that the project settings' text will not change, but the value associated to each setting behind the scenes will be changed successfully.

PS: It would be possible to change this project setting to allow setting any number of frames, rather than being limited to a few predefined settings. Edit: Done in https://github.com/godotengine/godot/pull/50796.

Note that you have to move or rotate the camera around a bit after changing the project setting to allow SDFGI to converge. This is because the editor only redraws when something on screen changes to save power.

30 frames to converge

image

60 frames to converge

image

90 frames to converge

image

120 frames to converge

image

150 frames to converge

image

180 frames to converge

image

There are diminishing returns to going further:

### 300 frames to converge ![image](https://user-images.githubusercontent.com/180032/126821710-c8c063be-a414-44f3-82fe-59827f2edc3c.png) ### 5000 frames to converge ![2021-07-23_19 50 20](https://user-images.githubusercontent.com/180032/126821771-25764f96-d1a5-492f-8c79-d106ff343578.png)
WickedInsignia commented 2 years ago

@Calinou I am merely but an artist haha. I'll have a look into that solution but I'm using Godot as shipped since I don't have the experience to change or recompile the editor code. Optimally, the ability to get a less splotchy result would be an in-editor setting. That may be asking for a lot though!

@clayjohn I hadn't tested GIProbe with SDFGI yet so I will give that a shot. Would using both together significantly reduce performance?

clayjohn commented 2 years ago

@WickedInsignia It depends on your hardware and the settings you use. But you are combining the cost of both effects so it will be more expensive than using either technique by itself. Thankfully VoxelGi is not very expensive to use at runtime (it requires baking though). You can also run VoxelGI at half resolution to make it even faster at runtime.

Calinou commented 2 years ago

Another way to reduce splotches is to increase Bounce Feedback and decrease energy to compensate for the brighter result. This results in a more uniform look with more gradual fadeouts, which may be an artistic choice that's also useful to avoid overly dark areas:

Bounce Feedback 0, Energy 1

2021-07-24_06 36 39

2021-07-24_06 40 38

Bounce Feedback 0.6, Energy 0.5

2021-07-24_06 37 45

2021-07-24_06 40 30

Combining this with a higher number of frames to converge can give you a very good result, which gets quite close to baked lighting in terms of quality. See https://github.com/godotengine/godot/pull/50796 for an example.

WickedInsignia commented 2 years ago

Nice! Seems to resolve the splotching to at least some level. Ran my own tests briefly, and it seems quite easy to hit the limits of Bounce Feedback becoming unusable, so potential users should be advised. It also took a few seconds for the adjustments to take effect so I made sure to wait until they settled.

Here's Bounce Feedback 0.8 and Energy 0.5. The large structure is quite nice: Bouncefeedback08_Energy05_01

However the small structure is unusable and bleeds through the geometry: Bouncefeedback08_Energy05_02

Setting it down to Bounce Feedback 0.7 and Energy 0.7 was a happy medium in this case: Bouncefeedback07_Energy07_01 Bouncefeedback07_Energy07_02

It's also worth taking note of how drastic the SDFGI effect with this adjustments was depending on distance. The smaller structure looks vastly different at a distance: Bouncefeedback06_Energy05_DistanceLong Bouncefeedback06_Energy05_DistanceShort

I also attempted to use the VoxelGI, but found at default settings my framerate tanked and there was excess light leakage: AlternativeVoxelGI_01

Lastly, I attempted to use LightmapGI at default settings but encountered even worse light leakage and some streaking artifacts. The lightmap options seem to differ considerably from 3.3.2 so I didn't bother taking shots. If you get some time, try this out since you'd probably know how to operate it better than I.

In conclusion none of the 3 GI options gave a satisfyingly smooth result (in my brief tests). VoxelGI was closest, but suffered excess light leakage. The lightmapping in Godot 4 gave vastly different results to Godot 3 in my other tests, but I'm probably not using it correctly and settled on defaults.

I absolutely don't expect the tools to do "all of the work" for the artist and there will always be caveats that need to be acknowledged, which is ultimately the goal of these bug reports.

Calinou commented 2 years ago

Ran my own tests briefly, and it seems quite easy to hit the limits of Bounce Feedback becoming unusable, so potential users should be advised.

Bounce Feedback will start having infinite feedback loops if the material receiving direct light is too bright. In most real world scenes, having such bright non-emissive materials over large surfaces is rare. In these scenes, a Bounce Feedback value around 1 can work in practice. Bounce Feedback values above 1 can also work in darker scenes that have few bright materials – this is why the inspector allows values up to 2.0.

I also attempted to use the VoxelGI, but found at default settings my framerate tanked and there was excess light leakage:

To improve performance, enable Rendering > Global Illumination > Gi > Use Half Resolution in the project settings. This affects both SDFGI and VoxelGI, and improves performance significantly at a small quality cost. The quality difference is less noticeable at higher resolutions. I have a pull request enabling that setting by default: https://github.com/godotengine/godot/pull/49738

To reduce leaking, adjust the GIProbe's position/rotation/extents a bit, bake again and experiment with values that make leaking less noticeable. To avoid leaks in all situations, walls have to be thicker than 1 VoxelGI subdivision. For instance, if you use the default 128 subdivisions and your VoxelGI's size is Vector3(40, 20, 40), walls have to be thicker than 0.3125 units and floors have to be thicker than 0.15625 units. Since the walls are axis-aligned in this demo, I would recommend playing with just the position and extents. You can also use solid meshes with bake mode set to Static that you hide after baking the VoxelGI.

The lightmap options seem to differ considerably from 3.3.2 so I didn't bother taking shots.

The master branch uses a GPU lightmapper which is much faster, but has gotten less testing and is missing some options from the CPU lightmapper. The 3.x branch uses a CPU lightmapper that takes much longer to bake, but generally results in better quality. I don't know if the CPU lightmapper will be ported to master in time for 4.0, but it is planned to do so in the future to allow baking lightmaps in the future OpenGL renderer.

With the CPU lightmapper, it's definitely possible to get nearly leak-free results like this:

Sponza

WickedInsignia commented 2 years ago

Awesome!! That’s really helpful, thank you. I’ll make sure to play with all of these a lot further and these tips will help a ton in my own projects.

Also very thankful for you thoroughness, since it presents viable solutions for other artists who come across the same issues.