From 1da732af358a8775fcfa157c99facdbcb7b40221 Mon Sep 17 00:00:00 2001
From: Hendrik Brucker <hendrik.brucker@mail.de>
Date: Wed, 8 Dec 2021 22:17:09 +0100
Subject: [PATCH] Fix volumetric fog in combination with spotlights

---
 .../renderer_rd/renderer_scene_render_rd.cpp  |  4 +--
 .../shaders/volumetric_fog_process.glsl       | 25 ++++++++++++++-----
 2 files changed, 21 insertions(+), 8 deletions(-)

diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
index ae8d91a73bb..d6452346721 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -4417,9 +4417,9 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
 
 		uint32_t cluster_screen_width = (rb->width - 1) / cluster_size + 1;
 		uint32_t cluster_screen_height = (rb->height - 1) / cluster_size + 1;
-		params.cluster_type_size = cluster_screen_width * cluster_screen_height * (32 + 32);
-		params.cluster_width = cluster_screen_width;
 		params.max_cluster_element_count_div_32 = max_cluster_elements / 32;
+		params.cluster_type_size = cluster_screen_width * cluster_screen_height * (params.max_cluster_element_count_div_32 + 32);
+		params.cluster_width = cluster_screen_width;
 
 		params.screen_size[0] = rb->width;
 		params.screen_size[1] = rb->height;
diff --git a/servers/rendering/renderer_rd/shaders/volumetric_fog_process.glsl b/servers/rendering/renderer_rd/shaders/volumetric_fog_process.glsl
index 747f88960c0..999e8d0844f 100644
--- a/servers/rendering/renderer_rd/shaders/volumetric_fog_process.glsl
+++ b/servers/rendering/renderer_rd/shaders/volumetric_fog_process.glsl
@@ -581,16 +581,29 @@ void main() {
 
 						if (spot_lights.data[light_index].shadow_enabled) {
 							//has shadow
-							vec4 v = vec4(view_pos, 1.0);
+							vec4 uv_rect = spot_lights.data[light_index].atlas_rect;
+							vec2 flip_offset = spot_lights.data[light_index].direction.xy;
 
-							vec4 splane = (spot_lights.data[light_index].shadow_matrix * v);
-							splane /= splane.w;
+							vec3 local_vert = (spot_lights.data[light_index].shadow_matrix * vec4(view_pos, 1.0)).xyz;
 
-							float depth = texture(sampler2D(shadow_atlas, linear_sampler), splane.xy).r;
+							float shadow_len = length(local_vert); //need to remember shadow len from here
+							vec3 shadow_sample = normalize(local_vert);
 
-							shadow_attenuation = exp(min(0.0, (depth - splane.z)) / spot_lights.data[light_index].inv_radius * spot_lights.data[light_index].shadow_volumetric_fog_fade);
+							if (shadow_sample.z >= 0.0) {
+								uv_rect.xy += flip_offset;
+							}
+
+							shadow_sample.z = 1.0 + abs(shadow_sample.z);
+							vec3 pos = vec3(shadow_sample.xy / shadow_sample.z, shadow_len - spot_lights.data[light_index].shadow_bias);
+							pos.z *= spot_lights.data[light_index].inv_radius;
+
+							pos.xy = pos.xy * 0.5 + 0.5;
+							pos.xy = uv_rect.xy + pos.xy * uv_rect.zw;
+
+							float depth = texture(sampler2D(shadow_atlas, linear_sampler), pos.xy).r;
+
+							shadow_attenuation = exp(min(0.0, (depth - pos.z)) / spot_lights.data[light_index].inv_radius * spot_lights.data[light_index].shadow_volumetric_fog_fade);
 						}
-
 						total_light += light * attenuation * shadow_attenuation * henyey_greenstein(dot(normalize(light_rel_vec), normalize(view_pos)), params.phase_g);
 					}
 				}