Explorar el Código

Add fog to sky shaders

clayjohn hace 5 años
padre
commit
9d341acf2d

+ 3 - 0
scene/resources/environment.cpp

@@ -134,6 +134,7 @@ Color Environment::get_ambient_light_color() const {
 void Environment::set_ambient_source(AmbientSource p_source) {
 	ambient_source = p_source;
 	_update_ambient_light();
+	_change_notify();
 }
 
 Environment::AmbientSource Environment::get_ambient_source() const {
@@ -161,6 +162,7 @@ float Environment::get_ambient_light_sky_contribution() const {
 void Environment::set_reflection_source(ReflectionSource p_source) {
 	reflection_source = p_source;
 	_update_ambient_light();
+	_change_notify();
 }
 
 Environment::ReflectionSource Environment::get_reflection_source() const {
@@ -758,6 +760,7 @@ void Environment::_update_volumetric_fog() {
 void Environment::set_volumetric_fog_enabled(bool p_enable) {
 	volumetric_fog_enabled = p_enable;
 	_update_volumetric_fog();
+	_change_notify();
 }
 
 bool Environment::is_volumetric_fog_enabled() const {

+ 2 - 2
servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp

@@ -1171,7 +1171,7 @@ void RasterizerEffectsRD::cubemap_filter(RID p_source_cubemap, Vector<RID> p_des
 	RD::get_singleton()->compute_list_end();
 }
 
-void RasterizerEffectsRD::render_sky(RD::DrawListID p_list, float p_time, RID p_fb, RID p_samplers, RID p_lights, RenderPipelineVertexFormatCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const CameraMatrix &p_camera, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position) {
+void RasterizerEffectsRD::render_sky(RD::DrawListID p_list, float p_time, RID p_fb, RID p_samplers, RID p_fog, RenderPipelineVertexFormatCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const CameraMatrix &p_camera, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position) {
 	SkyPushConstant sky_push_constant;
 
 	zeromem(&sky_push_constant, sizeof(SkyPushConstant));
@@ -1198,7 +1198,7 @@ void RasterizerEffectsRD::render_sky(RD::DrawListID p_list, float p_time, RID p_
 		RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_uniform_set, 1);
 	}
 	RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_texture_set, 2);
-	RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_lights, 3);
+	RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_fog, 3);
 
 	RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
 

+ 1 - 1
servers/rendering/rasterizer_rd/rasterizer_effects_rd.h

@@ -638,7 +638,7 @@ public:
 	void roughness_limit(RID p_source_normal, RID p_roughness, const Size2i &p_size, float p_curve);
 	void cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size);
 	void cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array);
-	void render_sky(RD::DrawListID p_list, float p_time, RID p_fb, RID p_samplers, RID p_lights, RenderPipelineVertexFormatCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const CameraMatrix &p_camera, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position);
+	void render_sky(RD::DrawListID p_list, float p_time, RID p_fb, RID p_samplers, RID p_fog, RenderPipelineVertexFormatCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const CameraMatrix &p_camera, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position);
 
 	void screen_space_reflection(RID p_diffuse, RID p_normal_roughness, RS::EnvironmentSSRRoughnessQuality p_roughness_quality, RID p_blur_radius, RID p_blur_radius2, RID p_metallic, const Color &p_metallic_mask, RID p_depth, RID p_scale_depth, RID p_scale_normal, RID p_output, RID p_output_blur, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const CameraMatrix &p_camera);
 	void merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_base, RID p_reflection);

+ 47 - 21
servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp

@@ -1156,8 +1156,19 @@ void RasterizerSceneHighEndRD::_setup_environment(RID p_environment, RID p_rende
 
 		if (render_buffers_has_volumetric_fog(p_render_buffers)) {
 			scene_state.ubo.volumetric_fog_enabled = true;
-			scene_state.ubo.volumetric_fog_inv_length = 1.0 / render_buffers_get_volumetric_fog_end(p_render_buffers);
-			scene_state.ubo.volumetric_fog_detail_spread = 1.0 / render_buffers_get_volumetric_fog_detail_spread(p_render_buffers); //reverse lookup
+			float fog_end = render_buffers_get_volumetric_fog_end(p_render_buffers);
+			if (fog_end > 0.0) {
+				scene_state.ubo.volumetric_fog_inv_length = 1.0 / fog_end;
+			} else {
+				scene_state.ubo.volumetric_fog_inv_length = 1.0;
+			}
+
+			float fog_detail_spread = render_buffers_get_volumetric_fog_detail_spread(p_render_buffers); //reverse lookup
+			if (fog_detail_spread > 0.0) {
+				scene_state.ubo.volumetric_fog_detail_spread = 1.0 / fog_detail_spread;
+			} else {
+				scene_state.ubo.volumetric_fog_detail_spread = 1.0;
+			}
 		}
 	}
 #if 0
@@ -1696,6 +1707,7 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor
 	}
 	RID radiance_uniform_set;
 	bool draw_sky = false;
+	bool draw_sky_fog_only = false;
 
 	Color clear_color;
 	bool keep_color = false;
@@ -1711,12 +1723,20 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor
 				clear_color.r *= bg_energy;
 				clear_color.g *= bg_energy;
 				clear_color.b *= bg_energy;
+				if (render_buffers_has_volumetric_fog(p_render_buffer) || environment_is_fog_enabled(p_environment)) {
+					draw_sky_fog_only = true;
+					storage->material_set_param(sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear()));
+				}
 			} break;
 			case RS::ENV_BG_COLOR: {
 				clear_color = environment_get_bg_color(p_environment);
 				clear_color.r *= bg_energy;
 				clear_color.g *= bg_energy;
 				clear_color.b *= bg_energy;
+				if (render_buffers_has_volumetric_fog(p_render_buffer) || environment_is_fog_enabled(p_environment)) {
+					draw_sky_fog_only = true;
+					storage->material_set_param(sky_scene_state.fog_material, "clear_color", Variant(clear_color.to_linear()));
+				}
 			} break;
 			case RS::ENV_BG_SKY: {
 				draw_sky = true;
@@ -1733,18 +1753,19 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor
 			}
 		}
 		// setup sky if used for ambient, reflections, or background
-		if (draw_sky || environment_get_reflection_source(p_environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_environment) == RS::ENV_AMBIENT_SOURCE_SKY) {
+		if (draw_sky || draw_sky_fog_only || environment_get_reflection_source(p_environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_environment) == RS::ENV_AMBIENT_SOURCE_SKY) {
+			RENDER_TIMESTAMP("Setup Sky");
+			CameraMatrix projection = p_cam_projection;
+			if (p_reflection_probe.is_valid()) {
+				CameraMatrix correction;
+				correction.set_depth_correction(true);
+				projection = correction * p_cam_projection;
+			}
+
+			_setup_sky(p_environment, p_render_buffer, projection, p_cam_transform, screen_size);
+
 			RID sky = environment_get_sky(p_environment);
 			if (sky.is_valid()) {
-				RENDER_TIMESTAMP("Setup Sky");
-				CameraMatrix projection = p_cam_projection;
-				if (p_reflection_probe.is_valid()) {
-					CameraMatrix correction;
-					correction.set_depth_correction(true);
-					projection = correction * p_cam_projection;
-				}
-
-				_setup_sky(p_environment, p_cam_transform.origin, screen_size);
 				_update_sky(p_environment, projection, p_cam_transform);
 				radiance_uniform_set = sky_get_radiance_uniform_set_rd(sky, default_shader_rd, RADIANCE_UNIFORM_SET);
 			} else {
@@ -1813,8 +1834,8 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor
 	bool can_continue_depth = !scene_state.used_depth_texture && !using_ssr && !using_sss;
 
 	{
-		bool will_continue_color = (can_continue_color || draw_sky || debug_giprobes || debug_sdfgi_probes);
-		bool will_continue_depth = (can_continue_depth || draw_sky || debug_giprobes || debug_sdfgi_probes);
+		bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only || debug_giprobes || debug_sdfgi_probes);
+		bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only || debug_giprobes || debug_sdfgi_probes);
 
 		//regular forward for now
 		Vector<Color> c;
@@ -1841,8 +1862,8 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor
 
 	if (debug_giprobes) {
 		//debug giprobes
-		bool will_continue_color = (can_continue_color || draw_sky);
-		bool will_continue_depth = (can_continue_depth || draw_sky);
+		bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only);
+		bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only);
 
 		CameraMatrix dc;
 		dc.set_depth_correction(true);
@@ -1856,8 +1877,8 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor
 
 	if (debug_sdfgi_probes) {
 		//debug giprobes
-		bool will_continue_color = (can_continue_color || draw_sky);
-		bool will_continue_depth = (can_continue_depth || draw_sky);
+		bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only);
+		bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only);
 
 		CameraMatrix dc;
 		dc.set_depth_correction(true);
@@ -1867,7 +1888,7 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor
 		RD::get_singleton()->draw_list_end();
 	}
 
-	if (draw_sky) {
+	if (draw_sky || draw_sky_fog_only) {
 		RENDER_TIMESTAMP("Render Sky");
 
 		CameraMatrix projection = p_cam_projection;
@@ -2532,8 +2553,13 @@ void RasterizerSceneHighEndRD::_update_render_buffers_uniform_set(RID p_render_b
 			RD::Uniform u;
 			u.binding = 10;
 			u.type = RD::UNIFORM_TYPE_TEXTURE;
-			RID vfog = render_buffers_get_volumetric_fog_texture(p_render_buffers);
-			if (vfog.is_null()) {
+			RID vfog = RID();
+			if (p_render_buffers.is_valid() && render_buffers_has_volumetric_fog(p_render_buffers)) {
+				vfog = render_buffers_get_volumetric_fog_texture(p_render_buffers);
+				if (vfog.is_null()) {
+					vfog = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
+				}
+			} else {
 				vfog = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
 			}
 			u.ids.push_back(vfog);

+ 280 - 122
servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp

@@ -2066,22 +2066,33 @@ RID RasterizerSceneRD::sky_get_material(RID p_sky) const {
 void RasterizerSceneRD::_draw_sky(bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform) {
 	ERR_FAIL_COND(!is_environment(p_environment));
 
+	SkyMaterialData *material = nullptr;
+
 	Sky *sky = sky_owner.getornull(environment_get_sky(p_environment));
-	ERR_FAIL_COND(!sky);
 
-	RID sky_material = sky_get_material(environment_get_sky(p_environment));
+	RID sky_material;
 
-	SkyMaterialData *material = nullptr;
+	RS::EnvironmentBG background = environment_get_background(p_environment);
 
-	if (sky_material.is_valid()) {
-		material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY);
-		if (!material || !material->shader_data->valid) {
-			material = nullptr;
+	if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) {
+		ERR_FAIL_COND(!sky);
+		sky_material = sky_get_material(environment_get_sky(p_environment));
+
+		if (sky_material.is_valid()) {
+			material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY);
+			if (!material || !material->shader_data->valid) {
+				material = nullptr;
+			}
+		}
+
+		if (!material) {
+			sky_material = sky_shader.default_material;
+			material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY);
 		}
 	}
 
-	if (!material) {
-		sky_material = sky_shader.default_material;
+	if (background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) {
+		sky_material = sky_scene_state.fog_material;
 		material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY);
 	}
 
@@ -2121,7 +2132,7 @@ void RasterizerSceneRD::_draw_sky(bool p_can_continue_color, bool p_can_continue
 		clear_colors.push_back(Color(0.0, 0.0, 0.0));
 
 		RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->quarter_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
-		storage->get_effects()->render_sky(draw_list, time, sky->quarter_res_framebuffer, sky_scene_state.sampler_uniform_set, sky_scene_state.light_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
+		storage->get_effects()->render_sky(draw_list, time, sky->quarter_res_framebuffer, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
 		RD::get_singleton()->draw_list_end();
 	}
 
@@ -2134,149 +2145,191 @@ void RasterizerSceneRD::_draw_sky(bool p_can_continue_color, bool p_can_continue
 		clear_colors.push_back(Color(0.0, 0.0, 0.0));
 
 		RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->half_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
-		storage->get_effects()->render_sky(draw_list, time, sky->half_res_framebuffer, sky_scene_state.sampler_uniform_set, sky_scene_state.light_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
+		storage->get_effects()->render_sky(draw_list, time, sky->half_res_framebuffer, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
 		RD::get_singleton()->draw_list_end();
 	}
 
 	RenderPipelineVertexFormatCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_BACKGROUND];
 
-	RID texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_BACKGROUND);
+	RID texture_uniform_set;
+	if (sky) {
+		texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_BACKGROUND);
+	} else {
+		texture_uniform_set = sky_scene_state.fog_only_texture_uniform_set;
+	}
 
 	RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_fb, RD::INITIAL_ACTION_CONTINUE, p_can_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, p_can_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ);
-	storage->get_effects()->render_sky(draw_list, time, p_fb, sky_scene_state.sampler_uniform_set, sky_scene_state.light_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
+	storage->get_effects()->render_sky(draw_list, time, p_fb, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin);
 	RD::get_singleton()->draw_list_end();
 }
 
-void RasterizerSceneRD::_setup_sky(RID p_environment, const Vector3 &p_position, const Size2i p_screen_size) {
+void RasterizerSceneRD::_setup_sky(RID p_environment, RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform, const Size2i p_screen_size) {
 	ERR_FAIL_COND(!is_environment(p_environment));
 
+	SkyMaterialData *material = nullptr;
+
 	Sky *sky = sky_owner.getornull(environment_get_sky(p_environment));
-	ERR_FAIL_COND(!sky);
 
-	RID sky_material = sky_get_material(environment_get_sky(p_environment));
+	RID sky_material;
 
-	SkyMaterialData *material = nullptr;
+	SkyShaderData *shader_data = nullptr;
 
-	if (sky_material.is_valid()) {
-		material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY);
-		if (!material || !material->shader_data->valid) {
-			material = nullptr;
+	RS::EnvironmentBG background = environment_get_background(p_environment);
+
+	if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) {
+		ERR_FAIL_COND(!sky);
+		sky_material = sky_get_material(environment_get_sky(p_environment));
+
+		if (sky_material.is_valid()) {
+			material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY);
+			if (!material || !material->shader_data->valid) {
+				material = nullptr;
+			}
 		}
-	}
 
-	if (!material) {
-		sky_material = sky_shader.default_material;
-		material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY);
-	}
+		if (!material) {
+			sky_material = sky_shader.default_material;
+			material = (SkyMaterialData *)storage->material_get_data(sky_material, RasterizerStorageRD::SHADER_TYPE_SKY);
+		}
 
-	ERR_FAIL_COND(!material);
+		ERR_FAIL_COND(!material);
 
-	SkyShaderData *shader_data = material->shader_data;
+		shader_data = material->shader_data;
 
-	ERR_FAIL_COND(!shader_data);
+		ERR_FAIL_COND(!shader_data);
+	}
 
-	// Invalidate supbass buffers if screen size changes
-	if (sky->screen_size != p_screen_size) {
-		sky->screen_size = p_screen_size;
-		sky->screen_size.x = sky->screen_size.x < 4 ? 4 : sky->screen_size.x;
-		sky->screen_size.y = sky->screen_size.y < 4 ? 4 : sky->screen_size.y;
-		if (shader_data->uses_half_res) {
-			if (sky->half_res_pass.is_valid()) {
-				RD::get_singleton()->free(sky->half_res_pass);
-				sky->half_res_pass = RID();
+	if (sky) {
+		// Invalidate supbass buffers if screen size changes
+		if (sky->screen_size != p_screen_size) {
+			sky->screen_size = p_screen_size;
+			sky->screen_size.x = sky->screen_size.x < 4 ? 4 : sky->screen_size.x;
+			sky->screen_size.y = sky->screen_size.y < 4 ? 4 : sky->screen_size.y;
+			if (shader_data->uses_half_res) {
+				if (sky->half_res_pass.is_valid()) {
+					RD::get_singleton()->free(sky->half_res_pass);
+					sky->half_res_pass = RID();
+				}
+				_sky_invalidate(sky);
 			}
-			_sky_invalidate(sky);
-		}
-		if (shader_data->uses_quarter_res) {
-			if (sky->quarter_res_pass.is_valid()) {
-				RD::get_singleton()->free(sky->quarter_res_pass);
-				sky->quarter_res_pass = RID();
+			if (shader_data->uses_quarter_res) {
+				if (sky->quarter_res_pass.is_valid()) {
+					RD::get_singleton()->free(sky->quarter_res_pass);
+					sky->quarter_res_pass = RID();
+				}
+				_sky_invalidate(sky);
 			}
+		}
+
+		// Create new subpass buffers if necessary
+		if ((shader_data->uses_half_res && sky->half_res_pass.is_null()) ||
+				(shader_data->uses_quarter_res && sky->quarter_res_pass.is_null()) ||
+				sky->radiance.is_null()) {
 			_sky_invalidate(sky);
+			_update_dirty_skys();
 		}
-	}
 
-	// Create new subpass buffers if necessary
-	if ((shader_data->uses_half_res && sky->half_res_pass.is_null()) ||
-			(shader_data->uses_quarter_res && sky->quarter_res_pass.is_null()) ||
-			sky->radiance.is_null()) {
-		_sky_invalidate(sky);
-		_update_dirty_skys();
-	}
+		if (shader_data->uses_time && time - sky->prev_time > 0.00001) {
+			sky->prev_time = time;
+			sky->reflection.dirty = true;
+			RenderingServerRaster::redraw_request();
+		}
 
-	if (shader_data->uses_time && time - sky->prev_time > 0.00001) {
-		sky->prev_time = time;
-		sky->reflection.dirty = true;
-		RenderingServerRaster::redraw_request();
-	}
+		if (material != sky->prev_material) {
+			sky->prev_material = material;
+			sky->reflection.dirty = true;
+		}
 
-	if (material != sky->prev_material) {
-		sky->prev_material = material;
-		sky->reflection.dirty = true;
-	}
+		if (material->uniform_set_updated) {
+			material->uniform_set_updated = false;
+			sky->reflection.dirty = true;
+		}
 
-	if (material->uniform_set_updated) {
-		material->uniform_set_updated = false;
-		sky->reflection.dirty = true;
-	}
+		if (!p_transform.origin.is_equal_approx(sky->prev_position) && shader_data->uses_position) {
+			sky->prev_position = p_transform.origin;
+			sky->reflection.dirty = true;
+		}
 
-	if (!p_position.is_equal_approx(sky->prev_position) && shader_data->uses_position) {
-		sky->prev_position = p_position;
-		sky->reflection.dirty = true;
-	}
+		if (shader_data->uses_light) {
+			// Check whether the directional_light_buffer changes
+			bool light_data_dirty = false;
 
-	if (shader_data->uses_light || sky_scene_state.light_uniform_set.is_null()) {
-		// Check whether the directional_light_buffer changes
-		bool light_data_dirty = false;
-
-		if (sky_scene_state.directional_light_count != sky_scene_state.last_frame_directional_light_count) {
-			light_data_dirty = true;
-			for (uint32_t i = sky_scene_state.directional_light_count; i < sky_scene_state.max_directional_lights; i++) {
-				sky_scene_state.directional_lights[i].enabled = false;
-			}
-		}
-		if (!light_data_dirty) {
-			for (uint32_t i = 0; i < sky_scene_state.directional_light_count; i++) {
-				if (sky_scene_state.directional_lights[i].direction[0] != sky_scene_state.last_frame_directional_lights[i].direction[0] ||
-						sky_scene_state.directional_lights[i].direction[1] != sky_scene_state.last_frame_directional_lights[i].direction[1] ||
-						sky_scene_state.directional_lights[i].direction[2] != sky_scene_state.last_frame_directional_lights[i].direction[2] ||
-						sky_scene_state.directional_lights[i].energy != sky_scene_state.last_frame_directional_lights[i].energy ||
-						sky_scene_state.directional_lights[i].color[0] != sky_scene_state.last_frame_directional_lights[i].color[0] ||
-						sky_scene_state.directional_lights[i].color[1] != sky_scene_state.last_frame_directional_lights[i].color[1] ||
-						sky_scene_state.directional_lights[i].color[2] != sky_scene_state.last_frame_directional_lights[i].color[2] ||
-						sky_scene_state.directional_lights[i].enabled != sky_scene_state.last_frame_directional_lights[i].enabled ||
-						sky_scene_state.directional_lights[i].size != sky_scene_state.last_frame_directional_lights[i].size) {
-					light_data_dirty = true;
-					break;
+			if (sky_scene_state.ubo.directional_light_count != sky_scene_state.last_frame_directional_light_count) {
+				light_data_dirty = true;
+				for (uint32_t i = sky_scene_state.ubo.directional_light_count; i < sky_scene_state.max_directional_lights; i++) {
+					sky_scene_state.directional_lights[i].enabled = false;
+				}
+			}
+			if (!light_data_dirty) {
+				for (uint32_t i = 0; i < sky_scene_state.ubo.directional_light_count; i++) {
+					if (sky_scene_state.directional_lights[i].direction[0] != sky_scene_state.last_frame_directional_lights[i].direction[0] ||
+							sky_scene_state.directional_lights[i].direction[1] != sky_scene_state.last_frame_directional_lights[i].direction[1] ||
+							sky_scene_state.directional_lights[i].direction[2] != sky_scene_state.last_frame_directional_lights[i].direction[2] ||
+							sky_scene_state.directional_lights[i].energy != sky_scene_state.last_frame_directional_lights[i].energy ||
+							sky_scene_state.directional_lights[i].color[0] != sky_scene_state.last_frame_directional_lights[i].color[0] ||
+							sky_scene_state.directional_lights[i].color[1] != sky_scene_state.last_frame_directional_lights[i].color[1] ||
+							sky_scene_state.directional_lights[i].color[2] != sky_scene_state.last_frame_directional_lights[i].color[2] ||
+							sky_scene_state.directional_lights[i].enabled != sky_scene_state.last_frame_directional_lights[i].enabled ||
+							sky_scene_state.directional_lights[i].size != sky_scene_state.last_frame_directional_lights[i].size) {
+						light_data_dirty = true;
+						break;
+					}
 				}
 			}
+
+			if (light_data_dirty) {
+				RD::get_singleton()->buffer_update(sky_scene_state.directional_light_buffer, 0, sizeof(SkyDirectionalLightData) * sky_scene_state.max_directional_lights, sky_scene_state.directional_lights, true);
+
+				RasterizerSceneRD::SkyDirectionalLightData *temp = sky_scene_state.last_frame_directional_lights;
+				sky_scene_state.last_frame_directional_lights = sky_scene_state.directional_lights;
+				sky_scene_state.directional_lights = temp;
+				sky_scene_state.last_frame_directional_light_count = sky_scene_state.ubo.directional_light_count;
+				sky->reflection.dirty = true;
+			}
 		}
+	}
 
-		if (light_data_dirty || sky_scene_state.light_uniform_set.is_null()) {
-			RD::get_singleton()->buffer_update(sky_scene_state.directional_light_buffer, 0, sizeof(SkyDirectionalLightData) * sky_scene_state.max_directional_lights, sky_scene_state.directional_lights, true);
+	//setup fog variables
+	sky_scene_state.ubo.volumetric_fog_enabled = false;
+	if (p_render_buffers.is_valid()) {
+		if (render_buffers_has_volumetric_fog(p_render_buffers)) {
+			sky_scene_state.ubo.volumetric_fog_enabled = true;
 
-			if (sky_scene_state.light_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sky_scene_state.light_uniform_set)) {
-				RD::get_singleton()->free(sky_scene_state.light_uniform_set);
+			float fog_end = render_buffers_get_volumetric_fog_end(p_render_buffers);
+			if (fog_end > 0.0) {
+				sky_scene_state.ubo.volumetric_fog_inv_length = 1.0 / fog_end;
+			} else {
+				sky_scene_state.ubo.volumetric_fog_inv_length = 1.0;
 			}
 
-			Vector<RD::Uniform> uniforms;
-			{
-				RD::Uniform u;
-				u.binding = 0;
-				u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
-				u.ids.push_back(sky_scene_state.directional_light_buffer);
-				uniforms.push_back(u);
+			float fog_detail_spread = render_buffers_get_volumetric_fog_detail_spread(p_render_buffers); //reverse lookup
+			if (fog_detail_spread > 0.0) {
+				sky_scene_state.ubo.volumetric_fog_detail_spread = 1.0 / fog_detail_spread;
+			} else {
+				sky_scene_state.ubo.volumetric_fog_detail_spread = 1.0;
 			}
+		}
 
-			sky_scene_state.light_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_LIGHTS);
+		RID fog_uniform_set = render_buffers_get_volumetric_fog_sky_uniform_set(p_render_buffers);
 
-			RasterizerSceneRD::SkyDirectionalLightData *temp = sky_scene_state.last_frame_directional_lights;
-			sky_scene_state.last_frame_directional_lights = sky_scene_state.directional_lights;
-			sky_scene_state.directional_lights = temp;
-			sky_scene_state.last_frame_directional_light_count = sky_scene_state.directional_light_count;
-			sky->reflection.dirty = true;
+		if (fog_uniform_set != RID()) {
+			sky_scene_state.fog_uniform_set = fog_uniform_set;
+		} else {
+			sky_scene_state.fog_uniform_set = sky_scene_state.default_fog_uniform_set;
 		}
 	}
+
+	sky_scene_state.ubo.z_far = p_projection.get_z_far();
+	sky_scene_state.ubo.fog_enabled = environment_is_fog_enabled(p_environment);
+	sky_scene_state.ubo.fog_density = environment_get_fog_density(p_environment);
+	Color fog_color = environment_get_fog_light_color(p_environment).to_linear();
+	float fog_energy = environment_get_fog_light_energy(p_environment);
+	sky_scene_state.ubo.fog_light_color[0] = fog_color.r * fog_energy;
+	sky_scene_state.ubo.fog_light_color[1] = fog_color.g * fog_energy;
+	sky_scene_state.ubo.fog_light_color[2] = fog_color.b * fog_energy;
+	sky_scene_state.ubo.fog_sun_scatter = environment_get_fog_sun_scatter(p_environment);
+
+	RD::get_singleton()->buffer_update(sky_scene_state.uniform_buffer, 0, sizeof(SkySceneState::UBO), &sky_scene_state.ubo, true);
 }
 
 void RasterizerSceneRD::_update_sky(RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform) {
@@ -2371,7 +2424,7 @@ void RasterizerSceneRD::_update_sky(RID p_environment, const CameraMatrix &p_pro
 				RID texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES);
 
 				cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[2].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
-				storage->get_effects()->render_sky(cubemap_draw_list, time, sky->reflection.layers[0].mipmaps[2].framebuffers[i], sky_scene_state.sampler_uniform_set, sky_scene_state.light_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);
+				storage->get_effects()->render_sky(cubemap_draw_list, time, sky->reflection.layers[0].mipmaps[2].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);
 				RD::get_singleton()->draw_list_end();
 			}
 		}
@@ -2389,7 +2442,7 @@ void RasterizerSceneRD::_update_sky(RID p_environment, const CameraMatrix &p_pro
 				RID texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_CUBEMAP_HALF_RES);
 
 				cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[1].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
-				storage->get_effects()->render_sky(cubemap_draw_list, time, sky->reflection.layers[0].mipmaps[1].framebuffers[i], sky_scene_state.sampler_uniform_set, sky_scene_state.light_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);
+				storage->get_effects()->render_sky(cubemap_draw_list, time, sky->reflection.layers[0].mipmaps[1].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);
 				RD::get_singleton()->draw_list_end();
 			}
 		}
@@ -2403,7 +2456,7 @@ void RasterizerSceneRD::_update_sky(RID p_environment, const CameraMatrix &p_pro
 			RID texture_uniform_set = _get_sky_textures(sky, SKY_TEXTURE_SET_CUBEMAP);
 
 			cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[0].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
-			storage->get_effects()->render_sky(cubemap_draw_list, time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], sky_scene_state.sampler_uniform_set, sky_scene_state.light_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);
+			storage->get_effects()->render_sky(cubemap_draw_list, time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin);
 			RD::get_singleton()->draw_list_end();
 		}
 
@@ -2965,7 +3018,7 @@ float RasterizerSceneRD::environment_get_fog_height_density(RID p_env) const {
 	return env->fog_height_density;
 }
 
-void RasterizerSceneRD::environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_lenght, float p_detail_spread, float p_gi_inject, RenderingServer::EnvVolumetricFogShadowFilter p_shadow_filter) {
+void RasterizerSceneRD::environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, RenderingServer::EnvVolumetricFogShadowFilter p_shadow_filter) {
 	Environment *env = environment_owner.getornull(p_env);
 	ERR_FAIL_COND(!env);
 
@@ -2973,7 +3026,7 @@ void RasterizerSceneRD::environment_set_volumetric_fog(RID p_env, bool p_enable,
 	env->volumetric_fog_density = p_density;
 	env->volumetric_fog_light = p_light;
 	env->volumetric_fog_light_energy = p_light_energy;
-	env->volumetric_fog_length = p_lenght;
+	env->volumetric_fog_length = p_length;
 	env->volumetric_fog_detail_spread = p_detail_spread;
 	env->volumetric_fog_shadow_filter = p_shadow_filter;
 	env->volumetric_fog_gi_inject = p_gi_inject;
@@ -5607,6 +5660,17 @@ RID RasterizerSceneRD::render_buffers_get_volumetric_fog_texture(RID p_render_bu
 	return rb->volumetric_fog->fog_map;
 }
 
+RID RasterizerSceneRD::render_buffers_get_volumetric_fog_sky_uniform_set(RID p_render_buffers) {
+	const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
+	ERR_FAIL_COND_V(!rb, RID());
+
+	if (!rb->volumetric_fog) {
+		return RID();
+	}
+
+	return rb->volumetric_fog->sky_uniform_set;
+}
+
 float RasterizerSceneRD::render_buffers_get_volumetric_fog_end(RID p_render_buffers) {
 	const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
 	ERR_FAIL_COND_V(!rb || !rb->volumetric_fog, 0);
@@ -5838,7 +5902,7 @@ void RasterizerSceneRD::_setup_lights(RID *p_light_cull_result, int p_light_cull
 	uint32_t light_count = 0;
 	r_directional_light_count = 0;
 	r_positional_light_count = 0;
-	sky_scene_state.directional_light_count = 0;
+	sky_scene_state.ubo.directional_light_count = 0;
 
 	for (int i = 0; i < p_light_cull_count; i++) {
 		RID li = p_light_cull_result[i];
@@ -6010,7 +6074,7 @@ void RasterizerSceneRD::_setup_lights(RID *p_light_cull_result, int p_light_cull
 
 					sky_light_data.enabled = true;
 					sky_light_data.size = angular_diameter;
-					sky_scene_state.directional_light_count++;
+					sky_scene_state.ubo.directional_light_count++;
 				}
 
 				r_directional_light_count++;
@@ -6317,7 +6381,22 @@ void RasterizerSceneRD::_volumetric_fog_erase(RenderBuffers *rb) {
 
 	RD::get_singleton()->free(rb->volumetric_fog->light_density_map);
 	RD::get_singleton()->free(rb->volumetric_fog->fog_map);
+
+	if (rb->volumetric_fog->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) {
+		RD::get_singleton()->free(rb->volumetric_fog->uniform_set);
+	}
+	if (rb->volumetric_fog->uniform_set2.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set2)) {
+		RD::get_singleton()->free(rb->volumetric_fog->uniform_set2);
+	}
+	if (rb->volumetric_fog->sdfgi_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->sdfgi_uniform_set)) {
+		RD::get_singleton()->free(rb->volumetric_fog->sdfgi_uniform_set);
+	}
+	if (rb->volumetric_fog->sky_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->sky_uniform_set)) {
+		RD::get_singleton()->free(rb->volumetric_fog->sky_uniform_set);
+	}
+
 	memdelete(rb->volumetric_fog);
+
 	rb->volumetric_fog = nullptr;
 }
 
@@ -6407,6 +6486,17 @@ void RasterizerSceneRD::_update_volumetric_fog(RID p_render_buffers, RID p_envir
 
 		rb->volumetric_fog->fog_map = RD::get_singleton()->texture_create(tf, RD::TextureView());
 		_render_buffers_uniform_set_changed(p_render_buffers);
+
+		Vector<RD::Uniform> uniforms;
+		{
+			RD::Uniform u;
+			u.binding = 0;
+			u.type = RD::UNIFORM_TYPE_TEXTURE;
+			u.ids.push_back(rb->volumetric_fog->fog_map);
+			uniforms.push_back(u);
+		}
+
+		rb->volumetric_fog->sky_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_FOG);
 	}
 
 	//update directional shadow
@@ -7907,6 +7997,7 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {
 		actions.custom_samplers["RADIANCE"] = "material_samplers[3]";
 		actions.usage_defines["HALF_RES_COLOR"] = "\n#define USES_HALF_RES_COLOR\n";
 		actions.usage_defines["QUARTER_RES_COLOR"] = "\n#define USES_QUARTER_RES_COLOR\n";
+		actions.render_mode_defines["disable_fog"] = "#define DISABLE_FOG\n";
 
 		actions.sampler_array_name = "material_samplers";
 		actions.base_texture_binding_index = 1;
@@ -7931,6 +8022,8 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {
 		SkyMaterialData *md = (SkyMaterialData *)storage->material_get_data(sky_shader.default_material, RasterizerStorageRD::SHADER_TYPE_SKY);
 		sky_shader.default_shader_rd = sky_shader.shader.version_get_shader(md->shader_data->version, SKY_VERSION_BACKGROUND);
 
+		sky_scene_state.uniform_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(SkySceneState::UBO));
+
 		Vector<RD::Uniform> uniforms;
 
 		{
@@ -7962,7 +8055,70 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {
 			uniforms.push_back(u);
 		}
 
-		sky_scene_state.sampler_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_SAMPLERS);
+		{
+			RD::Uniform u;
+			u.binding = 2;
+			u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+			u.ids.push_back(sky_scene_state.uniform_buffer);
+			uniforms.push_back(u);
+		}
+
+		{
+			RD::Uniform u;
+			u.binding = 3;
+			u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+			u.ids.push_back(sky_scene_state.directional_light_buffer);
+			uniforms.push_back(u);
+		}
+
+		sky_scene_state.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_UNIFORMS);
+	}
+
+	{
+		Vector<RD::Uniform> uniforms;
+		{
+			RD::Uniform u;
+			u.binding = 0;
+			u.type = RD::UNIFORM_TYPE_TEXTURE;
+			RID vfog = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE);
+			u.ids.push_back(vfog);
+			uniforms.push_back(u);
+		}
+
+		sky_scene_state.default_fog_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_FOG);
+	}
+
+	{
+		// Need defaults for using fog with clear color
+		sky_scene_state.fog_shader = storage->shader_create();
+		storage->shader_set_code(sky_scene_state.fog_shader, "shader_type sky; uniform vec4 clear_color; void fragment() { COLOR = clear_color.rgb; } \n");
+		sky_scene_state.fog_material = storage->material_create();
+		storage->material_set_shader(sky_scene_state.fog_material, sky_scene_state.fog_shader);
+
+		Vector<RD::Uniform> uniforms;
+		{
+			RD::Uniform u;
+			u.type = RD::UNIFORM_TYPE_TEXTURE;
+			u.binding = 0;
+			u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK));
+			uniforms.push_back(u);
+		}
+		{
+			RD::Uniform u;
+			u.type = RD::UNIFORM_TYPE_TEXTURE;
+			u.binding = 1;
+			u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE));
+			uniforms.push_back(u);
+		}
+		{
+			RD::Uniform u;
+			u.type = RD::UNIFORM_TYPE_TEXTURE;
+			u.binding = 2;
+			u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE));
+			uniforms.push_back(u);
+		}
+
+		sky_scene_state.fog_only_texture_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_TEXTURES);
 	}
 
 	{
@@ -8179,11 +8335,8 @@ RasterizerSceneRD::~RasterizerSceneRD() {
 		RD::get_singleton()->free(E->get().cubemap);
 	}
 
-	if (sky_scene_state.sampler_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sky_scene_state.sampler_uniform_set)) {
-		RD::get_singleton()->free(sky_scene_state.sampler_uniform_set);
-	}
-	if (sky_scene_state.light_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sky_scene_state.light_uniform_set)) {
-		RD::get_singleton()->free(sky_scene_state.light_uniform_set);
+	if (sky_scene_state.uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sky_scene_state.uniform_set)) {
+		RD::get_singleton()->free(sky_scene_state.uniform_set);
 	}
 
 	RD::get_singleton()->free(default_giprobe_buffer);
@@ -8199,14 +8352,19 @@ RasterizerSceneRD::~RasterizerSceneRD() {
 	sdfgi_shader.integrate.version_free(sdfgi_shader.integrate_shader);
 	sdfgi_shader.preprocess.version_free(sdfgi_shader.preprocess_shader);
 
+	volumetric_fog.shader.version_free(volumetric_fog.shader_version);
+
 	memdelete_arr(gi_probe_lights);
 	SkyMaterialData *md = (SkyMaterialData *)storage->material_get_data(sky_shader.default_material, RasterizerStorageRD::SHADER_TYPE_SKY);
 	sky_shader.shader.version_free(md->shader_data->version);
 	RD::get_singleton()->free(sky_scene_state.directional_light_buffer);
+	RD::get_singleton()->free(sky_scene_state.uniform_buffer);
 	memdelete_arr(sky_scene_state.directional_lights);
 	memdelete_arr(sky_scene_state.last_frame_directional_lights);
 	storage->free(sky_shader.default_shader);
 	storage->free(sky_shader.default_material);
+	storage->free(sky_scene_state.fog_shader);
+	storage->free(sky_scene_state.fog_material);
 	memdelete_arr(directional_penumbra_shadow_kernel);
 	memdelete_arr(directional_soft_shadow_kernel);
 	memdelete_arr(penumbra_shadow_kernel);

+ 31 - 6
servers/rendering/rasterizer_rd/rasterizer_scene_rd.h

@@ -63,14 +63,37 @@ protected:
 	};
 
 	struct SkySceneState {
+		struct UBO {
+			uint32_t volumetric_fog_enabled;
+			float volumetric_fog_inv_length;
+			float volumetric_fog_detail_spread;
+			uint32_t volumetric_fog_pad;
+
+			float fog_light_color[3];
+			float fog_sun_scatter;
+
+			uint32_t fog_enabled;
+			float fog_density;
+
+			float z_far;
+			uint32_t directional_light_count;
+		};
+
+		UBO ubo;
+
 		SkyDirectionalLightData *directional_lights;
 		SkyDirectionalLightData *last_frame_directional_lights;
 		uint32_t max_directional_lights;
-		uint32_t directional_light_count;
 		uint32_t last_frame_directional_light_count;
 		RID directional_light_buffer;
-		RID sampler_uniform_set;
-		RID light_uniform_set;
+		RID uniform_set;
+		RID uniform_buffer;
+		RID fog_uniform_set;
+		RID default_fog_uniform_set;
+
+		RID fog_shader;
+		RID fog_material;
+		RID fog_only_texture_uniform_set;
 	} sky_scene_state;
 
 	struct RenderBufferData {
@@ -105,7 +128,7 @@ protected:
 	void _process_ssr(RID p_render_buffers, RID p_dest_framebuffer, RID p_normal_buffer, RID p_specular_buffer, RID p_metallic, const Color &p_metallic_mask, RID p_environment, const CameraMatrix &p_projection, bool p_use_additive);
 	void _process_sss(RID p_render_buffers, const CameraMatrix &p_camera);
 
-	void _setup_sky(RID p_environment, const Vector3 &p_position, const Size2i p_screen_size);
+	void _setup_sky(RID p_environment, RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform, const Size2i p_screen_size);
 	void _update_sky(RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform);
 	void _draw_sky(bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform);
 	void _process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_ambient_buffer, RID p_reflection_buffer, RID p_gi_probe_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, RID *p_gi_probe_cull_result, int p_gi_probe_cull_count);
@@ -244,10 +267,10 @@ private:
 	};
 
 	enum SkySet {
-		SKY_SET_SAMPLERS,
+		SKY_SET_UNIFORMS,
 		SKY_SET_MATERIAL,
 		SKY_SET_TEXTURES,
-		SKY_SET_LIGHTS,
+		SKY_SET_FOG,
 		SKY_SET_MAX
 	};
 
@@ -1355,6 +1378,7 @@ private:
 		RID uniform_set;
 		RID uniform_set2;
 		RID sdfgi_uniform_set;
+		RID sky_uniform_set;
 
 		int last_shadow_filter = -1;
 	};
@@ -1837,6 +1861,7 @@ public:
 
 	bool render_buffers_has_volumetric_fog(RID p_render_buffers) const;
 	RID render_buffers_get_volumetric_fog_texture(RID p_render_buffers);
+	RID render_buffers_get_volumetric_fog_sky_uniform_set(RID p_render_buffers);
 	float render_buffers_get_volumetric_fog_end(RID p_render_buffers);
 	float render_buffers_get_volumetric_fog_detail_spread(RID p_render_buffers);
 

+ 69 - 12
servers/rendering/rasterizer_rd/shaders/sky.glsl

@@ -58,6 +58,35 @@ layout(set = 0, binding = 1, std430) restrict readonly buffer GlobalVariableData
 }
 global_variables;
 
+layout(set = 0, binding = 2, std140) uniform SceneData {
+	bool volumetric_fog_enabled;
+	float volumetric_fog_inv_length;
+	float volumetric_fog_detail_spread;
+	uint volumetric_fog_pad;
+
+	vec3 fog_light_color;
+	float fog_sun_scatter;
+
+	bool fog_enabled;
+	float fog_density;
+
+	float z_far;
+	uint directional_light_count;
+}
+scene_data;
+
+struct DirectionalLightData {
+	vec4 direction_energy;
+	vec4 color_size;
+	bool enabled;
+};
+
+layout(set = 0, binding = 3, std140) uniform DirectionalLights {
+	DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
+}
+
+directional_lights;
+
 #ifdef USE_MATERIAL_UNIFORMS
 layout(set = 1, binding = 0, std140) uniform MaterialUniforms{
 	/* clang-format off */
@@ -77,6 +106,8 @@ layout(set = 2, binding = 1) uniform texture2D half_res;
 layout(set = 2, binding = 2) uniform texture2D quarter_res;
 #endif
 
+layout(set = 3, binding = 0) uniform texture3D volumetric_fog_texture;
+
 #ifdef USE_CUBEMAP_PASS
 #define AT_CUBEMAP_PASS true
 #else
@@ -95,18 +126,6 @@ layout(set = 2, binding = 2) uniform texture2D quarter_res;
 #define AT_QUARTER_RES_PASS false
 #endif
 
-struct DirectionalLightData {
-	vec4 direction_energy;
-	vec4 color_size;
-	bool enabled;
-};
-
-layout(set = 3, binding = 0, std140) uniform DirectionalLights {
-	DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
-}
-
-directional_lights;
-
 /* clang-format off */
 
 FRAGMENT_SHADER_GLOBALS
@@ -115,6 +134,30 @@ FRAGMENT_SHADER_GLOBALS
 
 layout(location = 0) out vec4 frag_color;
 
+vec4 volumetric_fog_process(vec2 screen_uv) {
+	vec3 fog_pos = vec3(screen_uv, 1.0);
+
+	return texture(sampler3D(volumetric_fog_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), fog_pos);
+}
+
+vec4 fog_process(vec3 view) {
+	vec3 fog_color = scene_data.fog_light_color;
+
+	if (scene_data.fog_sun_scatter > 0.001) {
+		vec4 sun_scatter = vec4(0.0);
+		float sun_total = 0.0;
+		for (uint i = 0; i < scene_data.directional_light_count; i++) {
+			vec3 light_color = directional_lights.data[i].color_size.xyz * directional_lights.data[i].direction_energy.w;
+			float light_amount = pow(max(dot(view, directional_lights.data[i].direction_energy.xyz), 0.0), 8.0);
+			fog_color += light_color * light_amount * scene_data.fog_sun_scatter;
+		}
+	}
+
+	float fog_amount = clamp(1.0 - exp(-scene_data.z_far * scene_data.fog_density), 0.0, 1.0);
+
+	return vec4(fog_color, fog_amount);
+}
+
 void main() {
 	vec3 cube_normal;
 	cube_normal.z = -1.0;
@@ -178,6 +221,20 @@ FRAGMENT_SHADER_CODE
 	frag_color.rgb = color * params.position_multiplier.w;
 	frag_color.a = alpha;
 
+#if !defined(DISABLE_FOG) && !defined(USE_CUBEMAP_PASS)
+
+	if (scene_data.volumetric_fog_enabled) {
+		vec4 fog = volumetric_fog_process(uv);
+		frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a);
+	}
+
+	if (scene_data.fog_enabled) {
+		vec4 fog = fog_process(cube_normal);
+		frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a);
+	}
+
+#endif // DISABLE_FOG
+
 	// Blending is disabled for Sky, so alpha doesn't blend
 	// alpha is used for subsurface scattering so make sure it doesn't get applied to Sky
 	if (!AT_CUBEMAP_PASS && !AT_HALF_RES_PASS && !AT_QUARTER_RES_PASS) {

+ 1 - 0
servers/rendering/shader_types.cpp

@@ -328,6 +328,7 @@ ShaderTypes::ShaderTypes() {
 
 	shader_modes[RS::SHADER_SKY].modes.push_back("use_half_res_pass");
 	shader_modes[RS::SHADER_SKY].modes.push_back("use_quarter_res_pass");
+	shader_modes[RS::SHADER_SKY].modes.push_back("disable_fog");
 
 	shader_types.insert("spatial");
 	shader_types.insert("canvas_item");