godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.17k stars 98 forks source link

Implement ray marched volumetric fog as an extension of the current froxel based solution #8580

Open InitialCon opened 12 months ago

InitialCon commented 12 months ago

Describe the project you are working on

A cross platform 3D game where the player can see far into the distance.

Describe the problem or limitation you are having in your project

The current volumetric fog solution works by slicing the view frustrum up into froxels and using fog volumes or a global density to calculate the density and colour of individual froxels. This provides high quality close to the camera but has a limitation on how far the effect can work due to the quality being inversely proportional to the effect's distance or requiring a much larger froxel buffer size which causes performance and memory problems very quickly. This method is also not feasible on mobile platforms due a number of factors including the performance requirement.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

An alternate method of computing volumetric fog is to use ray marching. This method works by marching advancing a ray along the scene for each pixel and computing which fog volumes are the closest and calculating their densities at a set position. The density and colour are then interpolated as the ray progresses giving the appearance of a continuous volume. The rays can be jittered slightly to take advantage of taa or the entire effect can be reprojected to increase quality and performance. This method requires vastly less resources and should be possible as a high end option in the mobile and compatibility renderers. Another benefit of this approach is that it can blend seemlessly with the current froxel based fog to maintain the high quality up close while allowing high performance volumetrics at much higher distances.

Edit: Global illumination and lights other than the main directional light should be ignored for performance reasons, especially on mobile. Additionally, Rockstar recommends disabling fog volumes and only computing global fog however, if the number of fog volumes considered is kept low this shouldn't be an issue. This could be acheived by only computing ray marched fog for certain layers of fog volumes to prevent performance problems.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

Expose a new option in the volumetric fog section of the world environment such as "enable long distance fog". When this option is enabled several other options become available such as the start distance(by default this will be set to the max distance of the froxel based fog or 0 if froxel fog is disabled), the step count, as well as the default density and colour. To allow for this method to work on mobile and in the compatibility renderers a new option "enable froxel fog" must be added with it defaulting to on to avoid breaking compatibility and having its value set to zero if the project is running on a platform that doesn't support it.

This is the same method as the one used in Red Dead Redemption 2 and thus it serves as a good example of the performance and quality possible: https://www.youtube.com/watch?v=9-HTvoBi0Iw&t=7100s

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

No, since it is not currently possible to read the contents of fog volumes from user facing shaders or scripts.

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

This is a pretty standard implementation of long distance volumetrics and would enable several other add-ons which would help the overall godot ecosystem. It could be made into an add-on if the ability to read the values from a fog volume at an exact position was added however the complexity of doing it in a script would make it very difficult compared to exposing it natively.

clayjohn commented 12 months ago

For context, the RDR2 approach is not to ray march the whole scene. The froxel approach is much faster for near range fog (especially if you use volumes). The RDR2 approach is to only raymarch the area after the froxel buffer ends. It is used to capture long range fog and clouds, but it doesn't include local lights or fog volumes.

It works efficiently because you are only integrating the sun light and you have a constant density.

That being said, I think there are 2 things to consider here:

  1. Long range, simplified fog
  2. Efficient fog for mobile devices

For long range fog, I think the RDR2 approach makes a lot of sense as something that extends the current volumetric fog solution.

For mobile fog, I think we need to go with a totally different approach. We don't support volumetric fog in the mobile renderer or the compatibility renderer because compute shaders are inefficient on most mobile devices (and not supported by GLES3). For the compatibility renderer we have been discussing adding a post-process fog that would be less physically accurate, but would look okay. It would be done in screen space and integrated into the scene during the post process pass. Using a low sample count, and a half or quarter res buffer, it should be efficient enough for mobile devices. But we would likely not be able to support FogVolumes or many local lights.

InitialCon commented 12 months ago

For context, the RDR2 approach is not to ray march the whole scene. The froxel approach is much faster for near range fog (especially if you use volumes). The RDR2 approach is to only raymarch the area after the froxel buffer ends. It is used to capture long range fog and clouds, but it doesn't include local lights or fog volumes.

Ah my bad, I mentioned that it would ideally be used after the froxel approach ends but didn't realise that it's not very useful for close range fog by itself or on mobile.

For long range fog, I think the RDR2 approach makes a lot of sense as something that extends the current volumetric fog solution.

I agree that it seems ideal as an extension of the current volumetric fog. I think it could be interesting to investigate adding the ability to either use custom fog volumes or a custom density function in the future as an extension of this implementation. A custom density function could be used to give the appearance of exponential height fog since a constant density would likely just obscure the sky, requiring the user to set sky affect to a very low value. Additionally, Godot's fog volumes process a lot less data than the volumes in RDR2(Density, Albedo, and Emission vs Scattering, Absorption, Phase, Emission, Ambient intensity, and Density). Given that their solution was fast enough to double as a cloud system I think that reading from Godot's fog volumes shouldn't have many performance issues. If that does end up being the case, then it might be useful to allow the froxel fog and ray marched fog to affect different layers to reduce the amount of volumes being processed or have different passes in the fog shader(similar to the different passes in sky shaders) where at a long distance or when being used for ray marching the fog volume could branch to a cheaper shader. Branching would be done on a per-volume basis to avoid branch issues in the shader.

clayjohn commented 11 months ago

Well, again, let's be clear about how their system works so you aren't setting unfair expectations. Their cloud system and Fog Volume system are two different systems. They are not ray marching Fog volumes to create clouds. The cloud system uses the HZD approach that everyone else is using these days. Which is a heirarchical ray march of implicit volume data.

The RDR2 system is really nice and really efficient, but you can't expect it to do more than it actually does. Setting the expectation that we can redesign it to be just as flexible as the froxel approach, and still as fast as the non-froxel approach is not realistic.

Remember, the RDR2 system was used for 2 things, god rays from the sun, and for marching the clouds. It wasn't used for local fog volumes, or local lights. We could probably adapt a similar system, but we would have to make similar tradeoffs we want to have acceptable performance.

InitialCon commented 11 months ago

Apologies for misunderstanding the presentation. I had assumed that the fog and clouds were done in the same ray marching shader since they cover them at roughly the same time in the presentation. With all of this in mind I can see how keeping the proposal as it is now would cause unrealistic expectations. Should I edit the original post to better outline what an implementation would actually entail?