diff --git a/doc/classes/Camera3D.xml b/doc/classes/Camera3D.xml index 06e2f83f055b..b6fad99121b8 100644 --- a/doc/classes/Camera3D.xml +++ b/doc/classes/Camera3D.xml @@ -167,6 +167,7 @@ The distance to the far culling boundary for this camera relative to its local Z axis. + [b]Note:[/b] When [member Environment.fog_enabled] is [code]true[/code], this is used as a base for open world fog fading (with fog starting at 50% of the Z far distance). The camera's field of view angle (in degrees). Only applicable in perspective mode. Since [member keep_aspect] locks one axis, [code]fov[/code] sets the other axis' field of view angle. diff --git a/doc/classes/Environment.xml b/doc/classes/Environment.xml index c3d1dc4ab63b..b1405dca636a 100644 --- a/doc/classes/Environment.xml +++ b/doc/classes/Environment.xml @@ -99,6 +99,7 @@ If [code]true[/code], fog effects are enabled. + [b]Note:[/b] Enabling fog automatically fades starting from 50% of the [member Camera3D.far] distance, regardless of [member fog_depth_density]. This is used for open world fog fading. To disable this, increase the camera's [member Camera3D.far] property. The height at which the height fog effect begins. diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl index e4628b2d5a15..11acce34bacd 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl @@ -530,7 +530,16 @@ vec4 fog_process(vec3 vertex) { } } - float fog_amount = 1.0 - exp(min(0.0, -length(vertex) * scene_data.fog_density)); + // Quadratic fade off to the Z far distance (for open world fog fading). + // Not physically accurate, but prevents visible sudden cutoffs near the Z far clip plane. + // This starts at 50% of the Z far distance, which is a good compromise between visibility + // and smoothness. + float fog_amount_quad = pow(smoothstep(scene_data.z_far * 0.5, scene_data.z_far, length(vertex)), 2.0); + + // Exponential fog (physically accurate). + float fog_amount_exp = 1.0 - exp(min(0.0, -length(vertex) * scene_data.fog_density)); + + float fog_amount = max(fog_amount_quad, fog_amount_exp); if (abs(scene_data.fog_height_density) >= 0.0001) { float y = (scene_data.camera_matrix * vec4(vertex, 1.0)).y;