ソースを参照

Add aerial perspective to fixed fog

clayjohn 5 年 前
コミット
8c21c26fb5

+ 4 - 0
doc/classes/Environment.xml

@@ -98,6 +98,10 @@
 		<member name="background_mode" type="int" setter="set_background" getter="get_background" enum="Environment.BGMode" default="0">
 			The background mode. See [enum BGMode] for possible values.
 		</member>
+		<member name="fog_aerial_perspective" type="float" setter="set_fog_aerial_perspective" getter="get_fog_aerial_perspective" default="0.0">
+			Blend factor between the fog's color and the color of the background [Sky]. Must have [member background_mode] set to [constant BG_SKY].
+			This is useful to simulate [url=https://en.wikipedia.org/wiki/Aerial_perspective]aerial perspective[/url] in large scenes with low density fog. However, it is not very useful for high-density fog, as the sky will shine through. When set to [code]1.0[/code], the fog color comes completely from the [Sky]. If set to [code]0.0[/code], aerial perspective is disabled.
+		</member>
 		<member name="fog_density" type="float" setter="set_fog_density" getter="get_fog_density" default="0.001">
 		</member>
 		<member name="fog_enabled" type="bool" setter="set_fog_enabled" getter="is_fog_enabled" default="false">

+ 23 - 1
scene/resources/environment.cpp

@@ -44,6 +44,9 @@ void Environment::set_background(BGMode p_bg) {
 	bg_mode = p_bg;
 	RS::get_singleton()->environment_set_background(environment, RS::EnvironmentBG(p_bg));
 	_change_notify();
+	if (bg_mode != BG_SKY) {
+		set_fog_aerial_perspective(0.0);
+	}
 }
 
 Environment::BGMode Environment::get_background() const {
@@ -739,6 +742,14 @@ float Environment::get_fog_height_density() const {
 	return fog_height_density;
 }
 
+void Environment::set_fog_aerial_perspective(float p_aerial_perspective) {
+	fog_aerial_perspective = p_aerial_perspective;
+	_update_fog();
+}
+float Environment::get_fog_aerial_perspective() const {
+	return fog_aerial_perspective;
+}
+
 void Environment::_update_fog() {
 	RS::get_singleton()->environment_set_fog(
 			environment,
@@ -748,7 +759,8 @@ void Environment::_update_fog() {
 			fog_sun_scatter,
 			fog_density,
 			fog_height,
-			fog_height_density);
+			fog_height_density,
+			fog_aerial_perspective);
 }
 
 // Volumetric Fog
@@ -887,6 +899,12 @@ void Environment::_validate_property(PropertyInfo &property) const {
 		}
 	}
 
+	if (property.name == "fog_aerial_perspective") {
+		if (bg_mode != BG_SKY) {
+			property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL;
+		}
+	}
+
 	if (property.name == "glow_intensity" && glow_blend_mode == GLOW_BLEND_MODE_MIX) {
 		property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL;
 	}
@@ -1219,6 +1237,9 @@ void Environment::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_fog_height_density", "height_density"), &Environment::set_fog_height_density);
 	ClassDB::bind_method(D_METHOD("get_fog_height_density"), &Environment::get_fog_height_density);
 
+	ClassDB::bind_method(D_METHOD("set_fog_aerial_perspective", "aerial_perspective"), &Environment::set_fog_aerial_perspective);
+	ClassDB::bind_method(D_METHOD("get_fog_aerial_perspective"), &Environment::get_fog_aerial_perspective);
+
 	ADD_GROUP("Fog", "fog_");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fog_enabled"), "set_fog_enabled", "is_fog_enabled");
 	ADD_PROPERTY(PropertyInfo(Variant::COLOR, "fog_light_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_fog_light_color", "get_fog_light_color");
@@ -1226,6 +1247,7 @@ void Environment::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_sun_scatter", PROPERTY_HINT_RANGE, "0,1,0.01,or_greater"), "set_fog_sun_scatter", "get_fog_sun_scatter");
 
 	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_density", PROPERTY_HINT_RANGE, "0,16,0.0001"), "set_fog_density", "get_fog_density");
+	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_aerial_perspective", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_fog_aerial_perspective", "get_fog_aerial_perspective");
 	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height", PROPERTY_HINT_RANGE, "-1024,1024,0.01,or_lesser,or_greater"), "set_fog_height", "get_fog_height");
 	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height_density", PROPERTY_HINT_RANGE, "0,128,0.001,or_greater"), "set_fog_height_density", "get_fog_height_density");
 

+ 3 - 0
scene/resources/environment.h

@@ -190,6 +190,7 @@ private:
 	float fog_density = 0.001;
 	float fog_height = 0.0;
 	float fog_height_density = 0.0; //can be negative to invert effect
+	float fog_aerial_perspective = 0.0;
 
 	void _update_fog();
 
@@ -368,6 +369,8 @@ public:
 	float get_fog_height() const;
 	void set_fog_height_density(float p_amount);
 	float get_fog_height_density() const;
+	void set_fog_aerial_perspective(float p_aerial_perspective);
+	float get_fog_aerial_perspective() const;
 
 	// Volumetric Fog
 	void set_volumetric_fog_enabled(bool p_enable);

+ 1 - 1
servers/rendering/rasterizer.h

@@ -111,7 +111,7 @@ public:
 
 	virtual void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp) = 0;
 
-	virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density) = 0;
+	virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective) = 0;
 
 	virtual Ref<Image> environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) = 0;
 

+ 1 - 0
servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp

@@ -1335,6 +1335,7 @@ void RasterizerSceneHighEndRD::_setup_environment(RID p_environment, RID p_rende
 		if (scene_state.ubo.fog_height_density >= 0.0001) {
 			scene_state.ubo.fog_height_density = 1.0 / scene_state.ubo.fog_height_density;
 		}
+		scene_state.ubo.fog_aerial_perspective = environment_get_fog_aerial_perspective(p_environment);
 
 		Color fog_color = environment_get_fog_light_color(p_environment).to_linear();
 		float fog_energy = environment_get_fog_light_energy(p_environment);

+ 7 - 7
servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.h

@@ -308,12 +308,6 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD {
 			float viewport_size[2];
 			float screen_pixel_size[2];
 
-			float time;
-			float reflection_multiplier;
-
-			uint32_t pancake_shadows;
-			uint32_t pad;
-
 			float directional_penumbra_shadow_kernel[128]; //32 vec4s
 			float directional_soft_shadow_kernel[128];
 			float penumbra_shadow_kernel[128];
@@ -366,7 +360,6 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD {
 			uint32_t volumetric_fog_pad;
 
 			// Fog
-
 			uint32_t fog_enabled;
 			float fog_density;
 			float fog_height;
@@ -374,6 +367,13 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD {
 
 			float fog_light_color[3];
 			float fog_sun_scatter;
+
+			float fog_aerial_perspective;
+
+			float time;
+			float reflection_multiplier;
+
+			uint32_t pancake_shadows;
 		};
 
 		UBO ubo;

+ 9 - 1
servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp

@@ -2322,6 +2322,7 @@ void RasterizerSceneRD::_setup_sky(RID p_environment, RID p_render_buffers, cons
 	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);
+	sky_scene_state.ubo.fog_aerial_perspective = environment_get_fog_aerial_perspective(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;
@@ -2971,7 +2972,7 @@ void RasterizerSceneRD::environment_set_sdfgi(RID p_env, bool p_enable, RS::Envi
 	env->sdfgi_y_scale = p_y_scale;
 }
 
-void RasterizerSceneRD::environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density) {
+void RasterizerSceneRD::environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_fog_aerial_perspective) {
 	Environment *env = environment_owner.getornull(p_env);
 	ERR_FAIL_COND(!env);
 
@@ -2982,6 +2983,7 @@ void RasterizerSceneRD::environment_set_fog(RID p_env, bool p_enable, const Colo
 	env->fog_density = p_density;
 	env->fog_height = p_height;
 	env->fog_height_density = p_height_density;
+	env->fog_aerial_perspective = p_fog_aerial_perspective;
 }
 
 bool RasterizerSceneRD::environment_is_fog_enabled(RID p_env) const {
@@ -3022,6 +3024,12 @@ float RasterizerSceneRD::environment_get_fog_height_density(RID p_env) const {
 	return env->fog_height_density;
 }
 
+float RasterizerSceneRD::environment_get_fog_aerial_perspective(RID p_env) const {
+	const Environment *env = environment_owner.getornull(p_env);
+	ERR_FAIL_COND_V(!env, 0);
+	return env->fog_aerial_perspective;
+}
+
 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);

+ 5 - 2
servers/rendering/rasterizer_rd/rasterizer_scene_rd.h

@@ -67,7 +67,8 @@ protected:
 			uint32_t volumetric_fog_enabled;
 			float volumetric_fog_inv_length;
 			float volumetric_fog_detail_spread;
-			uint32_t volumetric_fog_pad;
+
+			float fog_aerial_perspective;
 
 			float fog_light_color[3];
 			float fog_sun_scatter;
@@ -706,6 +707,7 @@ private:
 		float fog_density = 0.001;
 		float fog_height = 0.0;
 		float fog_height_density = 0.0; //can be negative to invert effect
+		float fog_aerial_perspective = 0.0;
 
 		/// Volumetric Fog
 		///
@@ -1534,7 +1536,7 @@ public:
 	void environment_glow_set_use_bicubic_upscale(bool p_enable);
 	void environment_glow_set_use_high_quality(bool p_enable);
 
-	void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density);
+	void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective);
 	bool environment_is_fog_enabled(RID p_env) const;
 	Color environment_get_fog_light_color(RID p_env) const;
 	float environment_get_fog_light_energy(RID p_env) const;
@@ -1542,6 +1544,7 @@ public:
 	float environment_get_fog_density(RID p_env) const;
 	float environment_get_fog_height(RID p_env) const;
 	float environment_get_fog_height_density(RID p_env) const;
+	float environment_get_fog_aerial_perspective(RID p_env) const;
 
 	void 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, RS::EnvVolumetricFogShadowFilter p_shadow_filter);
 

+ 16 - 0
servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl

@@ -1621,6 +1621,22 @@ vec4 volumetric_fog_process(vec2 screen_uv, float z) {
 vec4 fog_process(vec3 vertex) {
 	vec3 fog_color = scene_data.fog_light_color;
 
+	if (scene_data.fog_aerial_perspective > 0.0) {
+		vec3 sky_fog_color = vec3(0.0);
+		vec3 cube_view = scene_data.radiance_inverse_xform * vertex;
+		// mip_level always reads from the second mipmap and higher so the fog is always slightly blurred
+		float mip_level = mix(1.0 / MAX_ROUGHNESS_LOD, 1.0, 1.0 - (abs(vertex.z) - scene_data.z_near) / (scene_data.z_far - scene_data.z_near));
+#ifdef USE_RADIANCE_CUBEMAP_ARRAY
+		float lod, blend;
+		blend = modf(mip_level * MAX_ROUGHNESS_LOD, lod);
+		sky_fog_color = texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(cube_view, lod)).rgb;
+		sky_fog_color = mix(sky_fog_color, texture(samplerCubeArray(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), vec4(cube_view, lod + 1)).rgb, blend);
+#else
+		sky_fog_color = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), cube_view, mip_level * MAX_ROUGHNESS_LOD).rgb;
+#endif //USE_RADIANCE_CUBEMAP_ARRAY
+		fog_color = mix(fog_color, sky_fog_color, scene_data.fog_aerial_perspective);
+	}
+
 	if (scene_data.fog_sun_scatter > 0.001) {
 		vec4 sun_scatter = vec4(0.0);
 		float sun_total = 0.0;

+ 7 - 6
servers/rendering/rasterizer_rd/shaders/scene_high_end_inc.glsl

@@ -43,12 +43,6 @@ layout(set = 0, binding = 3, std140) uniform SceneData {
 	vec2 viewport_size;
 	vec2 screen_pixel_size;
 
-	float time;
-	float reflection_multiplier; // one normally, zero when rendering reflections
-
-	bool pancake_shadows;
-	uint pad;
-
 	//use vec4s because std140 doesnt play nice with vec2s, z and w are wasted
 	vec4 directional_penumbra_shadow_kernel[32];
 	vec4 directional_soft_shadow_kernel[32];
@@ -108,6 +102,13 @@ layout(set = 0, binding = 3, std140) uniform SceneData {
 
 	vec3 fog_light_color;
 	float fog_sun_scatter;
+
+	float fog_aerial_perspective;
+
+	float time;
+	float reflection_multiplier; // one normally, zero when rendering reflections
+
+	bool pancake_shadows;
 }
 
 scene_data;

+ 5 - 4
servers/rendering/rasterizer_rd/shaders/sky.glsl

@@ -62,7 +62,8 @@ 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;
+
+	float fog_aerial_perspective;
 
 	vec3 fog_light_color;
 	float fog_sun_scatter;
@@ -140,8 +141,8 @@ vec4 volumetric_fog_process(vec2 screen_uv) {
 	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;
+vec4 fog_process(vec3 view, vec3 sky_color) {
+	vec3 fog_color = mix(scene_data.fog_light_color, sky_color, scene_data.fog_aerial_perspective);
 
 	if (scene_data.fog_sun_scatter > 0.001) {
 		vec4 sun_scatter = vec4(0.0);
@@ -225,7 +226,7 @@ FRAGMENT_SHADER_CODE
 
 	// Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky.
 	if (scene_data.fog_enabled) {
-		vec4 fog = fog_process(cube_normal);
+		vec4 fog = fog_process(cube_normal, frag_color.rgb);
 		frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a);
 	}
 

+ 1 - 1
servers/rendering/rendering_server_raster.h

@@ -589,7 +589,7 @@ public:
 
 	BIND6(environment_set_adjustment, RID, bool, float, float, float, RID)
 
-	BIND8(environment_set_fog, RID, bool, const Color &, float, float, float, float, float)
+	BIND9(environment_set_fog, RID, bool, const Color &, float, float, float, float, float, float)
 	BIND9(environment_set_volumetric_fog, RID, bool, float, const Color &, float, float, float, float, EnvVolumetricFogShadowFilter)
 
 	BIND2(environment_set_volumetric_fog_volume_size, int, int)

+ 1 - 1
servers/rendering/rendering_server_wrap_mt.h

@@ -500,7 +500,7 @@ public:
 
 	FUNC6(environment_set_adjustment, RID, bool, float, float, float, RID)
 
-	FUNC8(environment_set_fog, RID, bool, const Color &, float, float, float, float, float)
+	FUNC9(environment_set_fog, RID, bool, const Color &, float, float, float, float, float, float)
 
 	FUNC9(environment_set_volumetric_fog, RID, bool, float, const Color &, float, float, float, float, EnvVolumetricFogShadowFilter)
 

+ 1 - 1
servers/rendering_server.cpp

@@ -1752,7 +1752,7 @@ void RenderingServer::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("environment_set_adjustment", "env", "enable", "brightness", "contrast", "saturation", "ramp"), &RenderingServer::environment_set_adjustment);
 	ClassDB::bind_method(D_METHOD("environment_set_ssr", "env", "enable", "max_steps", "fade_in", "fade_out", "depth_tolerance"), &RenderingServer::environment_set_ssr);
 	ClassDB::bind_method(D_METHOD("environment_set_ssao", "env", "enable", "radius", "intensity", "bias", "light_affect", "ao_channel_affect", "blur", "bilateral_sharpness"), &RenderingServer::environment_set_ssao);
-	ClassDB::bind_method(D_METHOD("environment_set_fog", "env", "enable", "light_color", "light_energy", "sun_scatter", "density", "height", "height_density"), &RenderingServer::environment_set_fog);
+	ClassDB::bind_method(D_METHOD("environment_set_fog", "env", "enable", "light_color", "light_energy", "sun_scatter", "density", "height", "height_density", "aerial_perspective"), &RenderingServer::environment_set_fog);
 
 	ClassDB::bind_method(D_METHOD("scenario_create"), &RenderingServer::scenario_create);
 	ClassDB::bind_method(D_METHOD("scenario_set_debug", "scenario", "debug_mode"), &RenderingServer::scenario_set_debug);

+ 1 - 1
servers/rendering_server.h

@@ -914,7 +914,7 @@ public:
 
 	virtual void environment_set_sdfgi_frames_to_converge(EnvironmentSDFGIFramesToConverge p_frames) = 0;
 
-	virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density) = 0;
+	virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective) = 0;
 
 	enum EnvVolumetricFogShadowFilter {
 		ENV_VOLUMETRIC_FOG_SHADOW_FILTER_DISABLED,