Преглед изворни кода

Merge pull request #65756 from clayjohn/sky-shader-debanding

Move debanding into internal sky shader
Rémi Verschelde пре 3 година
родитељ
комит
eb4ac38fcd

+ 13 - 0
drivers/gles3/shaders/sky.glsl

@@ -104,6 +104,15 @@ uniform uint directional_light_count;
 
 layout(location = 0) out vec4 frag_color;
 
+#ifdef USE_DEBANDING
+// https://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare
+vec3 interleaved_gradient_noise(vec2 pos) {
+	const vec3 magic = vec3(0.06711056f, 0.00583715f, 52.9829189f);
+	float res = fract(magic.z * fract(dot(pos, magic.xy))) * 2.0 - 1.0;
+	return vec3(res, -res, res) / 255.0;
+}
+#endif
+
 void main() {
 	vec3 cube_normal;
 	cube_normal.z = -1.0;
@@ -168,4 +177,8 @@ void main() {
 
 	frag_color.rgb = color;
 	frag_color.a = alpha;
+
+#ifdef USE_DEBANDING
+	frag_color.rgb += interleaved_gradient_noise(gl_FragCoord.xy);
+#endif
 }

+ 1 - 0
drivers/gles3/storage/material_storage.cpp

@@ -1715,6 +1715,7 @@ ShaderCompiler::DefaultIdentifierActions actions;
 		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.render_mode_defines["use_debanding"] = "#define USE_DEBANDING\n";
 
 		actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
 		actions.default_repeat = ShaderLanguage::REPEAT_ENABLE;

+ 42 - 44
scene/resources/sky_material.cpp

@@ -34,7 +34,7 @@
 #include "core/version.h"
 
 Mutex ProceduralSkyMaterial::shader_mutex;
-RID ProceduralSkyMaterial::shader;
+RID ProceduralSkyMaterial::shader_cache[2];
 
 void ProceduralSkyMaterial::set_sky_top_color(const Color &p_sky_top) {
 	sky_top_color = p_sky_top;
@@ -147,7 +147,11 @@ float ProceduralSkyMaterial::get_sun_curve() const {
 
 void ProceduralSkyMaterial::set_use_debanding(bool p_use_debanding) {
 	use_debanding = p_use_debanding;
-	RS::get_singleton()->material_set_param(_get_material(), "use_debanding", use_debanding);
+	_update_shader();
+	// Only set if shader already compiled
+	if (shader_set) {
+		RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(use_debanding)]);
+	}
 }
 
 bool ProceduralSkyMaterial::get_use_debanding() const {
@@ -161,7 +165,8 @@ Shader::Mode ProceduralSkyMaterial::get_shader_mode() const {
 RID ProceduralSkyMaterial::get_rid() const {
 	_update_shader();
 	if (!shader_set) {
-		RS::get_singleton()->material_set_shader(_get_material(), shader);
+		RS::get_singleton()->material_set_shader(_get_material(), shader_cache[1 - int(use_debanding)]);
+		RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(use_debanding)]);
 		shader_set = true;
 	}
 	return _get_material();
@@ -169,7 +174,7 @@ RID ProceduralSkyMaterial::get_rid() const {
 
 RID ProceduralSkyMaterial::get_shader_rid() const {
 	_update_shader();
-	return shader;
+	return shader_cache[int(use_debanding)];
 }
 
 void ProceduralSkyMaterial::_validate_property(PropertyInfo &p_property) const {
@@ -241,21 +246,24 @@ void ProceduralSkyMaterial::_bind_methods() {
 }
 
 void ProceduralSkyMaterial::cleanup_shader() {
-	if (shader.is_valid()) {
-		RS::get_singleton()->free(shader);
+	if (shader_cache[0].is_valid()) {
+		RS::get_singleton()->free(shader_cache[0]);
+		RS::get_singleton()->free(shader_cache[1]);
 	}
 }
 
 void ProceduralSkyMaterial::_update_shader() {
 	shader_mutex.lock();
-	if (shader.is_null()) {
-		shader = RS::get_singleton()->shader_create();
+	if (shader_cache[0].is_null()) {
+		for (int i = 0; i < 2; i++) {
+			shader_cache[i] = RS::get_singleton()->shader_create();
 
-		// Add a comment to describe the shader origin (useful when converting to ShaderMaterial).
-		RS::get_singleton()->shader_set_code(shader, R"(
+			// Add a comment to describe the shader origin (useful when converting to ShaderMaterial).
+			RS::get_singleton()->shader_set_code(shader_cache[i], vformat(R"(
 // NOTE: Shader automatically converted from )" VERSION_NAME " " VERSION_FULL_CONFIG R"('s ProceduralSkyMaterial.
 
 shader_type sky;
+%s
 
 uniform vec4 sky_top_color : source_color = vec4(0.385, 0.454, 0.55, 1.0);
 uniform vec4 sky_horizon_color : source_color = vec4(0.646, 0.656, 0.67, 1.0);
@@ -269,14 +277,6 @@ uniform float ground_curve : hint_range(0, 1) = 0.02;
 uniform float ground_energy = 1.0;
 uniform float sun_angle_max = 30.0;
 uniform float sun_curve : hint_range(0, 1) = 0.15;
-uniform bool use_debanding = true;
-
-// https://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare
-vec3 interleaved_gradient_noise(vec2 pos) {
-	const vec3 magic = vec3(0.06711056f, 0.00583715f, 52.9829189f);
-	float res = fract(magic.z * fract(dot(pos, magic.xy))) * 2.0 - 1.0;
-	return vec3(res, -res, res) / 255.0;
-}
 
 void sky() {
 	float v_angle = acos(clamp(EYEDIR.y, -1.0, 1.0));
@@ -332,11 +332,10 @@ void sky() {
 	ground *= ground_energy;
 
 	COLOR = mix(ground, sky, step(0.0, EYEDIR.y));
-	if (use_debanding) {
-		COLOR += interleaved_gradient_noise(FRAGCOORD.xy);
-	}
 }
-)");
+)",
+																		  i ? "render_mode use_debanding;" : ""));
+		}
 	}
 	shader_mutex.unlock();
 }
@@ -546,7 +545,11 @@ float PhysicalSkyMaterial::get_energy_multiplier() const {
 
 void PhysicalSkyMaterial::set_use_debanding(bool p_use_debanding) {
 	use_debanding = p_use_debanding;
-	RS::get_singleton()->material_set_param(_get_material(), "use_debanding", use_debanding);
+	_update_shader();
+	// Only set if shader already compiled
+	if (shader_set) {
+		RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(use_debanding)]);
+	}
 }
 
 bool PhysicalSkyMaterial::get_use_debanding() const {
@@ -570,7 +573,8 @@ Shader::Mode PhysicalSkyMaterial::get_shader_mode() const {
 RID PhysicalSkyMaterial::get_rid() const {
 	_update_shader();
 	if (!shader_set) {
-		RS::get_singleton()->material_set_shader(_get_material(), shader);
+		RS::get_singleton()->material_set_shader(_get_material(), shader_cache[1 - int(use_debanding)]);
+		RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(use_debanding)]);
 		shader_set = true;
 	}
 	return _get_material();
@@ -578,7 +582,7 @@ RID PhysicalSkyMaterial::get_rid() const {
 
 RID PhysicalSkyMaterial::get_shader_rid() const {
 	_update_shader();
-	return shader;
+	return shader_cache[int(use_debanding)];
 }
 
 void PhysicalSkyMaterial::_validate_property(PropertyInfo &p_property) const {
@@ -588,7 +592,7 @@ void PhysicalSkyMaterial::_validate_property(PropertyInfo &p_property) const {
 }
 
 Mutex PhysicalSkyMaterial::shader_mutex;
-RID PhysicalSkyMaterial::shader;
+RID PhysicalSkyMaterial::shader_cache[2];
 
 void PhysicalSkyMaterial::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_rayleigh_coefficient", "rayleigh"), &PhysicalSkyMaterial::set_rayleigh_coefficient);
@@ -642,21 +646,24 @@ void PhysicalSkyMaterial::_bind_methods() {
 }
 
 void PhysicalSkyMaterial::cleanup_shader() {
-	if (shader.is_valid()) {
-		RS::get_singleton()->free(shader);
+	if (shader_cache[0].is_valid()) {
+		RS::get_singleton()->free(shader_cache[0]);
+		RS::get_singleton()->free(shader_cache[1]);
 	}
 }
 
 void PhysicalSkyMaterial::_update_shader() {
 	shader_mutex.lock();
-	if (shader.is_null()) {
-		shader = RS::get_singleton()->shader_create();
+	if (shader_cache[0].is_null()) {
+		for (int i = 0; i < 2; i++) {
+			shader_cache[i] = RS::get_singleton()->shader_create();
 
-		// Add a comment to describe the shader origin (useful when converting to ShaderMaterial).
-		RS::get_singleton()->shader_set_code(shader, R"(
+			// Add a comment to describe the shader origin (useful when converting to ShaderMaterial).
+			RS::get_singleton()->shader_set_code(shader_cache[i], vformat(R"(
 // NOTE: Shader automatically converted from )" VERSION_NAME " " VERSION_FULL_CONFIG R"('s PhysicalSkyMaterial.
 
 shader_type sky;
+%s
 
 uniform float rayleigh : hint_range(0, 64) = 2.0;
 uniform vec4 rayleigh_color : source_color = vec4(0.3, 0.405, 0.6, 1.0);
@@ -668,7 +675,6 @@ uniform float turbidity : hint_range(0, 1000) = 10.0;
 uniform float sun_disk_scale : hint_range(0, 360) = 1.0;
 uniform vec4 ground_color : source_color = vec4(0.1, 0.07, 0.034, 1.0);
 uniform float exposure : hint_range(0, 128) = 1.0;
-uniform bool use_debanding = true;
 
 uniform sampler2D night_sky : source_color, hint_default_black;
 
@@ -683,13 +689,6 @@ float henyey_greenstein(float cos_theta, float g) {
 	return k * (1.0 - g * g) / (pow(1.0 + g * g - 2.0 * g * cos_theta, 1.5));
 }
 
-// https://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare
-vec3 interleaved_gradient_noise(vec2 pos) {
-	const vec3 magic = vec3(0.06711056f, 0.00583715f, 52.9829189f);
-	float res = fract(magic.z * fract(dot(pos, magic.xy))) * 2.0 - 1.0;
-	return vec3(res, -res, res) / 255.0;
-}
-
 void sky() {
 	if (LIGHT0_ENABLED) {
 		float zenith_angle = clamp( dot(UP, normalize(LIGHT0_DIRECTION)), -1.0, 1.0 );
@@ -737,16 +736,15 @@ void sky() {
 		vec3 color = Lin + L0;
 		COLOR = pow(color, vec3(1.0 / (1.2 + (1.2 * sun_fade))));
 		COLOR *= exposure;
-		if (use_debanding) {
-			COLOR += interleaved_gradient_noise(FRAGCOORD.xy);
-		}
 	} else {
 		// There is no sun, so display night_sky and nothing else.
 		COLOR = texture(night_sky, SKY_COORDS).xyz;
 		COLOR *= exposure;
 	}
 }
-)");
+)",
+																		  i ? "render_mode use_debanding;" : ""));
+		}
 	}
 
 	shader_mutex.unlock();

+ 2 - 2
scene/resources/sky_material.h

@@ -55,7 +55,7 @@ private:
 	bool use_debanding = true;
 
 	static Mutex shader_mutex;
-	static RID shader;
+	static RID shader_cache[2];
 	static void _update_shader();
 	mutable bool shader_set = false;
 
@@ -160,7 +160,7 @@ class PhysicalSkyMaterial : public Material {
 
 private:
 	static Mutex shader_mutex;
-	static RID shader;
+	static RID shader_cache[2];
 
 	float rayleigh = 0.0f;
 	Color rayleigh_color;

+ 1 - 0
servers/rendering/renderer_rd/environment/sky.cpp

@@ -907,6 +907,7 @@ void SkyRD::init() {
 		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.render_mode_defines["use_debanding"] = "#define USE_DEBANDING\n";
 
 		actions.sampler_array_name = "material_samplers";
 		actions.base_texture_binding_index = 1;

+ 13 - 0
servers/rendering/renderer_rd/shaders/environment/sky.glsl

@@ -153,6 +153,15 @@ layout(set = 3, binding = 0) uniform texture3D volumetric_fog_texture;
 
 layout(location = 0) out vec4 frag_color;
 
+#ifdef USE_DEBANDING
+// https://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare
+vec3 interleaved_gradient_noise(vec2 pos) {
+	const vec3 magic = vec3(0.06711056f, 0.00583715f, 52.9829189f);
+	float res = fract(magic.z * fract(dot(pos, magic.xy))) * 2.0 - 1.0;
+	return vec3(res, -res, res) / 255.0;
+}
+#endif
+
 vec4 volumetric_fog_process(vec2 screen_uv) {
 	vec3 fog_pos = vec3(screen_uv, 1.0);
 
@@ -252,4 +261,8 @@ void main() {
 	// For mobile renderer we're multiplying by 0.5 as we're using a UNORM buffer.
 	// For both mobile and clustered, we also bake in the exposure value for the environment and camera.
 	frag_color.rgb = frag_color.rgb * params.luminance_multiplier;
+
+#ifdef USE_DEBANDING
+	frag_color.rgb += interleaved_gradient_noise(gl_FragCoord.xy);
+#endif
 }

+ 1 - 0
servers/rendering/shader_types.cpp

@@ -444,6 +444,7 @@ ShaderTypes::ShaderTypes() {
 		shader_modes[RS::SHADER_SKY].modes.push_back({ PNAME("use_half_res_pass") });
 		shader_modes[RS::SHADER_SKY].modes.push_back({ PNAME("use_quarter_res_pass") });
 		shader_modes[RS::SHADER_SKY].modes.push_back({ PNAME("disable_fog") });
+		shader_modes[RS::SHADER_SKY].modes.push_back({ PNAME("use_debanding") });
 	}
 
 	/************ FOG **************************/