bevy icon indicating copy to clipboard operation
bevy copied to clipboard

Add Distance Fog support

Open coreh opened this issue 3 years ago • 13 comments

Objective

  • Add support for the “classic” distance fog effect, as well as a more advanced atmospheric fog effect.

Solution

This PR:

  • Introduces a new FogSettings component that controls distance fog per-camera.
  • Adds support for three widely used “traditional” fog falloff modes: Linear, Exponential and ExponentialSquared, as well as a more advanced Atmospheric fog;
  • Adds support for directional light influence over fog color;
  • Extracts fog via ExtractComponent, then uses a prepare system that sets up a new dynamic uniform struct (Fog), similar to other mesh view types;
  • Renders fog in PBR material shader, as a final adjustment to the output_color, after PBR is computed (but before tone mapping);
  • Adds a new StandardMaterial flag to enable fog; (fog_enabled)
  • Adds convenience methods for easier artistic control when creating non-linear fog types;
  • Adds documentation around fog.

Changelog

Added

  • Added support for distance-based fog effects for PBR materials, controllable per-camera via the new FogSettings component;
  • Added FogFalloff enum for selecting between three widely used “traditional” fog falloff modes: Linear, Exponential and ExponentialSquared, as well as a more advanced Atmospheric fog;

coreh avatar Oct 29 '22 22:10 coreh

Thanks for the speedy CR! Added additional documentation comments.

I do wonder if we can make these more... modular? Having to include this sort of effect in bevy_pbr, and adding a bitflag to StandardMaterial definitely feels like it might get messy.

Maybe? There are already some things that affect, for example, lights that end up as bitflags there instead of special light-related components, so it's not completely out of place, but maybe there's indeed a cleaner way? I think what Wireframe is doing is maybe too heavy handed for this, but I'm new to the bevy way of doing things. Is there some precedent in how to modularize stuff like this?

Re: PBR shader, I added it there after some conversations on #rendering-dev on Discord, since if I understand it correctly depth-based post processing effects are not yet possible. (or not straightforward?) One benefit is that it allows us to handle fog on transparency correctly, which would be trickier with post processing.

I also got some feedback also in #rendering-dev about maybe moving Fog itself from a resource to a component, so that it can vary per-camera, not sure how to implement extraction for that case.

coreh avatar Oct 30 '22 01:10 coreh

Maybe? There are already some things that affect, for example, lights that end up as bitflags there instead of special light-related components, so it's not completely out of place, but maybe there's indeed a cleaner way?

Yep, not a problem for this PR, but wanted to surface the idea so we start chewing on it.

I also got some feedback also in #rendering-dev about maybe moving Fog itself from a resource to a component, so that it can vary per-camera, not sure how to implement extraction for that case.

Oh I rather like that. IIRC there's an ExtractComponentPlugin that should point you in the right direction.

alice-i-cecile avatar Oct 30 '22 01:10 alice-i-cecile

IIRC there's an ExtractComponentPlugin that should point you in the right direction.

Thanks! That was a good starting point.

Fog is now a Component and can be set independently per-camera. Here's a modified split_screen example running with two different fogs, one for each camera:

Screenshot 2022-11-01 at 02 19 21

I also consolidated the fog setup code into a single FogPlugin.


Some ergonomics/usability questions:

  1. Now that we can add/remove fog from cameras by simply adding and removing the component, does it still make sense to have a FogMode::Off variant? Is there some precedent to Components that are “added but disabled”, and does that feel idiomatic?
  2. If we decide to keep the Off variant, should it still be the default? Or should we make one of the other variants a more “useful” out-of-the-box default?
  3. Should we keep the short name Fog or make it something more specific (e.g. DistanceFog)? That's longer to type/remember but could makes sense in a future where there are other fog effects which are not added to the camera, but rather as separate, independent entities with Transform/GlobalTransform (e.g. LinearFog, SphericalFog or even VolumetricFog). That's kinda like lights work currently, naming-wise.

coreh avatar Nov 01 '22 05:11 coreh

Could you add an example that show off the various fog modes? Maybe cycle through them on a timer, or on a key press

mockersf avatar Nov 01 '22 08:11 mockersf

  1. I would remove the Off variant, and make the component not-added by default.
  2. I would go with the more verbose option, something like DistanceFogSettings (and DistanceFogPlugin).

In general, this is the patterns I've been seeing for post-processing effects recently:

  • Make an ExamplePlugin plugin, that's either loaded by default as part of PbrPlugin (BloomPlugin), or optionally added by the user (FXAAPlugin)
  • Make an ExampleSettings component to be applied to any view you want the effect on, whose presence enables the effect and which holds the settings (no off switch on this component).
  • Optionally, add a setting to PbrPlugin or somewhere similar to globally toggle the effect off.

JMS55 avatar Nov 01 '22 18:11 JMS55

Added an interactive example, where you can tweak the parameters:

https://user-images.githubusercontent.com/418473/199402028-8d651f3f-bf33-4afa-bd89-28d251880fdb.mov

coreh avatar Nov 02 '22 05:11 coreh

I would go with the more verbose option, something like DistanceFogSettings (and DistanceFogPlugin).

Renamed Fog to FogSettings. I want to propose this shorter name instead of DistanceFogSettings because I believe we can reuse these same settings for volumetric fogs, so in the future you could add FogCubeVolume { .. } and FogSettings { .. } to a non-camera entity to produce volumetric fog.

Also added the atmospheric extinction/inscattering falloff calculations (in a new Atmospheric fog falloff mode) and the sun pseudo-scattering math from Inigo Quilez's article, as suggested by @superdump:

Screenshot 2022-11-03 at 03 27 10 Screenshot 2022-11-03 at 03 27 06 Screenshot 2022-11-03 at 03 10 52 Screenshot 2022-11-03 at 03 15 29

coreh avatar Nov 03 '22 06:11 coreh

Also, any chance of adding a demo of the final mode to the example? :)

I'm thinking about maybe adding a separate demo, since the scene on the fog demo doesn't have sufficiently apart far/near objects for the different color channel-specific effect of extinction/in-scattering to be really noticeable.

There's also far too many parameters to control via keybindings UI, so I was thinking about maybe just having a few preset modes (e.g. day, sunset, very foggy day)

coreh avatar Nov 04 '22 04:11 coreh

Added an example showcasing the atmospheric fog effect, with toggles for disabling it, and also disabling the directional light influence.

image image image

coreh avatar Nov 04 '22 07:11 coreh

Did some reading about atmospheric scattering and visibility, and I now have a much better grasp of what the parameters do and how to control them.

Added some utility methods based on Koschmieder's visibility equation:

  • For FogFalloff::Exponential:

    • FogFalloff::from_visibility()
    • FogFalloff::from_visibility_contrast()
  • For FogFalloff::ExponentialSquared:

    • FogFalloff::from_visibility_squared()
    • FogFalloff::from_visibility_contrast_squared()
  • For FogFalloff::Atmospheric:

    • FogFalloff::from_visibility_color()
    • FogFalloff::from_visibility_colors()
    • FogFalloff::from_visibility_contrast_color()
    • FogFalloff::from_visibility_contrast_colors()

For atmospheric fog, these also convert colors into the right exponential scale needed for the extinction and inscattering parameters, (and invert the extinction color) so it's now much easier to have artistic control over the look of the fog:

https://github.com/bevyengine/bevy/blob/a35783a6ef9e7182c80ce74dfc2195910a368cd4/examples/3d/atmospheric_fog.rs#L26-L30

coreh avatar Nov 04 '22 21:11 coreh

I've removed this from the 0.9 milestone. Sadly its just too big to properly review this late in the game.

cart avatar Nov 12 '22 01:11 cart

That's completely understandable, no worries! 😉 I plan on using main for the foreseeable future for my project. Please take your time

coreh avatar Nov 12 '22 01:11 coreh

BTW, merged main, and confirmed that @aevyrie's now-merged PR #5264 also fixes the banding effect on the fog:

Before

image

After

image

coreh avatar Nov 12 '22 01:11 coreh

FYI, https://github.com/bevyengine/bevy/pull/6707 should reduce excess noise in darker areas of banded fog, when not using HDR.

Upon pixel peeping, the dithered screenshot above has a lot more noise than it should.

aevyrie avatar Nov 21 '22 01:11 aevyrie

Hey 👋 Sorry for taking a while to reply; I didn't have a lot of bandwidth for open source due to holidays/new year. Catching up now!

coreh avatar Jan 15 '23 02:01 coreh

@superdump @robtfm Applied feedback and updated to the latest main. Added tweaks so that the shadows still look correct, as we now have cascade shadow maps (#7064 🎉!)

coreh avatar Jan 28 '23 19:01 coreh