Преглед на файлове

Fix BaseMaterial3D refracting objects located in front of the material

Depth comparison is now used to prevent refraction from occurring
if the pixel being refracted is located in front of the object.

For pixels slightly behind the object, a `smoothstep()` curve
is used to progressively increases refraction intensity
as the distance between the object and the refraction increases.
This avoids sudden discontinuities in the refraction.

Co-authored-by: GeneralLegendary <[email protected]>
Hugo Locurcio преди 1 година
родител
ревизия
8a485ff658
променени са 1 файла, в които са добавени 13 реда и са изтрити 6 реда
  1. 13 6
      scene/resources/material.cpp

+ 13 - 6
scene/resources/material.cpp

@@ -946,7 +946,7 @@ uniform vec4 refraction_texture_channel;
 		code += "uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_linear_mipmap;\n";
 		code += "uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_linear_mipmap;\n";
 	}
 	}
 
 
-	if (proximity_fade_enabled) {
+	if (features[FEATURE_REFRACTION] || proximity_fade_enabled) {
 		code += "uniform sampler2D depth_texture : hint_depth_texture, repeat_disable, filter_nearest;\n";
 		code += "uniform sampler2D depth_texture : hint_depth_texture, repeat_disable, filter_nearest;\n";
 	}
 	}
 
 
@@ -1627,7 +1627,14 @@ void fragment() {)";
 		}
 		}
 		code += R"(
 		code += R"(
 	float ref_amount = 1.0 - albedo.a * albedo_tex.a;
 	float ref_amount = 1.0 - albedo.a * albedo_tex.a;
-	EMISSION += textureLod(screen_texture, ref_ofs, ROUGHNESS * 8.0).rgb * ref_amount * EXPOSURE;
+
+	float refraction_depth_tex = textureLod(depth_texture, ref_ofs, 0.0).r;
+	vec4 refraction_view_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV * 2.0 - 1.0, refraction_depth_tex, 1.0);
+	refraction_view_pos.xyz /= refraction_view_pos.w;
+
+	// If the depth buffer is lower then the model's Z position, use the refracted UV, otherwise use the normal screen UV.
+	// At low depth differences, decrease refraction intensity to avoid sudden discontinuities.
+	EMISSION += textureLod(screen_texture, mix(SCREEN_UV, ref_ofs, smoothstep(0.0, 1.0, VERTEX.z - refraction_view_pos.z)), ROUGHNESS * 8.0).rgb * ref_amount * EXPOSURE;
 	ALBEDO *= 1.0 - ref_amount;
 	ALBEDO *= 1.0 - ref_amount;
 	// Force transparency on the material (required for refraction).
 	// Force transparency on the material (required for refraction).
 	ALPHA = 1.0;
 	ALPHA = 1.0;
@@ -1649,10 +1656,10 @@ void fragment() {)";
 	if (proximity_fade_enabled) {
 	if (proximity_fade_enabled) {
 		code += R"(
 		code += R"(
 	// Proximity Fade: Enabled
 	// Proximity Fade: Enabled
-	float depth_tex = textureLod(depth_texture, SCREEN_UV, 0.0).r;
-	vec4 world_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV * 2.0 - 1.0, depth_tex, 1.0);
-	world_pos.xyz /= world_pos.w;
-	ALPHA *= clamp(1.0 - smoothstep(world_pos.z + proximity_fade_distance, world_pos.z, VERTEX.z), 0.0, 1.0);
+	float proximity_depth_tex = textureLod(depth_texture, SCREEN_UV, 0.0).r;
+	vec4 proximity_view_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV * 2.0 - 1.0, proximity_depth_tex, 1.0);
+	proximity_view_pos.xyz /= proximity_view_pos.w;
+	ALPHA *= clamp(1.0 - smoothstep(proximity_view_pos.z + proximity_fade_distance, proximity_view_pos.z, VERTEX.z), 0.0, 1.0);
 )";
 )";
 	}
 	}