Browse Source

Add depth function for spatial materials

Apples 1 year ago
parent
commit
7574a5dbb3

+ 10 - 0
doc/classes/BaseMaterial3D.xml

@@ -159,6 +159,10 @@
 		<member name="depth_draw_mode" type="int" setter="set_depth_draw_mode" getter="get_depth_draw_mode" enum="BaseMaterial3D.DepthDrawMode" default="0">
 		<member name="depth_draw_mode" type="int" setter="set_depth_draw_mode" getter="get_depth_draw_mode" enum="BaseMaterial3D.DepthDrawMode" default="0">
 			Determines when depth rendering takes place. See also [member transparency].
 			Determines when depth rendering takes place. See also [member transparency].
 		</member>
 		</member>
+		<member name="depth_test" type="int" setter="set_depth_test" getter="get_depth_test" enum="BaseMaterial3D.DepthTest" default="0" experimental="May be affected by future rendering pipeline changes.">
+			Determines which comparison operator is used when testing depth. See [enum DepthTest].
+			[b]Note:[/b] Changing [member depth_test] to a non-default value only has a visible effect when used on a transparent material, or a material that has [member depth_draw_mode] set to [constant DEPTH_DRAW_DISABLED].
+		</member>
 		<member name="detail_albedo" type="Texture2D" setter="set_texture" getter="get_texture">
 		<member name="detail_albedo" type="Texture2D" setter="set_texture" getter="get_texture">
 			Texture that specifies the color of the detail overlay. [member detail_albedo]'s alpha channel is used as a mask, even when the material is opaque. To use a dedicated texture as a mask, see [member detail_mask].
 			Texture that specifies the color of the detail overlay. [member detail_albedo]'s alpha channel is used as a mask, even when the material is opaque. To use a dedicated texture as a mask, see [member detail_mask].
 			[b]Note:[/b] [member detail_albedo] is [i]not[/i] modulated by [member albedo_color].
 			[b]Note:[/b] [member detail_albedo] is [i]not[/i] modulated by [member albedo_color].
@@ -661,6 +665,12 @@
 		<constant name="DEPTH_DRAW_DISABLED" value="2" enum="DepthDrawMode">
 		<constant name="DEPTH_DRAW_DISABLED" value="2" enum="DepthDrawMode">
 			Objects will not write their depth to the depth buffer, even during the depth prepass (if enabled).
 			Objects will not write their depth to the depth buffer, even during the depth prepass (if enabled).
 		</constant>
 		</constant>
+		<constant name="DEPTH_TEST_DEFAULT" value="0" enum="DepthTest">
+			Depth test will discard the pixel if it is behind other pixels.
+		</constant>
+		<constant name="DEPTH_TEST_INVERTED" value="1" enum="DepthTest">
+			Depth test will discard the pixel if it is in front of other pixels. Useful for stencil effects.
+		</constant>
 		<constant name="CULL_BACK" value="0" enum="CullMode">
 		<constant name="CULL_BACK" value="0" enum="CullMode">
 			Default cull mode. The back of the object is culled when not visible. Back face triangles will be culled when facing the camera. This results in only the front side of triangles being drawn. For closed-surface meshes, this means that only the exterior of the mesh will be visible.
 			Default cull mode. The back of the object is culled when not visible. Back face triangles will be culled when facing the camera. This results in only the front side of triangles being drawn. For closed-surface meshes, this means that only the exterior of the mesh will be visible.
 		</constant>
 		</constant>

+ 17 - 9
drivers/gles3/rasterizer_scene_gles3.cpp

@@ -32,6 +32,7 @@
 
 
 #include "drivers/gles3/effects/copy_effects.h"
 #include "drivers/gles3/effects/copy_effects.h"
 #include "drivers/gles3/effects/feed_effects.h"
 #include "drivers/gles3/effects/feed_effects.h"
+#include "drivers/gles3/storage/material_storage.h"
 #include "rasterizer_gles3.h"
 #include "rasterizer_gles3.h"
 #include "storage/config.h"
 #include "storage/config.h"
 #include "storage/mesh_storage.h"
 #include "storage/mesh_storage.h"
@@ -223,10 +224,10 @@ void RasterizerSceneGLES3::_geometry_instance_add_surface_with_material(Geometry
 		flags |= GeometryInstanceSurface::FLAG_USES_DOUBLE_SIDED_SHADOWS;
 		flags |= GeometryInstanceSurface::FLAG_USES_DOUBLE_SIDED_SHADOWS;
 	}
 	}
 
 
-	if (has_alpha || has_read_screen_alpha || p_material->shader_data->depth_draw == GLES3::SceneShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == GLES3::SceneShaderData::DEPTH_TEST_DISABLED) {
+	if (has_alpha || has_read_screen_alpha || p_material->shader_data->depth_draw == GLES3::SceneShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test != GLES3::SceneShaderData::DEPTH_TEST_ENABLED) {
 		//material is only meant for alpha pass
 		//material is only meant for alpha pass
 		flags |= GeometryInstanceSurface::FLAG_PASS_ALPHA;
 		flags |= GeometryInstanceSurface::FLAG_PASS_ALPHA;
-		if (p_material->shader_data->uses_depth_prepass_alpha && !(p_material->shader_data->depth_draw == GLES3::SceneShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == GLES3::SceneShaderData::DEPTH_TEST_DISABLED)) {
+		if (p_material->shader_data->uses_depth_prepass_alpha && !(p_material->shader_data->depth_draw == GLES3::SceneShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test != GLES3::SceneShaderData::DEPTH_TEST_ENABLED)) {
 			flags |= GeometryInstanceSurface::FLAG_PASS_DEPTH;
 			flags |= GeometryInstanceSurface::FLAG_PASS_DEPTH;
 			flags |= GeometryInstanceSurface::FLAG_PASS_SHADOW;
 			flags |= GeometryInstanceSurface::FLAG_PASS_SHADOW;
 		}
 		}
@@ -2184,7 +2185,7 @@ void RasterizerSceneGLES3::_render_shadow_pass(RID p_light, RID p_shadow_atlas,
 	scene_state.reset_gl_state();
 	scene_state.reset_gl_state();
 	scene_state.enable_gl_depth_test(true);
 	scene_state.enable_gl_depth_test(true);
 	scene_state.enable_gl_depth_draw(true);
 	scene_state.enable_gl_depth_draw(true);
-	glDepthFunc(GL_GREATER);
+	scene_state.set_gl_depth_func(GL_GREATER);
 
 
 	glColorMask(0, 0, 0, 0);
 	glColorMask(0, 0, 0, 0);
 	glDrawBuffers(0, nullptr);
 	glDrawBuffers(0, nullptr);
@@ -2503,7 +2504,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
 		scene_state.enable_gl_depth_test(true);
 		scene_state.enable_gl_depth_test(true);
 		scene_state.enable_gl_depth_draw(true);
 		scene_state.enable_gl_depth_draw(true);
 		scene_state.enable_gl_blend(false);
 		scene_state.enable_gl_blend(false);
-		glDepthFunc(GL_GEQUAL);
+		scene_state.set_gl_depth_func(GL_GEQUAL);
 		scene_state.enable_gl_scissor_test(false);
 		scene_state.enable_gl_scissor_test(false);
 
 
 		glColorMask(0, 0, 0, 0);
 		glColorMask(0, 0, 0, 0);
@@ -2541,7 +2542,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
 	scene_state.enable_gl_scissor_test(false);
 	scene_state.enable_gl_scissor_test(false);
 	scene_state.enable_gl_depth_test(true);
 	scene_state.enable_gl_depth_test(true);
 	scene_state.enable_gl_depth_draw(true);
 	scene_state.enable_gl_depth_draw(true);
-	glDepthFunc(GL_GEQUAL);
+	scene_state.set_gl_depth_func(GL_GEQUAL);
 
 
 	{
 	{
 		GLuint db = GL_COLOR_ATTACHMENT0;
 		GLuint db = GL_COLOR_ATTACHMENT0;
@@ -2635,6 +2636,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
 		RENDER_TIMESTAMP("Render Sky");
 		RENDER_TIMESTAMP("Render Sky");
 
 
 		scene_state.enable_gl_depth_test(true);
 		scene_state.enable_gl_depth_test(true);
+		scene_state.set_gl_depth_func(GL_GEQUAL);
 		scene_state.enable_gl_blend(false);
 		scene_state.enable_gl_blend(false);
 		scene_state.set_gl_cull_mode(RS::CULL_MODE_BACK);
 		scene_state.set_gl_cull_mode(RS::CULL_MODE_BACK);
 
 
@@ -3016,7 +3018,13 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
 		}
 		}
 
 
 		if constexpr (p_pass_mode == PASS_MODE_COLOR_TRANSPARENT) {
 		if constexpr (p_pass_mode == PASS_MODE_COLOR_TRANSPARENT) {
-			scene_state.enable_gl_depth_test(shader->depth_test == GLES3::SceneShaderData::DEPTH_TEST_ENABLED);
+			scene_state.enable_gl_depth_test(shader->depth_test != GLES3::SceneShaderData::DEPTH_TEST_DISABLED);
+		}
+
+		if (shader->depth_test == GLES3::SceneShaderData::DEPTH_TEST_ENABLED_INVERTED) {
+			scene_state.set_gl_depth_func(GL_LESS);
+		} else {
+			scene_state.set_gl_depth_func(GL_GEQUAL);
 		}
 		}
 
 
 		if constexpr (p_pass_mode != PASS_MODE_SHADOW) {
 		if constexpr (p_pass_mode != PASS_MODE_SHADOW) {
@@ -3713,7 +3721,7 @@ void RasterizerSceneGLES3::render_particle_collider_heightfield(RID p_collider,
 	scene_state.reset_gl_state();
 	scene_state.reset_gl_state();
 	scene_state.enable_gl_depth_test(true);
 	scene_state.enable_gl_depth_test(true);
 	scene_state.enable_gl_depth_draw(true);
 	scene_state.enable_gl_depth_draw(true);
-	glDepthFunc(GL_GREATER);
+	scene_state.set_gl_depth_func(GL_GREATER);
 
 
 	glDrawBuffers(0, nullptr);
 	glDrawBuffers(0, nullptr);
 
 
@@ -3759,7 +3767,7 @@ void RasterizerSceneGLES3::_render_uv2(const PagedArray<RenderGeometryInstance *
 		scene_state.reset_gl_state();
 		scene_state.reset_gl_state();
 		scene_state.enable_gl_depth_test(true);
 		scene_state.enable_gl_depth_test(true);
 		scene_state.enable_gl_depth_draw(true);
 		scene_state.enable_gl_depth_draw(true);
-		glDepthFunc(GL_GREATER);
+		scene_state.set_gl_depth_func(GL_GREATER);
 
 
 		TightLocalVector<GLenum> draw_buffers;
 		TightLocalVector<GLenum> draw_buffers;
 		draw_buffers.push_back(GL_COLOR_ATTACHMENT0);
 		draw_buffers.push_back(GL_COLOR_ATTACHMENT0);
@@ -3852,7 +3860,7 @@ void RasterizerSceneGLES3::_render_buffers_debug_draw(Ref<RenderSceneBuffersGLES
 			glViewport(0, 0, shadow_atlas_size, shadow_atlas_size);
 			glViewport(0, 0, shadow_atlas_size, shadow_atlas_size);
 			glActiveTexture(GL_TEXTURE0);
 			glActiveTexture(GL_TEXTURE0);
 			scene_state.enable_gl_depth_draw(true);
 			scene_state.enable_gl_depth_draw(true);
-			glDepthFunc(GL_ALWAYS);
+			scene_state.set_gl_depth_func(GL_ALWAYS);
 			scene_state.set_gl_cull_mode(RS::CULL_MODE_DISABLED);
 			scene_state.set_gl_cull_mode(RS::CULL_MODE_DISABLED);
 
 
 			// Loop through quadrants and copy shadows over.
 			// Loop through quadrants and copy shadows over.

+ 12 - 0
drivers/gles3/rasterizer_scene_gles3.h

@@ -30,6 +30,7 @@
 
 
 #pragma once
 #pragma once
 
 
+#include "platform_gl.h"
 #ifdef GLES3_ENABLED
 #ifdef GLES3_ENABLED
 
 
 #include "core/math/projection.h"
 #include "core/math/projection.h"
@@ -462,6 +463,7 @@ private:
 
 
 		GLES3::SceneShaderData::BlendMode current_blend_mode = GLES3::SceneShaderData::BLEND_MODE_MIX;
 		GLES3::SceneShaderData::BlendMode current_blend_mode = GLES3::SceneShaderData::BLEND_MODE_MIX;
 		RS::CullMode cull_mode = RS::CULL_MODE_BACK;
 		RS::CullMode cull_mode = RS::CULL_MODE_BACK;
+		GLenum current_depth_function = GL_GEQUAL;
 
 
 		bool current_blend_enabled = false;
 		bool current_blend_enabled = false;
 		bool current_depth_draw_enabled = false;
 		bool current_depth_draw_enabled = false;
@@ -483,6 +485,9 @@ private:
 			current_depth_draw_enabled = false;
 			current_depth_draw_enabled = false;
 			glDisable(GL_DEPTH_TEST);
 			glDisable(GL_DEPTH_TEST);
 			current_depth_test_enabled = false;
 			current_depth_test_enabled = false;
+
+			glDepthFunc(GL_GEQUAL);
+			current_depth_function = GL_GEQUAL;
 		}
 		}
 
 
 		void set_gl_cull_mode(RS::CullMode p_mode) {
 		void set_gl_cull_mode(RS::CullMode p_mode) {
@@ -540,6 +545,13 @@ private:
 			}
 			}
 		}
 		}
 
 
+		void set_gl_depth_func(GLenum p_depth_func) {
+			if (current_depth_function != p_depth_func) {
+				glDepthFunc(p_depth_func);
+				current_depth_function = p_depth_func;
+			}
+		}
+
 		bool texscreen_copied = false;
 		bool texscreen_copied = false;
 		bool used_screen_texture = false;
 		bool used_screen_texture = false;
 		bool used_normal_texture = false;
 		bool used_normal_texture = false;

+ 12 - 4
drivers/gles3/storage/material_storage.cpp

@@ -2941,7 +2941,8 @@ void SceneShaderData::set_code(const String &p_code) {
 
 
 	// Actual enums set further down after compilation.
 	// Actual enums set further down after compilation.
 	int blend_modei = BLEND_MODE_MIX;
 	int blend_modei = BLEND_MODE_MIX;
-	int depth_testi = DEPTH_TEST_ENABLED;
+	int depth_test_disabledi = 0;
+	int depth_test_invertedi = 0;
 	int alpha_antialiasing_modei = ALPHA_ANTIALIASING_OFF;
 	int alpha_antialiasing_modei = ALPHA_ANTIALIASING_OFF;
 	int cull_modei = RS::CULL_MODE_BACK;
 	int cull_modei = RS::CULL_MODE_BACK;
 	int depth_drawi = DEPTH_DRAW_OPAQUE;
 	int depth_drawi = DEPTH_DRAW_OPAQUE;
@@ -2964,7 +2965,8 @@ void SceneShaderData::set_code(const String &p_code) {
 	actions.render_mode_values["depth_draw_opaque"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_OPAQUE);
 	actions.render_mode_values["depth_draw_opaque"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_OPAQUE);
 	actions.render_mode_values["depth_draw_always"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_ALWAYS);
 	actions.render_mode_values["depth_draw_always"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_ALWAYS);
 
 
-	actions.render_mode_values["depth_test_disabled"] = Pair<int *, int>(&depth_testi, DEPTH_TEST_DISABLED);
+	actions.render_mode_values["depth_test_disabled"] = Pair<int *, int>(&depth_test_disabledi, 1);
+	actions.render_mode_values["depth_test_inverted"] = Pair<int *, int>(&depth_test_invertedi, 1);
 
 
 	actions.render_mode_values["cull_disabled"] = Pair<int *, int>(&cull_modei, RS::CULL_MODE_DISABLED);
 	actions.render_mode_values["cull_disabled"] = Pair<int *, int>(&cull_modei, RS::CULL_MODE_DISABLED);
 	actions.render_mode_values["cull_front"] = Pair<int *, int>(&cull_modei, RS::CULL_MODE_FRONT);
 	actions.render_mode_values["cull_front"] = Pair<int *, int>(&cull_modei, RS::CULL_MODE_FRONT);
@@ -3026,7 +3028,13 @@ void SceneShaderData::set_code(const String &p_code) {
 	blend_mode = BlendMode(blend_modei);
 	blend_mode = BlendMode(blend_modei);
 	alpha_antialiasing_mode = AlphaAntiAliasing(alpha_antialiasing_modei);
 	alpha_antialiasing_mode = AlphaAntiAliasing(alpha_antialiasing_modei);
 	depth_draw = DepthDraw(depth_drawi);
 	depth_draw = DepthDraw(depth_drawi);
-	depth_test = DepthTest(depth_testi);
+	if (depth_test_disabledi) {
+		depth_test = DEPTH_TEST_DISABLED;
+	} else if (depth_test_invertedi) {
+		depth_test = DEPTH_TEST_ENABLED_INVERTED;
+	} else {
+		depth_test = DEPTH_TEST_ENABLED;
+	}
 	cull_mode = RS::CullMode(cull_modei);
 	cull_mode = RS::CullMode(cull_modei);
 
 
 	vertex_input_mask = RS::ARRAY_FORMAT_VERTEX | RS::ARRAY_FORMAT_NORMAL; // We can always read vertices and normals.
 	vertex_input_mask = RS::ARRAY_FORMAT_VERTEX | RS::ARRAY_FORMAT_NORMAL; // We can always read vertices and normals.
@@ -3114,7 +3122,7 @@ bool SceneShaderData::casts_shadows() const {
 	bool has_base_alpha = (uses_alpha && !uses_alpha_clip) || has_read_screen_alpha;
 	bool has_base_alpha = (uses_alpha && !uses_alpha_clip) || has_read_screen_alpha;
 	bool has_alpha = has_base_alpha || uses_blend_alpha;
 	bool has_alpha = has_base_alpha || uses_blend_alpha;
 
 
-	return !has_alpha || (uses_depth_prepass_alpha && !(depth_draw == DEPTH_DRAW_DISABLED || depth_test == DEPTH_TEST_DISABLED));
+	return !has_alpha || (uses_depth_prepass_alpha && !(depth_draw == DEPTH_DRAW_DISABLED || depth_test != DEPTH_TEST_ENABLED));
 }
 }
 
 
 RS::ShaderNativeSourceCode SceneShaderData::get_native_source_code() const {
 RS::ShaderNativeSourceCode SceneShaderData::get_native_source_code() const {

+ 2 - 1
drivers/gles3/storage/material_storage.h

@@ -257,7 +257,8 @@ struct SceneShaderData : public ShaderData {
 
 
 	enum DepthTest {
 	enum DepthTest {
 		DEPTH_TEST_DISABLED,
 		DEPTH_TEST_DISABLED,
-		DEPTH_TEST_ENABLED
+		DEPTH_TEST_ENABLED,
+		DEPTH_TEST_ENABLED_INVERTED,
 	};
 	};
 
 
 	enum AlphaAntiAliasing {
 	enum AlphaAntiAliasing {

+ 37 - 1
scene/resources/material.cpp

@@ -861,6 +861,17 @@ void BaseMaterial3D::_update_shader() {
 	}
 	}
 	if (flags[FLAG_DISABLE_DEPTH_TEST]) {
 	if (flags[FLAG_DISABLE_DEPTH_TEST]) {
 		code += ", depth_test_disabled";
 		code += ", depth_test_disabled";
+	} else {
+		switch (depth_test) {
+			case DEPTH_TEST_DEFAULT:
+				// depth_test_default is the default behavior, no need to emit it here.
+				break;
+			case DEPTH_TEST_INVERTED:
+				code += ", depth_test_inverted";
+				break;
+			case DEPTH_TEST_MAX:
+				break; // Internal value, skip.
+		}
 	}
 	}
 	if (flags[FLAG_PARTICLE_TRAILS_MODE]) {
 	if (flags[FLAG_PARTICLE_TRAILS_MODE]) {
 		code += ", particle_trails";
 		code += ", particle_trails";
@@ -2354,6 +2365,19 @@ BaseMaterial3D::DepthDrawMode BaseMaterial3D::get_depth_draw_mode() const {
 	return depth_draw_mode;
 	return depth_draw_mode;
 }
 }
 
 
+void BaseMaterial3D::set_depth_test(DepthTest p_func) {
+	if (depth_test == p_func) {
+		return;
+	}
+
+	depth_test = p_func;
+	_queue_shader_change();
+}
+
+BaseMaterial3D::DepthTest BaseMaterial3D::get_depth_test() const {
+	return depth_test;
+}
+
 void BaseMaterial3D::set_cull_mode(CullMode p_mode) {
 void BaseMaterial3D::set_cull_mode(CullMode p_mode) {
 	if (cull_mode == p_mode) {
 	if (cull_mode == p_mode) {
 		return;
 		return;
@@ -2410,7 +2434,8 @@ void BaseMaterial3D::set_flag(Flags p_flag, bool p_enabled) {
 			p_flag == FLAG_UV1_USE_TRIPLANAR ||
 			p_flag == FLAG_UV1_USE_TRIPLANAR ||
 			p_flag == FLAG_UV2_USE_TRIPLANAR ||
 			p_flag == FLAG_UV2_USE_TRIPLANAR ||
 			p_flag == FLAG_USE_Z_CLIP_SCALE ||
 			p_flag == FLAG_USE_Z_CLIP_SCALE ||
-			p_flag == FLAG_USE_FOV_OVERRIDE) {
+			p_flag == FLAG_USE_FOV_OVERRIDE ||
+			p_flag == FLAG_DISABLE_DEPTH_TEST) {
 		notify_property_list_changed();
 		notify_property_list_changed();
 	}
 	}
 
 
@@ -2565,6 +2590,10 @@ void BaseMaterial3D::_validate_property(PropertyInfo &p_property) const {
 		p_property.usage = PROPERTY_USAGE_NONE;
 		p_property.usage = PROPERTY_USAGE_NONE;
 	}
 	}
 
 
+	if (p_property.name == "depth_test" && flags[FLAG_DISABLE_DEPTH_TEST]) {
+		p_property.usage = PROPERTY_USAGE_NONE;
+	}
+
 	if (flags[FLAG_SUBSURFACE_MODE_SKIN] && (p_property.name == "subsurf_scatter_transmittance_color" || p_property.name == "subsurf_scatter_transmittance_texture")) {
 	if (flags[FLAG_SUBSURFACE_MODE_SKIN] && (p_property.name == "subsurf_scatter_transmittance_color" || p_property.name == "subsurf_scatter_transmittance_texture")) {
 		p_property.usage = PROPERTY_USAGE_NONE;
 		p_property.usage = PROPERTY_USAGE_NONE;
 	}
 	}
@@ -3133,6 +3162,9 @@ void BaseMaterial3D::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_depth_draw_mode", "depth_draw_mode"), &BaseMaterial3D::set_depth_draw_mode);
 	ClassDB::bind_method(D_METHOD("set_depth_draw_mode", "depth_draw_mode"), &BaseMaterial3D::set_depth_draw_mode);
 	ClassDB::bind_method(D_METHOD("get_depth_draw_mode"), &BaseMaterial3D::get_depth_draw_mode);
 	ClassDB::bind_method(D_METHOD("get_depth_draw_mode"), &BaseMaterial3D::get_depth_draw_mode);
 
 
+	ClassDB::bind_method(D_METHOD("set_depth_test", "depth_test"), &BaseMaterial3D::set_depth_test);
+	ClassDB::bind_method(D_METHOD("get_depth_test"), &BaseMaterial3D::get_depth_test);
+
 	ClassDB::bind_method(D_METHOD("set_cull_mode", "cull_mode"), &BaseMaterial3D::set_cull_mode);
 	ClassDB::bind_method(D_METHOD("set_cull_mode", "cull_mode"), &BaseMaterial3D::set_cull_mode);
 	ClassDB::bind_method(D_METHOD("get_cull_mode"), &BaseMaterial3D::get_cull_mode);
 	ClassDB::bind_method(D_METHOD("get_cull_mode"), &BaseMaterial3D::get_cull_mode);
 
 
@@ -3269,6 +3301,7 @@ void BaseMaterial3D::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "cull_mode", PROPERTY_HINT_ENUM, "Back,Front,Disabled"), "set_cull_mode", "get_cull_mode");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "cull_mode", PROPERTY_HINT_ENUM, "Back,Front,Disabled"), "set_cull_mode", "get_cull_mode");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "depth_draw_mode", PROPERTY_HINT_ENUM, "Opaque Only,Always,Never"), "set_depth_draw_mode", "get_depth_draw_mode");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "depth_draw_mode", PROPERTY_HINT_ENUM, "Opaque Only,Always,Never"), "set_depth_draw_mode", "get_depth_draw_mode");
 	ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "no_depth_test"), "set_flag", "get_flag", FLAG_DISABLE_DEPTH_TEST);
 	ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "no_depth_test"), "set_flag", "get_flag", FLAG_DISABLE_DEPTH_TEST);
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "depth_test", PROPERTY_HINT_ENUM, "Default,Inverted"), "set_depth_test", "get_depth_test");
 
 
 	ADD_GROUP("Shading", "");
 	ADD_GROUP("Shading", "");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "shading_mode", PROPERTY_HINT_ENUM, "Unshaded,Per-Pixel,Per-Vertex"), "set_shading_mode", "get_shading_mode");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "shading_mode", PROPERTY_HINT_ENUM, "Unshaded,Per-Pixel,Per-Vertex"), "set_shading_mode", "get_shading_mode");
@@ -3518,6 +3551,9 @@ void BaseMaterial3D::_bind_methods() {
 	BIND_ENUM_CONSTANT(DEPTH_DRAW_ALWAYS);
 	BIND_ENUM_CONSTANT(DEPTH_DRAW_ALWAYS);
 	BIND_ENUM_CONSTANT(DEPTH_DRAW_DISABLED);
 	BIND_ENUM_CONSTANT(DEPTH_DRAW_DISABLED);
 
 
+	BIND_ENUM_CONSTANT(DEPTH_TEST_DEFAULT);
+	BIND_ENUM_CONSTANT(DEPTH_TEST_INVERTED);
+
 	BIND_ENUM_CONSTANT(CULL_BACK);
 	BIND_ENUM_CONSTANT(CULL_BACK);
 	BIND_ENUM_CONSTANT(CULL_FRONT);
 	BIND_ENUM_CONSTANT(CULL_FRONT);
 	BIND_ENUM_CONSTANT(CULL_DISABLED);
 	BIND_ENUM_CONSTANT(CULL_DISABLED);

+ 13 - 0
scene/resources/material.h

@@ -238,6 +238,12 @@ public:
 		DEPTH_DRAW_MAX
 		DEPTH_DRAW_MAX
 	};
 	};
 
 
+	enum DepthTest {
+		DEPTH_TEST_DEFAULT,
+		DEPTH_TEST_INVERTED,
+		DEPTH_TEST_MAX
+	};
+
 	enum CullMode {
 	enum CullMode {
 		CULL_BACK,
 		CULL_BACK,
 		CULL_FRONT,
 		CULL_FRONT,
@@ -330,6 +336,7 @@ private:
 		uint64_t shading_mode : get_num_bits(SHADING_MODE_MAX - 1);
 		uint64_t shading_mode : get_num_bits(SHADING_MODE_MAX - 1);
 		uint64_t blend_mode : get_num_bits(BLEND_MODE_MAX - 1);
 		uint64_t blend_mode : get_num_bits(BLEND_MODE_MAX - 1);
 		uint64_t depth_draw_mode : get_num_bits(DEPTH_DRAW_MAX - 1);
 		uint64_t depth_draw_mode : get_num_bits(DEPTH_DRAW_MAX - 1);
+		uint64_t depth_test : get_num_bits(DEPTH_TEST_MAX - 1);
 		uint64_t cull_mode : get_num_bits(CULL_MAX - 1);
 		uint64_t cull_mode : get_num_bits(CULL_MAX - 1);
 		uint64_t diffuse_mode : get_num_bits(DIFFUSE_MAX - 1);
 		uint64_t diffuse_mode : get_num_bits(DIFFUSE_MAX - 1);
 		uint64_t specular_mode : get_num_bits(SPECULAR_MAX - 1);
 		uint64_t specular_mode : get_num_bits(SPECULAR_MAX - 1);
@@ -381,6 +388,7 @@ private:
 		mk.detail_uv = detail_uv;
 		mk.detail_uv = detail_uv;
 		mk.blend_mode = blend_mode;
 		mk.blend_mode = blend_mode;
 		mk.depth_draw_mode = depth_draw_mode;
 		mk.depth_draw_mode = depth_draw_mode;
+		mk.depth_test = depth_test;
 		mk.cull_mode = cull_mode;
 		mk.cull_mode = cull_mode;
 		mk.texture_filter = texture_filter;
 		mk.texture_filter = texture_filter;
 		mk.transparency = transparency;
 		mk.transparency = transparency;
@@ -553,6 +561,7 @@ private:
 	BlendMode blend_mode = BLEND_MODE_MIX;
 	BlendMode blend_mode = BLEND_MODE_MIX;
 	BlendMode detail_blend_mode = BLEND_MODE_MIX;
 	BlendMode detail_blend_mode = BLEND_MODE_MIX;
 	DepthDrawMode depth_draw_mode = DEPTH_DRAW_OPAQUE_ONLY;
 	DepthDrawMode depth_draw_mode = DEPTH_DRAW_OPAQUE_ONLY;
+	DepthTest depth_test = DEPTH_TEST_DEFAULT;
 	CullMode cull_mode = CULL_BACK;
 	CullMode cull_mode = CULL_BACK;
 	bool flags[FLAG_MAX] = {};
 	bool flags[FLAG_MAX] = {};
 	SpecularMode specular_mode = SPECULAR_SCHLICK_GGX;
 	SpecularMode specular_mode = SPECULAR_SCHLICK_GGX;
@@ -688,6 +697,9 @@ public:
 	void set_depth_draw_mode(DepthDrawMode p_mode);
 	void set_depth_draw_mode(DepthDrawMode p_mode);
 	DepthDrawMode get_depth_draw_mode() const;
 	DepthDrawMode get_depth_draw_mode() const;
 
 
+	void set_depth_test(DepthTest p_func);
+	DepthTest get_depth_test() const;
+
 	void set_cull_mode(CullMode p_mode);
 	void set_cull_mode(CullMode p_mode);
 	CullMode get_cull_mode() const;
 	CullMode get_cull_mode() const;
 
 
@@ -816,6 +828,7 @@ VARIANT_ENUM_CAST(BaseMaterial3D::DetailUV)
 VARIANT_ENUM_CAST(BaseMaterial3D::Feature)
 VARIANT_ENUM_CAST(BaseMaterial3D::Feature)
 VARIANT_ENUM_CAST(BaseMaterial3D::BlendMode)
 VARIANT_ENUM_CAST(BaseMaterial3D::BlendMode)
 VARIANT_ENUM_CAST(BaseMaterial3D::DepthDrawMode)
 VARIANT_ENUM_CAST(BaseMaterial3D::DepthDrawMode)
+VARIANT_ENUM_CAST(BaseMaterial3D::DepthTest)
 VARIANT_ENUM_CAST(BaseMaterial3D::CullMode)
 VARIANT_ENUM_CAST(BaseMaterial3D::CullMode)
 VARIANT_ENUM_CAST(BaseMaterial3D::Flags)
 VARIANT_ENUM_CAST(BaseMaterial3D::Flags)
 VARIANT_ENUM_CAST(BaseMaterial3D::DiffuseMode)
 VARIANT_ENUM_CAST(BaseMaterial3D::DiffuseMode)

+ 40 - 0
scene/resources/visual_shader.cpp

@@ -1886,6 +1886,29 @@ void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const {
 	for (int i = 0; i < rmodes.size(); i++) {
 	for (int i = 0; i < rmodes.size(); i++) {
 		const ShaderLanguage::ModeInfo &info = rmodes[i];
 		const ShaderLanguage::ModeInfo &info = rmodes[i];
 
 
+		// Special handling for depth_test.
+		if (info.name == "depth_test") {
+			toggles.insert("depth_test_disabled");
+
+			const String begin = String(info.name);
+
+			for (int j = 0; j < info.options.size(); j++) {
+				if (info.options[j] == "disabled") {
+					continue;
+				}
+
+				const String option = String(info.options[j]).capitalize();
+
+				if (!blend_mode_enums.has(begin)) {
+					blend_mode_enums[begin] = vformat("%s:%s", option, j);
+				} else {
+					blend_mode_enums[begin] += "," + vformat("%s:%s", option, j);
+				}
+			}
+
+			continue;
+		}
+
 		if (!info.options.is_empty()) {
 		if (!info.options.is_empty()) {
 			const String begin = String(info.name);
 			const String begin = String(info.name);
 
 
@@ -2550,6 +2573,23 @@ void VisualShader::_update_shader() const {
 			const ShaderLanguage::ModeInfo &info = rmodes[i];
 			const ShaderLanguage::ModeInfo &info = rmodes[i];
 			const String temp = String(info.name);
 			const String temp = String(info.name);
 
 
+			// Special handling for depth_test.
+			if (temp == "depth_test") {
+				if (flags.has("depth_test_disabled")) {
+					flag_names.push_back("depth_test_disabled");
+				} else {
+					if (!render_mode.is_empty()) {
+						render_mode += ", ";
+					}
+					if (modes.has(temp) && modes[temp] < info.options.size()) {
+						render_mode += temp + "_" + info.options[modes[temp]];
+					} else {
+						render_mode += temp + "_" + info.options[0];
+					}
+				}
+				continue;
+			}
+
 			if (!info.options.is_empty()) {
 			if (!info.options.is_empty()) {
 				if (!render_mode.is_empty()) {
 				if (!render_mode.is_empty()) {
 					render_mode += ", ";
 					render_mode += ", ";

+ 17 - 5
servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp

@@ -52,7 +52,8 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
 	ShaderCompiler::GeneratedCode gen_code;
 	ShaderCompiler::GeneratedCode gen_code;
 
 
 	blend_mode = BLEND_MODE_MIX;
 	blend_mode = BLEND_MODE_MIX;
-	depth_testi = DEPTH_TEST_ENABLED;
+	depth_test_disabledi = 0;
+	depth_test_invertedi = 0;
 	alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF;
 	alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF;
 	int cull_modei = RS::CULL_MODE_BACK;
 	int cull_modei = RS::CULL_MODE_BACK;
 
 
@@ -101,7 +102,8 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
 	actions.render_mode_values["depth_draw_opaque"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_OPAQUE);
 	actions.render_mode_values["depth_draw_opaque"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_OPAQUE);
 	actions.render_mode_values["depth_draw_always"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_ALWAYS);
 	actions.render_mode_values["depth_draw_always"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_ALWAYS);
 
 
-	actions.render_mode_values["depth_test_disabled"] = Pair<int *, int>(&depth_testi, DEPTH_TEST_DISABLED);
+	actions.render_mode_values["depth_test_disabled"] = Pair<int *, int>(&depth_test_disabledi, 1);
+	actions.render_mode_values["depth_test_inverted"] = Pair<int *, int>(&depth_test_invertedi, 1);
 
 
 	actions.render_mode_values["cull_disabled"] = Pair<int *, int>(&cull_modei, RS::CULL_MODE_DISABLED);
 	actions.render_mode_values["cull_disabled"] = Pair<int *, int>(&cull_modei, RS::CULL_MODE_DISABLED);
 	actions.render_mode_values["cull_front"] = Pair<int *, int>(&cull_modei, RS::CULL_MODE_FRONT);
 	actions.render_mode_values["cull_front"] = Pair<int *, int>(&cull_modei, RS::CULL_MODE_FRONT);
@@ -164,7 +166,13 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
 	}
 	}
 
 
 	depth_draw = DepthDraw(depth_drawi);
 	depth_draw = DepthDraw(depth_drawi);
-	depth_test = DepthTest(depth_testi);
+	if (depth_test_disabledi) {
+		depth_test = DEPTH_TEST_DISABLED;
+	} else if (depth_test_invertedi) {
+		depth_test = DEPTH_TEST_ENABLED_INVERTED;
+	} else {
+		depth_test = DEPTH_TEST_ENABLED;
+	}
 	cull_mode = RS::CullMode(cull_modei);
 	cull_mode = RS::CullMode(cull_modei);
 	uses_screen_texture_mipmaps = gen_code.uses_screen_texture_mipmaps;
 	uses_screen_texture_mipmaps = gen_code.uses_screen_texture_mipmaps;
 	uses_screen_texture = gen_code.uses_screen_texture;
 	uses_screen_texture = gen_code.uses_screen_texture;
@@ -219,7 +227,7 @@ bool SceneShaderForwardClustered::ShaderData::casts_shadows() const {
 	bool has_base_alpha = (uses_alpha && (!uses_alpha_clip || uses_alpha_antialiasing)) || has_read_screen_alpha;
 	bool has_base_alpha = (uses_alpha && (!uses_alpha_clip || uses_alpha_antialiasing)) || has_read_screen_alpha;
 	bool has_alpha = has_base_alpha || uses_blend_alpha;
 	bool has_alpha = has_base_alpha || uses_blend_alpha;
 
 
-	return !has_alpha || (uses_depth_prepass_alpha && !(depth_draw == DEPTH_DRAW_DISABLED || depth_test == DEPTH_TEST_DISABLED));
+	return !has_alpha || (uses_depth_prepass_alpha && !(depth_draw == DEPTH_DRAW_DISABLED || depth_test != DEPTH_TEST_ENABLED));
 }
 }
 
 
 RS::ShaderNativeSourceCode SceneShaderForwardClustered::ShaderData::get_native_source_code() const {
 RS::ShaderNativeSourceCode SceneShaderForwardClustered::ShaderData::get_native_source_code() const {
@@ -318,8 +326,12 @@ void SceneShaderForwardClustered::ShaderData::_create_pipeline(PipelineKey p_pip
 
 
 	if (depth_test != DEPTH_TEST_DISABLED) {
 	if (depth_test != DEPTH_TEST_DISABLED) {
 		depth_stencil_state.enable_depth_test = true;
 		depth_stencil_state.enable_depth_test = true;
-		depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_GREATER_OR_EQUAL;
 		depth_stencil_state.enable_depth_write = depth_draw != DEPTH_DRAW_DISABLED ? true : false;
 		depth_stencil_state.enable_depth_write = depth_draw != DEPTH_DRAW_DISABLED ? true : false;
+		depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_GREATER_OR_EQUAL;
+
+		if (depth_test == DEPTH_TEST_ENABLED_INVERTED) {
+			depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS;
+		}
 	}
 	}
 	bool depth_pre_pass_enabled = bool(GLOBAL_GET_CACHED(bool, "rendering/driver/depth_prepass/enable"));
 	bool depth_pre_pass_enabled = bool(GLOBAL_GET_CACHED(bool, "rendering/driver/depth_prepass/enable"));
 
 

+ 6 - 4
servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h

@@ -150,7 +150,8 @@ public:
 
 
 		enum DepthTest {
 		enum DepthTest {
 			DEPTH_TEST_DISABLED,
 			DEPTH_TEST_DISABLED,
-			DEPTH_TEST_ENABLED
+			DEPTH_TEST_ENABLED,
+			DEPTH_TEST_ENABLED_INVERTED,
 		};
 		};
 
 
 		enum CullVariant {
 		enum CullVariant {
@@ -213,7 +214,8 @@ public:
 		DepthTest depth_test = DEPTH_TEST_ENABLED;
 		DepthTest depth_test = DEPTH_TEST_ENABLED;
 
 
 		int blend_mode = BLEND_MODE_MIX;
 		int blend_mode = BLEND_MODE_MIX;
-		int depth_testi = DEPTH_TEST_ENABLED;
+		int depth_test_disabledi = 0;
+		int depth_test_invertedi = 0;
 		int alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF;
 		int alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF;
 
 
 		bool uses_point_size = false;
 		bool uses_point_size = false;
@@ -257,13 +259,13 @@ public:
 			bool has_blend_alpha = uses_blend_alpha;
 			bool has_blend_alpha = uses_blend_alpha;
 			bool has_alpha = has_base_alpha || has_blend_alpha;
 			bool has_alpha = has_base_alpha || has_blend_alpha;
 			bool no_depth_draw = depth_draw == DEPTH_DRAW_DISABLED;
 			bool no_depth_draw = depth_draw == DEPTH_DRAW_DISABLED;
-			bool no_depth_test = depth_test == DEPTH_TEST_DISABLED;
+			bool no_depth_test = depth_test != DEPTH_TEST_ENABLED;
 			return has_alpha || has_read_screen_alpha || no_depth_draw || no_depth_test;
 			return has_alpha || has_read_screen_alpha || no_depth_draw || no_depth_test;
 		}
 		}
 
 
 		_FORCE_INLINE_ bool uses_depth_in_alpha_pass() const {
 		_FORCE_INLINE_ bool uses_depth_in_alpha_pass() const {
 			bool no_depth_draw = depth_draw == DEPTH_DRAW_DISABLED;
 			bool no_depth_draw = depth_draw == DEPTH_DRAW_DISABLED;
-			bool no_depth_test = depth_test == DEPTH_TEST_DISABLED;
+			bool no_depth_test = depth_test != DEPTH_TEST_ENABLED;
 			return (uses_depth_prepass_alpha || uses_alpha_antialiasing) && !(no_depth_draw || no_depth_test);
 			return (uses_depth_prepass_alpha || uses_alpha_antialiasing) && !(no_depth_draw || no_depth_test);
 		}
 		}
 
 

+ 17 - 5
servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp

@@ -54,7 +54,8 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
 	ShaderCompiler::GeneratedCode gen_code;
 	ShaderCompiler::GeneratedCode gen_code;
 
 
 	blend_mode = BLEND_MODE_MIX;
 	blend_mode = BLEND_MODE_MIX;
-	depth_testi = DEPTH_TEST_ENABLED;
+	depth_test_disabledi = 0;
+	depth_test_invertedi = 0;
 	alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF;
 	alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF;
 	cull_mode = RS::CULL_MODE_BACK;
 	cull_mode = RS::CULL_MODE_BACK;
 
 
@@ -101,7 +102,8 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
 	actions.render_mode_values["depth_draw_opaque"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_OPAQUE);
 	actions.render_mode_values["depth_draw_opaque"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_OPAQUE);
 	actions.render_mode_values["depth_draw_always"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_ALWAYS);
 	actions.render_mode_values["depth_draw_always"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_ALWAYS);
 
 
-	actions.render_mode_values["depth_test_disabled"] = Pair<int *, int>(&depth_testi, DEPTH_TEST_DISABLED);
+	actions.render_mode_values["depth_test_disabled"] = Pair<int *, int>(&depth_test_disabledi, 1);
+	actions.render_mode_values["depth_test_inverted"] = Pair<int *, int>(&depth_test_invertedi, 1);
 
 
 	actions.render_mode_values["cull_disabled"] = Pair<int *, int>(&cull_mode, RS::CULL_MODE_DISABLED);
 	actions.render_mode_values["cull_disabled"] = Pair<int *, int>(&cull_mode, RS::CULL_MODE_DISABLED);
 	actions.render_mode_values["cull_front"] = Pair<int *, int>(&cull_mode, RS::CULL_MODE_FRONT);
 	actions.render_mode_values["cull_front"] = Pair<int *, int>(&cull_mode, RS::CULL_MODE_FRONT);
@@ -159,7 +161,13 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
 	}
 	}
 
 
 	depth_draw = DepthDraw(depth_drawi);
 	depth_draw = DepthDraw(depth_drawi);
-	depth_test = DepthTest(depth_testi);
+	if (depth_test_disabledi) {
+		depth_test = DEPTH_TEST_DISABLED;
+	} else if (depth_test_invertedi) {
+		depth_test = DEPTH_TEST_ENABLED_INVERTED;
+	} else {
+		depth_test = DEPTH_TEST_ENABLED;
+	}
 	uses_vertex_time = gen_code.uses_vertex_time;
 	uses_vertex_time = gen_code.uses_vertex_time;
 	uses_fragment_time = gen_code.uses_fragment_time;
 	uses_fragment_time = gen_code.uses_fragment_time;
 	uses_screen_texture_mipmaps = gen_code.uses_screen_texture_mipmaps;
 	uses_screen_texture_mipmaps = gen_code.uses_screen_texture_mipmaps;
@@ -224,7 +232,7 @@ bool SceneShaderForwardMobile::ShaderData::casts_shadows() const {
 	bool has_base_alpha = (uses_alpha && (!uses_alpha_clip || uses_alpha_antialiasing)) || has_read_screen_alpha;
 	bool has_base_alpha = (uses_alpha && (!uses_alpha_clip || uses_alpha_antialiasing)) || has_read_screen_alpha;
 	bool has_alpha = has_base_alpha || uses_blend_alpha;
 	bool has_alpha = has_base_alpha || uses_blend_alpha;
 
 
-	return !has_alpha || (uses_depth_prepass_alpha && !(depth_draw == DEPTH_DRAW_DISABLED || depth_test == DEPTH_TEST_DISABLED));
+	return !has_alpha || (uses_depth_prepass_alpha && !(depth_draw == DEPTH_DRAW_DISABLED || depth_test != DEPTH_TEST_ENABLED));
 }
 }
 
 
 RS::ShaderNativeSourceCode SceneShaderForwardMobile::ShaderData::get_native_source_code() const {
 RS::ShaderNativeSourceCode SceneShaderForwardMobile::ShaderData::get_native_source_code() const {
@@ -276,8 +284,12 @@ void SceneShaderForwardMobile::ShaderData::_create_pipeline(PipelineKey p_pipeli
 
 
 	if (depth_test != DEPTH_TEST_DISABLED) {
 	if (depth_test != DEPTH_TEST_DISABLED) {
 		depth_stencil_state.enable_depth_test = true;
 		depth_stencil_state.enable_depth_test = true;
-		depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_GREATER_OR_EQUAL;
 		depth_stencil_state.enable_depth_write = depth_draw != DEPTH_DRAW_DISABLED ? true : false;
 		depth_stencil_state.enable_depth_write = depth_draw != DEPTH_DRAW_DISABLED ? true : false;
+		depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_GREATER_OR_EQUAL;
+
+		if (depth_test == DEPTH_TEST_ENABLED_INVERTED) {
+			depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS;
+		}
 	}
 	}
 
 
 	RD::RenderPrimitive primitive_rd_table[RS::PRIMITIVE_MAX] = {
 	RD::RenderPrimitive primitive_rd_table[RS::PRIMITIVE_MAX] = {

+ 6 - 4
servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h

@@ -148,7 +148,8 @@ public:
 
 
 		enum DepthTest {
 		enum DepthTest {
 			DEPTH_TEST_DISABLED,
 			DEPTH_TEST_DISABLED,
-			DEPTH_TEST_ENABLED
+			DEPTH_TEST_ENABLED,
+			DEPTH_TEST_ENABLED_INVERTED,
 		};
 		};
 
 
 		enum CullVariant {
 		enum CullVariant {
@@ -211,7 +212,8 @@ public:
 		DepthTest depth_test;
 		DepthTest depth_test;
 
 
 		int blend_mode = BLEND_MODE_MIX;
 		int blend_mode = BLEND_MODE_MIX;
-		int depth_testi = DEPTH_TEST_ENABLED;
+		int depth_test_disabledi = 0;
+		int depth_test_invertedi = 0;
 		int alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF;
 		int alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF;
 		int cull_mode = RS::CULL_MODE_BACK;
 		int cull_mode = RS::CULL_MODE_BACK;
 
 
@@ -253,13 +255,13 @@ public:
 			bool has_blend_alpha = uses_blend_alpha;
 			bool has_blend_alpha = uses_blend_alpha;
 			bool has_alpha = has_base_alpha || has_blend_alpha;
 			bool has_alpha = has_base_alpha || has_blend_alpha;
 			bool no_depth_draw = depth_draw == DEPTH_DRAW_DISABLED;
 			bool no_depth_draw = depth_draw == DEPTH_DRAW_DISABLED;
-			bool no_depth_test = depth_test == DEPTH_TEST_DISABLED;
+			bool no_depth_test = depth_test != DEPTH_TEST_ENABLED;
 			return has_alpha || has_read_screen_alpha || no_depth_draw || no_depth_test;
 			return has_alpha || has_read_screen_alpha || no_depth_draw || no_depth_test;
 		}
 		}
 
 
 		_FORCE_INLINE_ bool uses_depth_in_alpha_pass() const {
 		_FORCE_INLINE_ bool uses_depth_in_alpha_pass() const {
 			bool no_depth_draw = depth_draw == DEPTH_DRAW_DISABLED;
 			bool no_depth_draw = depth_draw == DEPTH_DRAW_DISABLED;
-			bool no_depth_test = depth_test == DEPTH_TEST_DISABLED;
+			bool no_depth_test = depth_test != DEPTH_TEST_ENABLED;
 			return (uses_depth_prepass_alpha || uses_alpha_antialiasing) && !(no_depth_draw || no_depth_test);
 			return (uses_depth_prepass_alpha || uses_alpha_antialiasing) && !(no_depth_draw || no_depth_test);
 		}
 		}
 
 

+ 7 - 0
servers/rendering/shader_language.h

@@ -937,6 +937,13 @@ public:
 			options.push_back(p_arg5);
 			options.push_back(p_arg5);
 			options.push_back(p_arg6);
 			options.push_back(p_arg6);
 		}
 		}
+
+		ModeInfo(const StringName &p_name, std::initializer_list<StringName> p_args) :
+				name(p_name) {
+			for (const StringName &arg : p_args) {
+				options.push_back(arg);
+			}
+		}
 	};
 	};
 
 
 	struct FunctionInfo {
 	struct FunctionInfo {

+ 1 - 1
servers/rendering/shader_types.cpp

@@ -226,7 +226,7 @@ ShaderTypes::ShaderTypes() {
 		shader_modes[RS::SHADER_SPATIAL].modes.push_back({ PNAME("blend"), "mix", "add", "sub", "mul", "premul_alpha" });
 		shader_modes[RS::SHADER_SPATIAL].modes.push_back({ PNAME("blend"), "mix", "add", "sub", "mul", "premul_alpha" });
 		shader_modes[RS::SHADER_SPATIAL].modes.push_back({ PNAME("depth_draw"), "opaque", "always", "never" });
 		shader_modes[RS::SHADER_SPATIAL].modes.push_back({ PNAME("depth_draw"), "opaque", "always", "never" });
 		shader_modes[RS::SHADER_SPATIAL].modes.push_back({ PNAME("depth_prepass_alpha") });
 		shader_modes[RS::SHADER_SPATIAL].modes.push_back({ PNAME("depth_prepass_alpha") });
-		shader_modes[RS::SHADER_SPATIAL].modes.push_back({ PNAME("depth_test_disabled") });
+		shader_modes[RS::SHADER_SPATIAL].modes.push_back({ PNAME("depth_test"), { "default", "disabled", "inverted" } });
 		shader_modes[RS::SHADER_SPATIAL].modes.push_back({ PNAME("sss_mode_skin") });
 		shader_modes[RS::SHADER_SPATIAL].modes.push_back({ PNAME("sss_mode_skin") });
 		shader_modes[RS::SHADER_SPATIAL].modes.push_back({ PNAME("cull"), "back", "front", "disabled" });
 		shader_modes[RS::SHADER_SPATIAL].modes.push_back({ PNAME("cull"), "back", "front", "disabled" });
 		shader_modes[RS::SHADER_SPATIAL].modes.push_back({ PNAME("unshaded") });
 		shader_modes[RS::SHADER_SPATIAL].modes.push_back({ PNAME("unshaded") });