godot
godot copied to clipboard
Add optional depth fog to Environment
This is a feature addition that accomplishes godotengine/godot-proposals#4619, addresses the needs of godotengine/godot-proposals#3429, and supercedes the implementation in #55388 by partially restoring some of the depth fog parameters in the Godot 3.x Environment.
The following properties are added to the Environment resource:
-
fog_depth_enabled
: used in a specialization constant in the relevant scene shaders. This addresses the performance caveat discussed in #55388 by ensuring that when only exponential fog is used, the branch is never present in the compiled program. It is not possible to use quadratic fog exclusively at the shader level in this implementation, but you can set the parameters of the environment such that the exponential fog density is 0 while still having quadratic fog if you must have no exponential fog at all. During project conversion, this property should be set to true if fog was enabled, the new fog density should be set to 0, and the sky affect scale should also be set to 0. -
fog_depth_curve
: Same as in Godot 3.x -
fog_depth_density
: replaces the alpha value offog_depth_color
in Godot 3.x. Project conversion should take the fog color's alpha and put it in this property instead. -
fog_depth_begin
: Same as in Godot 3.x -
fog_depth_end
: Same as in Godot 3.x
The depth fog interacts with the new fog model gracefully, supporting sun scattering and the improved light transmission. It does not affect the behavior of exponential fog with depth fog disabled at all.
Implementations are provided for gles3, vulkan mobile and vulkan clustered. Although, in the commit this branch is based on, vulkan mobile's support for fog is broken (there is already an MR to fix it) and gles3 seems to be very broken regardless.
Todo:
- [x] Documentation entries for new Environment properties
- [ ] Changes to the project convertor to migrate the old fog properties
Do note that this implementation fails to hide Z-far effectively.
Here is a Plane (default camera settings, fog settings in pic)
See banding visible on the Left and Right of the Fog Circle in this Image which is actually not fully faded Plane:
The effect is clearer when inverting the Fog like here:
Do note that this is also the case in the above mentioned PR, and the issue seems to be due to aerial perspective.
Do note that this is also the case in the above mentioned PR, and the issue seems to be due to aerial perspective.
Aerial perspective uses a blurred version of the background sky, not an exact copy of the background sky. It's meant to mimic fog light scattering.
After talking with a friend about the lost fog features in the 4.0 beta, there is one more 3.x fog property that isn't present: light transmittance (fog_transmit_enabled
, fog_transmit_curve
). Volumetric fog appears to support this, but not distance fog anymore.
From a cursory glance on how fog light transmittance is implemented in 3.x, it relies on the light information, but fog is evaluated before lighting in 4.0 rather than after it in 3.x; a comment notes that this is to maximize VGPR occupancy. I could perform the transmittance after lighting in a specialization constant branch to restore the property, but I am wary to add another specialization permutation to the standard scene shader too. Curious what y'all's thoughts are.
We discussed this in today's PR review meeting. The main idea has been approved for implementation but the consensus was to expose the feature a little bit differently. Instead of exposing both exponential fog and depth fog side by side they should be exposed as options toggleable in the shader with a specialization constant (so only one version is compiled).
In other words, we would add a FogType enum that can be used to select between exponential and depth-based fog. In the Environment you would only see the settings related to the type of fog you have selected. Then in the shader the specialization constant would be used to toggle between exponential fog and the depth fog so only one is enabled at a time and the user doesn't pay the cost for having both.
After talking with a friend about the lost fog features in the 4.0 beta, there is one more 3.x fog property that isn't present: light transmittance (fog_transmit_enabled, fog_transmit_curve). Volumetric fog appears to support this, but not distance fog anymore.
From a cursory glance on how fog light transmittance is implemented in 3.x, it relies on the light information, but fog is evaluated before lighting in 4.0 rather than after it in 3.x; a comment notes that this is to maximize VGPR occupancy. I could perform the transmittance after lighting in a specialization constant branch to restore the property, but I am wary to add another specialization permutation to the standard scene shader too. Curious what y'all's thoughts are.
fog_transmit
was renamed tosun_scatter
in 4.0. It works essentially the same way as it used to and is used to produce the same effect. So there is not need to add fog_transmit
back in.
We discussed this in today's PR review meeting. The main idea has been approved for implementation but the consensus was to expose the feature a little bit differently. Instead of exposing both exponential fog and depth fog side by side they should be exposed as options toggleable in the shader with a specialization constant (so only one version is compiled).
In other words, we would add a FogType enum that can be used to select between exponential and depth-based fog. In the Environment you would only see the settings related to the type of fog you have selected. Then in the shader the specialization constant would be used to toggle between exponential fog and the depth fog so only one is enabled at a time and the user doesn't pay the cost for having both.
After talking with a friend about the lost fog features in the 4.0 beta, there is one more 3.x fog property that isn't present: light transmittance (fog_transmit_enabled, fog_transmit_curve). Volumetric fog appears to support this, but not distance fog anymore. From a cursory glance on how fog light transmittance is implemented in 3.x, it relies on the light information, but fog is evaluated before lighting in 4.0 rather than after it in 3.x; a comment notes that this is to maximize VGPR occupancy. I could perform the transmittance after lighting in a specialization constant branch to restore the property, but I am wary to add another specialization permutation to the standard scene shader too. Curious what y'all's thoughts are.
fog_transmit
was renamed tosun_scatter
in 4.0. It works essentially the same way as it used to and is used to produce the same effect. So there is not need to addfog_transmit
back in.
Sounds good, just make sure to try to implement sky affect from exponential fog to depth fog.
@HybridEidolon Do you think you will have a chance to update this in the next couple of weeks?
Do you think you will have a chance to update this in the next couple of weeks?
@HybridEidolon Bump :slightly_smiling_face:
Sorry for the long delay on this. I'm split between multiple projects at the moment. I do have a vested interested in finishing this out with the FogType enum request, but I don't think I'll really be able to work on it until after 4.0 is released.
Sorry for the long delay on this. I'm split between multiple projects at the moment. I do have a vested interested in finishing this out with the FogType enum request, but I don't think I'll really be able to work on it until after 4.0 is released.
No worries! Take your time
@HybridEidolon Do you have time to rebase and update this pull request? If you don't, it's fine – let us know and someone else should be able to salvage this PR while keeping you as a co-author.
I do not. Anyone is free to take over if they'd like! The only major changes needed are the shader specialization to be either-or for the fog type and setting up the appropriate enum needed in the Environment.
Will there be a way to exclude meshes when using the depth fog, like was possible in 3.x by setting a mesh to unshaded? This is a very important feature for anyone using mesh based sky boxes/clouds, which were really common with old school map designs and has been the biggest problem some friends and I have run into with a porting project we've been working on for some old PS1 games when considering moving it over to 4.x.
Will there be a way to exclude meshes when using the depth fog, like was possible in 3.x by setting a mesh to unshaded?
See https://github.com/godotengine/godot/issues/56374. Given how controversial this is in practice, I think this needs a dedicated render_mode
rather than relying on shading mode being Unshaded. There's render_mode disable_fog
in sky shaders, but not in spatial shaders.
See #56374. Given how controversial this is in practice, I think this needs a dedicated
render_mode
rather than relying on shading mode being Unshaded. There'srender_mode disable_fog
in sky shaders, but not in spatial shaders.
Ya, a new shading mode would be fine, I only mentioned unshaded as a point of reference to how we handle things currently in 3.x. Though I wonder if the problem in that issue will also be relevant for the depth fog, since I'm guessing it won't be using the same approach as the volumetric fog. Might be worth some testing before a new mode is added to see if it is necessary or not.
But anyway, I just wanted to bring up the need for a way to have objects that aren't touched by the fog. Here is an old side-by-side comparison from when we first took a crack at porting the project and found the fog setup in 4 to be a deal breaker for us. Both for the problem this proposal addresses, but also not being able to use sky boxes with it.
If anyone may tell me, what are the possible workarounds for this type of fog then? I was waiting for this as a feature to start working on a project but it's becoming apparent that it is stuck in limbo.
If anyone may tell me, what are the possible workarounds for this type of fog then?
See https://github.com/godotengine/godot/pull/55388#issuecomment-1120011889 (works on all rendering methods) or https://github.com/godotengine/godot/pull/55388#issuecomment-1358958782 (requires volumetric fog, so it requires Forward+).
Here's use-case example. Lack of basic "linear fog" with start/end fade is currently stopping this game being ported from Unity. It's a basic feature you can even see in Starfield's interiors. Default Godot 4.1 fog overlaps far too close to the camera.
Here's use-case example. Lack of basic "linear fog" with start/end fade is currently stopping this game being ported from Unity. It's a basic feature you can even see in Starfield's interiors. Default Godot 4.1 fog overlaps far too close to the camera.
We are well-aware of example use cases now, but we still need someone to salvage this pull request 🙂
I tested a simple merge with adjusting values in the conflict I had, everything came out fine here.
my branch: https://github.com/expressobits/godot/tree/distance-fog
However, these values were added to main
uint32_t camera_visible_layers;
uint32_t pad1;
uint32_t pad2;
uint32_t pad3;
And these to distance_fog
float fog_sun_scatter;
float pad1;
float pad3;
float pad4;
Which makes me think that the editor values might be editing something already used elsewhere in the shader, I don't know exactly what the rule is for these pad* properties
Which makes me think that the editor values might be editing something already used elsewhere in the shader, I don't know exactly what the rule is for these pad* properties
You only have to keep pad1
and pad2
in the shader – you don't need 6 pad values. Alignment needs to be performed over 16-byte regions. A uint32_t
or float
is 4 bytes.
Implementation note for whoever takes over this PR. The last remaining details are:
- Rebase on top of master and resolve conflicts
- Change the API a bit to add a "fog mode" instead of "depth enabled" Then use either the depth mode or the physically based fog based on that setting, don't use both types of fog at once.
@scriptsengineer Are you available to perform the changes requested above?
@scriptsengineer Are you available to perform the changes requested above?
Yes, I intend to take it easy this week.
- Rebase on top of master and resolve conflicts
I resolved the conflict with master again, updated with the latest version of master https://github.com/expressobits/godot/tree/distance-fog Still trying to study ways to remove the excessive pads.
- Change the API a bit to add a "fog mode" instead of "depth enabled" Then use either the depth mode or the physically based fog based on that setting, don't use both types of fog at once.
I intend to study more about how to create the option, but my understanding of the source code is still small, I want to leave this open in case anyone wants to take it.
Update: ✅Cleaned unnecessary pads 🚧I put an fog mode option with an enum, the only thing left to do is connect it with shaders.
@clayjohn Is there a justification for a user not to use both fogs together? It seems to me that the fog by distance is classified as the fog by height works, something that is added to the current fog.
@clayjohn Is there a justification for a user not to use both fogs together? It seems to me that the fog by distance is classified as the fog by height works, something that is added to the current fog.
A mix of performance and simplicity in the editor. Exposing both together is kind of messy, bad for performance, and so far no one has suggested that they need it for their project.
Depth Begin should ideally support negative numbers, to simulate being in the fog, like Exponential. Without that, someone might need both enabled.
Finished 🚀
✅ Merged successfully
✅ Removed unnecessary pads
✅ Added enum option in the environment inspector
✅ Added conditional in shader to execute correct fog mode I was wondering if there is a better way to define this if scene.glsl:
#ifndef DISABLE_FOG_DEPTH
if (scene_data.fog_mode == 1) {
float fog_far = scene_data.fog_depth_end > 0.0 ? scene_data.fog_depth_end : scene_data.z_far;
float fog_z = smoothstep(scene_data.fog_depth_begin, fog_far, length(vertex));
float fog_quad_amount = pow(fog_z, scene_data.fog_depth_curve) * scene_data.fog_density;
fog_amount = fog_quad_amount;
}
#else
if (scene_data.fog_mode == 0) {
fog_amount = 1 - exp(min(0.0, -length(vertex) * scene_data.fog_density));
}
✅ Possible to add negative values in fog begin
https://github.com/godotengine/godot/assets/1673249/f44b9a2f-b946-4e59-99d3-b42ebce7510d
Looking really nice. Does height works with depth?