瀏覽代碼

Several fixes to make GLES2 on HTML5 work much better.
Changed math class error reporting to be a bit less paranoid.

Juan Linietsky 6 年之前
父節點
當前提交
a32b26dfa2

+ 4 - 0
SConstruct

@@ -141,6 +141,7 @@ opts.Add(EnumVariable('target', "Compilation target", 'debug', ('debug', 'releas
 opts.Add(EnumVariable('optimize', "Optimization type", 'speed', ('speed', 'size')))
 opts.Add(BoolVariable('tools', "Build the tools (a.k.a. the Godot editor)", True))
 opts.Add(BoolVariable('use_lto', 'Use link-time optimization', False))
+opts.Add(BoolVariable('use_precise_math_checks', 'Math checks use very precise epsilon (useful to debug the engine)', False))
 
 # Components
 opts.Add(BoolVariable('deprecated', "Enable deprecated features", True))
@@ -224,6 +225,9 @@ env_base.Append(CPPPATH=['#editor', '#'])
 env_base.platform_exporters = platform_exporters
 env_base.platform_apis = platform_apis
 
+if (env_base["use_precise_math_checks"]):
+    env_base.Append(CPPDEFINES=['PRECISE_MATH_CHECKS'])
+
 if (env_base['target'] == 'debug'):
     env_base.Append(CPPDEFINES=['DEBUG_MEMORY_ALLOC','DISABLE_FORCED_INLINE'])
 

+ 46 - 28
core/math/basis.cpp

@@ -76,15 +76,23 @@ void Basis::invert() {
 }
 
 void Basis::orthonormalize() {
+	/* this check is undesired, the matrix could be wrong but we still may want to generate a valid one
+	 * for practical purposes
 #ifdef MATH_CHECKS
 	ERR_FAIL_COND(determinant() == 0);
 #endif
+*/
 	// Gram-Schmidt Process
 
 	Vector3 x = get_axis(0);
 	Vector3 y = get_axis(1);
 	Vector3 z = get_axis(2);
 
+#ifdef MATH_CHECKS
+	ERR_FAIL_COND(x.length_squared() == 0);
+	ERR_FAIL_COND(y.length_squared() == 0);
+	ERR_FAIL_COND(z.length_squared() == 0);
+#endif
 	x.normalize();
 	y = (y - x * (x.dot(y)));
 	y.normalize();
@@ -118,16 +126,16 @@ bool Basis::is_diagonal() const {
 }
 
 bool Basis::is_rotation() const {
-	return Math::is_equal_approx(determinant(), 1) && is_orthogonal();
+	return Math::is_equal_approx(determinant(), 1, UNIT_EPSILON) && is_orthogonal();
 }
 
 bool Basis::is_symmetric() const {
 
-	if (!Math::is_equal_approx(elements[0][1], elements[1][0]))
+	if (!Math::is_equal_approx_ratio(elements[0][1], elements[1][0], UNIT_EPSILON))
 		return false;
-	if (!Math::is_equal_approx(elements[0][2], elements[2][0]))
+	if (!Math::is_equal_approx_ratio(elements[0][2], elements[2][0], UNIT_EPSILON))
 		return false;
-	if (!Math::is_equal_approx(elements[1][2], elements[2][1]))
+	if (!Math::is_equal_approx_ratio(elements[1][2], elements[2][1], UNIT_EPSILON))
 		return false;
 
 	return true;
@@ -488,6 +496,11 @@ void Basis::set_euler_xyz(const Vector3 &p_euler) {
 // as the x, y, and z components of a Vector3 respectively.
 Vector3 Basis::get_euler_yxz() const {
 
+	/* checking this is a bad idea, because obtaining from scaled transform is a valid use case
+#ifdef MATH_CHECKS
+	ERR_FAIL_COND(!is_rotation());
+#endif
+*/
 	// Euler angles in YXZ convention.
 	// See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix
 	//
@@ -496,9 +509,7 @@ Vector3 Basis::get_euler_yxz() const {
 	//        cy*sx*sz-cz*sy    cy*cz*sx+sy*sz        cy*cx
 
 	Vector3 euler;
-#ifdef MATH_CHECKS
-	ERR_FAIL_COND_V(!is_rotation(), euler);
-#endif
+
 	real_t m12 = elements[1][2];
 
 	if (m12 < 1) {
@@ -556,7 +567,7 @@ bool Basis::is_equal_approx(const Basis &a, const Basis &b) const {
 
 	for (int i = 0; i < 3; i++) {
 		for (int j = 0; j < 3; j++) {
-			if (!Math::is_equal_approx(a.elements[i][j], b.elements[i][j]))
+			if (!Math::is_equal_approx_ratio(a.elements[i][j], b.elements[i][j], UNIT_EPSILON))
 				return false;
 		}
 	}
@@ -599,10 +610,14 @@ Basis::operator String() const {
 }
 
 Quat Basis::get_quat() const {
-#ifdef MATH_CHECKS
-	ERR_FAIL_COND_V(!is_rotation(), Quat());
-#endif
-	real_t trace = elements[0][0] + elements[1][1] + elements[2][2];
+
+	/* Allow getting a quaternion from an unnormalized transform */
+	Basis m = *this;
+	m.elements[0].normalize();
+	m.elements[1].normalize();
+	m.elements[2].normalize();
+
+	real_t trace = m.elements[0][0] + m.elements[1][1] + m.elements[2][2];
 	real_t temp[4];
 
 	if (trace > 0.0) {
@@ -610,23 +625,23 @@ Quat Basis::get_quat() const {
 		temp[3] = (s * 0.5);
 		s = 0.5 / s;
 
-		temp[0] = ((elements[2][1] - elements[1][2]) * s);
-		temp[1] = ((elements[0][2] - elements[2][0]) * s);
-		temp[2] = ((elements[1][0] - elements[0][1]) * s);
+		temp[0] = ((m.elements[2][1] - m.elements[1][2]) * s);
+		temp[1] = ((m.elements[0][2] - m.elements[2][0]) * s);
+		temp[2] = ((m.elements[1][0] - m.elements[0][1]) * s);
 	} else {
-		int i = elements[0][0] < elements[1][1] ?
-						(elements[1][1] < elements[2][2] ? 2 : 1) :
-						(elements[0][0] < elements[2][2] ? 2 : 0);
+		int i = m.elements[0][0] < m.elements[1][1] ?
+						(m.elements[1][1] < m.elements[2][2] ? 2 : 1) :
+						(m.elements[0][0] < m.elements[2][2] ? 2 : 0);
 		int j = (i + 1) % 3;
 		int k = (i + 2) % 3;
 
-		real_t s = Math::sqrt(elements[i][i] - elements[j][j] - elements[k][k] + 1.0);
+		real_t s = Math::sqrt(m.elements[i][i] - m.elements[j][j] - m.elements[k][k] + 1.0);
 		temp[i] = s * 0.5;
 		s = 0.5 / s;
 
-		temp[3] = (elements[k][j] - elements[j][k]) * s;
-		temp[j] = (elements[j][i] + elements[i][j]) * s;
-		temp[k] = (elements[k][i] + elements[i][k]) * s;
+		temp[3] = (m.elements[k][j] - m.elements[j][k]) * s;
+		temp[j] = (m.elements[j][i] + m.elements[i][j]) * s;
+		temp[k] = (m.elements[k][i] + m.elements[i][k]) * s;
 	}
 
 	return Quat(temp[0], temp[1], temp[2], temp[3]);
@@ -696,9 +711,11 @@ void Basis::set_orthogonal_index(int p_index) {
 }
 
 void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const {
+	/* checking this is a bad idea, because obtaining from scaled transform is a valid use case
 #ifdef MATH_CHECKS
 	ERR_FAIL_COND(!is_rotation());
 #endif
+*/
 	real_t angle, x, y, z; // variables for result
 	real_t epsilon = 0.01; // margin to allow for rounding errors
 	real_t epsilon2 = 0.1; // margin to distinguish between 0 and 180 degrees
@@ -835,14 +852,15 @@ void Basis::set_diagonal(const Vector3 p_diag) {
 }
 
 Basis Basis::slerp(const Basis &target, const real_t &t) const {
-// TODO: implement this directly without using quaternions to make it more efficient
-#ifdef MATH_CHECKS
-	ERR_FAIL_COND_V(!is_rotation(), Basis());
-	ERR_FAIL_COND_V(!target.is_rotation(), Basis());
-#endif
 
+	//consider scale
 	Quat from(*this);
 	Quat to(target);
 
-	return Basis(from.slerp(to, t));
+	Basis b(from.slerp(to, t));
+	b.elements[0] *= Math::lerp(elements[0].length(), target.elements[0].length(), t);
+	b.elements[1] *= Math::lerp(elements[1].length(), target.elements[1].length(), t);
+	b.elements[2] *= Math::lerp(elements[2].length(), target.elements[2].length(), t);
+
+	return b;
 }

+ 9 - 0
core/math/math_defs.h

@@ -33,6 +33,7 @@
 
 #define CMP_EPSILON 0.00001
 #define CMP_EPSILON2 (CMP_EPSILON * CMP_EPSILON)
+
 #define CMP_NORMALIZE_TOLERANCE 0.000001
 #define CMP_POINT_IN_PLANE_EPSILON 0.00001
 
@@ -49,6 +50,14 @@
 #define MATH_CHECKS
 #endif
 
+//this epsilon is for values related to a unit size (scalar or vector len)
+#ifdef PRECISE_MATH_CHECKS
+#define UNIT_EPSILON 0.00001
+#else
+//tolerate some more floating point error normally
+#define UNIT_EPSILON 0.001
+#endif
+
 #define USEC_TO_SEC(m_usec) ((m_usec) / 1000000.0)
 
 enum ClockDirection {

+ 14 - 2
core/math/math_funcs.h

@@ -249,13 +249,25 @@ public:
 	static float random(float from, float to);
 	static real_t random(int from, int to) { return (real_t)random((real_t)from, (real_t)to); }
 
-	static _ALWAYS_INLINE_ bool is_equal_approx(real_t a, real_t b) {
+	static _ALWAYS_INLINE_ bool is_equal_approx_ratio(real_t a, real_t b, real_t epsilon = CMP_EPSILON) {
+		// this is an approximate way to check that numbers are close, as a ratio of their average size
+		// helps compare approximate numbers that may be very big or very small
+		real_t diff = abs(a - b);
+		if (diff == 0.0) {
+			return true;
+		}
+		real_t avg_size = (abs(a) + abs(b)) / 2.0;
+		diff /= avg_size;
+		return diff < epsilon;
+	}
+
+	static _ALWAYS_INLINE_ bool is_equal_approx(real_t a, real_t b, real_t epsilon = CMP_EPSILON) {
 		// TODO: Comparing floats for approximate-equality is non-trivial.
 		// Using epsilon should cover the typical cases in Godot (where a == b is used to compare two reals), such as matrix and vector comparison operators.
 		// A proper implementation in terms of ULPs should eventually replace the contents of this function.
 		// See https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ for details.
 
-		return abs(a - b) < CMP_EPSILON;
+		return abs(a - b) < epsilon;
 	}
 
 	static _ALWAYS_INLINE_ float absf(float g) {

+ 1 - 1
core/math/quat.cpp

@@ -135,7 +135,7 @@ Quat Quat::normalized() const {
 }
 
 bool Quat::is_normalized() const {
-	return Math::is_equal_approx(length_squared(), 1.0);
+	return Math::is_equal_approx(length_squared(), 1.0, UNIT_EPSILON); //use less epsilon
 }
 
 Quat Quat::inverse() const {

+ 1 - 1
core/math/vector2.cpp

@@ -65,7 +65,7 @@ Vector2 Vector2::normalized() const {
 
 bool Vector2::is_normalized() const {
 	// use length_squared() instead of length() to avoid sqrt(), makes it more stringent.
-	return Math::is_equal_approx(length_squared(), 1.0);
+	return Math::is_equal_approx(length_squared(), 1.0, UNIT_EPSILON);
 }
 
 real_t Vector2::distance_to(const Vector2 &p_vector2) const {

+ 1 - 1
core/math/vector3.h

@@ -414,7 +414,7 @@ Vector3 Vector3::normalized() const {
 
 bool Vector3::is_normalized() const {
 	// use length_squared() instead of length() to avoid sqrt(), makes it more stringent.
-	return Math::is_equal_approx(length_squared(), 1.0);
+	return Math::is_equal_approx(length_squared(), 1.0, UNIT_EPSILON);
 }
 
 Vector3 Vector3::inverse() const {

+ 1 - 0
drivers/gles2/rasterizer_canvas_gles2.cpp

@@ -2019,6 +2019,7 @@ void RasterizerCanvasGLES2::initialize() {
 	state.canvas_shader.init();
 
 	state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, true);
+	state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_RGBA_SHADOWS, storage->config.use_rgba_2d_shadows);
 
 	state.canvas_shader.bind();
 

+ 107 - 25
drivers/gles2/rasterizer_scene_gles2.cpp

@@ -62,6 +62,7 @@ RID RasterizerSceneGLES2::shadow_atlas_create() {
 	ShadowAtlas *shadow_atlas = memnew(ShadowAtlas);
 	shadow_atlas->fbo = 0;
 	shadow_atlas->depth = 0;
+	shadow_atlas->color = 0;
 	shadow_atlas->size = 0;
 	shadow_atlas->smallest_subdiv = 0;
 
@@ -86,9 +87,13 @@ void RasterizerSceneGLES2::shadow_atlas_set_size(RID p_atlas, int p_size) {
 	if (shadow_atlas->fbo) {
 		glDeleteTextures(1, &shadow_atlas->depth);
 		glDeleteFramebuffers(1, &shadow_atlas->fbo);
+		if (shadow_atlas->color) {
+			glDeleteTextures(1, &shadow_atlas->color);
+		}
 
 		shadow_atlas->fbo = 0;
 		shadow_atlas->depth = 0;
+		shadow_atlas->color = 0;
 	}
 
 	// erase shadow atlast references from lights
@@ -119,6 +124,16 @@ void RasterizerSceneGLES2::shadow_atlas_set_size(RID p_atlas, int p_size) {
 
 		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, shadow_atlas->depth, 0);
 
+		if (storage->config.use_rgba_3d_shadows) {
+			glGenTextures(1, &shadow_atlas->color);
+			glBindTexture(GL_TEXTURE_2D, shadow_atlas->color);
+			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, shadow_atlas->size, shadow_atlas->size, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+			glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, shadow_atlas->color, 0);
+		}
 		glViewport(0, 0, shadow_atlas->size, shadow_atlas->size);
 
 		glDepthMask(GL_TRUE);
@@ -459,10 +474,10 @@ RID RasterizerSceneGLES2::reflection_probe_instance_create(RID p_probe) {
 
 	for (int i = 0; i < 6; i++) {
 		glGenFramebuffers(1, &rpi->fbo[i]);
+		glGenTextures(1, &rpi->color[i]);
 	}
 
-	glGenFramebuffers(1, &rpi->fbo_blur);
-	glGenRenderbuffers(1, &rpi->depth);
+	glGenTextures(1, &rpi->depth);
 	rpi->cubemap = 0;
 	//glGenTextures(1, &rpi->cubemap);
 
@@ -510,9 +525,14 @@ bool RasterizerSceneGLES2::reflection_probe_instance_begin_render(RID p_instance
 		GLenum type = GL_UNSIGNED_BYTE;
 
 		glActiveTexture(GL_TEXTURE0);
+
+		glBindTexture(GL_TEXTURE_2D, rpi->depth);
+		glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, size, size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
+
 		if (rpi->cubemap != 0) {
 			glDeleteTextures(1, &rpi->cubemap);
 		}
+
 		glGenTextures(1, &rpi->cubemap);
 		glBindTexture(GL_TEXTURE_CUBE_MAP, rpi->cubemap);
 #if 1
@@ -523,17 +543,15 @@ bool RasterizerSceneGLES2::reflection_probe_instance_begin_render(RID p_instance
 
 		glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
 
-		glBindRenderbuffer(GL_RENDERBUFFER, rpi->depth); //resize depth buffer
-#ifdef JAVASCRIPT_ENABLED
-		glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, size, size);
-#else
-		glRenderbufferStorage(GL_RENDERBUFFER, _DEPTH_COMPONENT24_OES, size, size);
-#endif
-
+		//Generate framebuffers for rendering
 		for (int i = 0; i < 6; i++) {
 			glBindFramebuffer(GL_FRAMEBUFFER, rpi->fbo[i]);
-			glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _cube_side_enum[i], rpi->cubemap, 0);
-			glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rpi->depth);
+			glBindTexture(GL_TEXTURE_2D, rpi->color[i]);
+			glTexImage2D(GL_TEXTURE_2D, 0, internal_format, size, size, 0, format, type, NULL);
+			glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rpi->color[i], 0);
+			glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rpi->depth, 0);
+			GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+			ERR_CONTINUE(status != GL_FRAMEBUFFER_COMPLETE);
 		}
 
 #else
@@ -570,6 +588,8 @@ bool RasterizerSceneGLES2::reflection_probe_instance_begin_render(RID p_instance
 		glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 		glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 		glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+		glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo);
 	}
 
 	return true;
@@ -579,6 +599,7 @@ bool RasterizerSceneGLES2::reflection_probe_instance_postprocess_step(RID p_inst
 
 	ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
 	ERR_FAIL_COND_V(!rpi, false);
+	ERR_FAIL_COND_V(rpi->current_resolution == 0, false);
 
 	int size = rpi->probe_ptr->resolution;
 
@@ -596,16 +617,23 @@ bool RasterizerSceneGLES2::reflection_probe_instance_postprocess_step(RID p_inst
 		}
 	}
 
+	glActiveTexture(GL_TEXTURE0);
+	glBindTexture(GL_TEXTURE_CUBE_MAP, rpi->cubemap);
+	glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); //use linear, no mipmaps so it does not read from what is being written to
+
+	//first of all, copy rendered textures to cubemap
+	for (int i = 0; i < 6; i++) {
+		glBindFramebuffer(GL_FRAMEBUFFER, rpi->fbo[i]);
+		glViewport(0, 0, size, size);
+		glCopyTexImage2D(_cube_side_enum[i], 0, GL_RGB, 0, 0, size, size, 0);
+	}
+	//do filtering
 	//vdc cache
 	glActiveTexture(GL_TEXTURE1);
 	glBindTexture(GL_TEXTURE_2D, storage->resources.radical_inverse_vdc_cache_tex);
 
-	glBindFramebuffer(GL_FRAMEBUFFER, rpi->fbo_blur);
 	// now render to the framebuffer, mipmap level for mipmap level
 	int lod = 1;
-	glActiveTexture(GL_TEXTURE0);
-	glBindTexture(GL_TEXTURE_CUBE_MAP, rpi->cubemap);
-	glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); //use linear, no mipmaps so it does not read from what is being written to
 
 	size >>= 1;
 	int mipmaps = 6;
@@ -613,13 +641,20 @@ bool RasterizerSceneGLES2::reflection_probe_instance_postprocess_step(RID p_inst
 	storage->shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_SOURCE_PANORAMA, false);
 	storage->shaders.cubemap_filter.bind();
 
+	glBindFramebuffer(GL_FRAMEBUFFER, storage->resources.mipmap_blur_fbo);
+
 	//blur
 	while (size >= 1) {
 
+		glActiveTexture(GL_TEXTURE3);
+		glBindTexture(GL_TEXTURE_2D, storage->resources.mipmap_blur_color);
+		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size, size, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
+		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, storage->resources.mipmap_blur_color, 0);
+		glViewport(0, 0, size, size);
+		glActiveTexture(GL_TEXTURE0);
+
 		for (int i = 0; i < 6; i++) {
-			glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _cube_side_enum[i], rpi->cubemap, lod);
 
-			glViewport(0, 0, size, size);
 			storage->bind_quad_array();
 			storage->shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::FACE_ID, i);
 			float roughness = CLAMP(lod / (float)(mipmaps - 1), 0, 1);
@@ -627,6 +662,7 @@ bool RasterizerSceneGLES2::reflection_probe_instance_postprocess_step(RID p_inst
 			storage->shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::Z_FLIP, false);
 
 			glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+			glCopyTexImage2D(_cube_side_enum[i], lod, GL_RGB, 0, 0, size, size, 0);
 		}
 
 		size >>= 1;
@@ -635,9 +671,14 @@ bool RasterizerSceneGLES2::reflection_probe_instance_postprocess_step(RID p_inst
 	}
 
 	// restore ranges
-
+	glActiveTexture(GL_TEXTURE0);
 	glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
-	glBindFramebuffer(GL_FRAMEBUFFER, 0);
+	glBindTexture(GL_TEXTURE_2D, 0);
+	glActiveTexture(GL_TEXTURE3); //back to panorama
+	glBindTexture(GL_TEXTURE_2D, 0);
+	glActiveTexture(GL_TEXTURE1);
+	glBindTexture(GL_TEXTURE_2D, 0);
+	glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo);
 
 	return true;
 }
@@ -1751,7 +1792,11 @@ void RasterizerSceneGLES2::_setup_light_type(LightInstance *p_light, ShadowAtlas
 			if (!state.render_no_shadows && p_light->light_ptr->shadow) {
 				state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, true);
 				glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3);
-				glBindTexture(GL_TEXTURE_2D, directional_shadow.depth);
+				if (storage->config.use_rgba_3d_shadows) {
+					glBindTexture(GL_TEXTURE_2D, directional_shadow.color);
+				} else {
+					glBindTexture(GL_TEXTURE_2D, directional_shadow.depth);
+				}
 				state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_5, shadow_filter_mode == SHADOW_FILTER_PCF5);
 				state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_13, shadow_filter_mode == SHADOW_FILTER_PCF13);
 			}
@@ -1763,7 +1808,11 @@ void RasterizerSceneGLES2::_setup_light_type(LightInstance *p_light, ShadowAtlas
 			if (!state.render_no_shadows && shadow_atlas && p_light->light_ptr->shadow) {
 				state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, true);
 				glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3);
-				glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth);
+				if (storage->config.use_rgba_3d_shadows) {
+					glBindTexture(GL_TEXTURE_2D, shadow_atlas->color);
+				} else {
+					glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth);
+				}
 				state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_5, shadow_filter_mode == SHADOW_FILTER_PCF5);
 				state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_13, shadow_filter_mode == SHADOW_FILTER_PCF13);
 			}
@@ -1774,7 +1823,11 @@ void RasterizerSceneGLES2::_setup_light_type(LightInstance *p_light, ShadowAtlas
 			if (!state.render_no_shadows && shadow_atlas && p_light->light_ptr->shadow) {
 				state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, true);
 				glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3);
-				glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth);
+				if (storage->config.use_rgba_3d_shadows) {
+					glBindTexture(GL_TEXTURE_2D, shadow_atlas->color);
+				} else {
+					glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth);
+				}
 				state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_5, shadow_filter_mode == SHADOW_FILTER_PCF5);
 				state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_13, shadow_filter_mode == SHADOW_FILTER_PCF13);
 			}
@@ -2041,7 +2094,7 @@ void RasterizerSceneGLES2::_setup_refprobes(ReflectionProbeInstance *p_refprobe1
 		state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_USE_BOX_PROJECT, p_refprobe2->probe_ptr->box_projection);
 		state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_BOX_EXTENTS, p_refprobe2->probe_ptr->extents);
 		state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_BOX_OFFSET, p_refprobe2->probe_ptr->origin_offset);
-		state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_EXTERIOR, !p_refprobe2->probe_ptr->interior);
+		state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_EXTERIOR, p_refprobe2->probe_ptr->interior);
 		state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_INTENSITY, p_refprobe2->probe_ptr->intensity);
 
 		Color ambient;
@@ -2737,6 +2790,7 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
 
 	if (probe_interior) {
 		env_radiance_tex = 0; //do not use radiance texture on interiors
+		state.default_ambient = Color(0, 0, 0, 1); //black as default ambient for interior
 	}
 
 	// render opaque things first
@@ -2994,7 +3048,9 @@ void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_
 	glBindFramebuffer(GL_FRAMEBUFFER, fbo);
 
 	glDepthMask(GL_TRUE);
-	glColorMask(0, 0, 0, 0);
+	if (!storage->config.use_rgba_3d_shadows) {
+		glColorMask(0, 0, 0, 0);
+	}
 
 	if (custom_vp_size) {
 		glViewport(0, 0, custom_vp_size, custom_vp_size);
@@ -3070,7 +3126,9 @@ void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_
 	if (storage->frame.current_rt) {
 		glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height);
 	}
-	glColorMask(1, 1, 1, 1);
+	if (!storage->config.use_rgba_3d_shadows) {
+		glColorMask(1, 1, 1, 1);
+	}
 }
 
 void RasterizerSceneGLES2::set_scene_pass(uint64_t p_pass) {
@@ -3108,6 +3166,16 @@ bool RasterizerSceneGLES2::free(RID p_rid) {
 
 		ReflectionProbeInstance *reflection_instance = reflection_probe_instance_owner.get(p_rid);
 
+		for (int i = 0; i < 6; i++) {
+			glDeleteFramebuffers(1, &reflection_instance->fbo[i]);
+			glDeleteTextures(1, &reflection_instance->color[i]);
+		}
+
+		if (reflection_instance->cubemap != 0) {
+			glDeleteTextures(1, &reflection_instance->cubemap);
+		}
+		glDeleteTextures(1, &reflection_instance->depth);
+
 		reflection_probe_release_atlas_index(p_rid);
 		reflection_probe_instance_owner.free(p_rid);
 		memdelete(reflection_instance);
@@ -3124,6 +3192,8 @@ void RasterizerSceneGLES2::set_debug_draw_mode(VS::ViewportDebugDraw p_debug_dra
 
 void RasterizerSceneGLES2::initialize() {
 	state.scene_shader.init();
+
+	state.scene_shader.set_conditional(SceneShaderGLES2::USE_RGBA_SHADOWS, storage->config.use_rgba_3d_shadows);
 	state.cube_to_dp_shader.init();
 
 	render_list.init();
@@ -3202,6 +3272,7 @@ void RasterizerSceneGLES2::initialize() {
 			glBindTexture(GL_TEXTURE_CUBE_MAP, cube.cubemap);
 
 			for (int i = 0; i < 6; i++) {
+
 				glTexImage2D(_cube_side_enum[i], 0, GL_DEPTH_COMPONENT, cube_size, cube_size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
 			}
 
@@ -3245,6 +3316,17 @@ void RasterizerSceneGLES2::initialize() {
 
 		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, directional_shadow.depth, 0);
 
+		if (storage->config.use_rgba_3d_shadows) {
+			glGenTextures(1, &directional_shadow.color);
+			glBindTexture(GL_TEXTURE_2D, directional_shadow.color);
+			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, directional_shadow.size, directional_shadow.size, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+			glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, directional_shadow.color, 0);
+		}
+
 		GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
 		if (status != GL_FRAMEBUFFER_COMPLETE) {
 			ERR_PRINT("Directional shadow framebuffer status invalid");

+ 4 - 3
drivers/gles2/rasterizer_scene_gles2.h

@@ -256,6 +256,7 @@ public:
 
 		GLuint fbo;
 		GLuint depth;
+		GLuint color;
 
 		Map<RID, uint32_t> shadow_owners;
 	};
@@ -279,6 +280,7 @@ public:
 	struct DirectionalShadow {
 		GLuint fbo;
 		GLuint depth;
+		GLuint color;
 
 		int light_count;
 		int size;
@@ -311,10 +313,9 @@ public:
 		int reflection_index;
 
 		GLuint fbo[6];
-		GLuint cubemap;
+		GLuint color[6];
 		GLuint depth;
-
-		GLuint fbo_blur;
+		GLuint cubemap;
 
 		int current_resolution;
 		mutable bool dirty;

+ 66 - 32
drivers/gles2/rasterizer_storage_gles2.cpp

@@ -1026,18 +1026,8 @@ void RasterizerStorageGLES2::sky_set_texture(RID p_sky, RID p_panorama, int p_ra
 	glGenTextures(1, &sky->radiance);
 	glBindTexture(GL_TEXTURE_CUBE_MAP, sky->radiance);
 
-	// Now we create a new framebuffer. The new cubemap images will be used as
-	// attachements for it, so we can fill them by issuing draw calls.
-	GLuint tmp_fb;
-
 	int size = p_radiance_size / 4; //divide by four because its a cubemap (this is an approximation because GLES3 uses a dual paraboloid)
 
-	int lod = 0;
-
-	int mipmaps = 6;
-
-	int mm_level = mipmaps;
-
 	GLenum internal_format = GL_RGB;
 	GLenum format = GL_RGB;
 	GLenum type = GL_UNSIGNED_BYTE;
@@ -1050,6 +1040,12 @@ void RasterizerStorageGLES2::sky_set_texture(RID p_sky, RID p_panorama, int p_ra
 	}
 
 	glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
+	//no filters for now
+	glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+	glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+	glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
 #else
 	while (size >= 1) {
 
@@ -1063,39 +1059,50 @@ void RasterizerStorageGLES2::sky_set_texture(RID p_sky, RID p_panorama, int p_ra
 	}
 #endif
 	//framebuffer
-	glGenFramebuffers(1, &tmp_fb);
-	glBindFramebuffer(GL_FRAMEBUFFER, tmp_fb);
 
-	shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_SOURCE_PANORAMA, texture->target == GL_TEXTURE_2D);
-
-	shaders.cubemap_filter.bind();
-	lod = 0;
-	mm_level = mipmaps;
+	glBindFramebuffer(GL_FRAMEBUFFER, resources.mipmap_blur_fbo);
 
+	int mipmaps = 6;
+	int lod = 0;
+	int mm_level = mipmaps;
 	size = p_radiance_size;
+	shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_SOURCE_PANORAMA, true);
+	shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_DIRECT_WRITE, true);
+	shaders.cubemap_filter.bind();
 
-	// now render to the framebuffer, mipmap level for mipmap level
+	// third, render to the framebuffer using separate textures, then copy to mipmaps
 	while (size >= 1) {
+		//make framebuffer size the texture size, need to use a separate texture for compatibility
+		glActiveTexture(GL_TEXTURE3);
+		glBindTexture(GL_TEXTURE_2D, resources.mipmap_blur_color);
+		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size, size, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
+		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, resources.mipmap_blur_color, 0);
+		if (lod == 1) {
+			//bind panorama for smaller lods
+
+			glActiveTexture(GL_TEXTURE0);
+			glBindTexture(GL_TEXTURE_CUBE_MAP, sky->radiance);
+			shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_SOURCE_PANORAMA, false);
+			shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_DIRECT_WRITE, false);
+			shaders.cubemap_filter.bind();
+		}
+		glViewport(0, 0, size, size);
+		bind_quad_array();
 
-		for (int i = 0; i < 6; i++) {
-			glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _cube_side_enum[i], sky->radiance, lod);
-
-			GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
-			if (status != GL_FRAMEBUFFER_COMPLETE) {
-				break; //may be too small
-			}
-
-			glViewport(0, 0, size, size);
+		glActiveTexture(GL_TEXTURE2); //back to panorama
 
-			bind_quad_array();
+		for (int i = 0; i < 6; i++) {
 
 			shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::FACE_ID, i);
 
-			float roughness = mm_level ? lod / (float)(mipmaps - 1) : 1;
+			float roughness = mm_level >= 0 ? lod / (float)(mipmaps - 1) : 1;
 			roughness = MIN(1.0, roughness); //keep max at 1
 			shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::ROUGHNESS, roughness);
+			shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::Z_FLIP, false);
 
 			glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+			glCopyTexImage2D(_cube_side_enum[i], lod, GL_RGB, 0, 0, size, size, 0);
 		}
 
 		size >>= 1;
@@ -1105,16 +1112,28 @@ void RasterizerStorageGLES2::sky_set_texture(RID p_sky, RID p_panorama, int p_ra
 		lod++;
 	}
 
+	shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_SOURCE_PANORAMA, false);
+	shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_DIRECT_WRITE, false);
+
 	// restore ranges
+	glActiveTexture(GL_TEXTURE2); //back to panorama
 
 	glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
 	glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 	glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 	glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
+	glBindTexture(GL_TEXTURE_2D, 0);
+	glActiveTexture(GL_TEXTURE3); //back to panorama
+	glBindTexture(GL_TEXTURE_2D, 0);
+	glActiveTexture(GL_TEXTURE1);
+	glBindTexture(GL_TEXTURE_2D, 0);
+	glActiveTexture(GL_TEXTURE0);
+	glBindTexture(GL_TEXTURE_2D, 0);
+
 	// Framebuffer did its job. thank mr framebuffer
+	glActiveTexture(GL_TEXTURE0); //back to panorama
 	glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo);
-	glDeleteFramebuffers(1, &tmp_fb);
 }
 
 /* SHADER API */
@@ -2438,7 +2457,6 @@ AABB RasterizerStorageGLES2::mesh_surface_get_aabb(RID p_mesh, int p_surface) co
 }
 
 Vector<PoolVector<uint8_t> > RasterizerStorageGLES2::mesh_surface_get_blend_shapes(RID p_mesh, int p_surface) const {
-	WARN_PRINT("GLES2 mesh_surface_get_blend_shapes is not implemented");
 	return Vector<PoolVector<uint8_t> >();
 }
 Vector<AABB> RasterizerStorageGLES2::mesh_surface_get_skeleton_aabb(RID p_mesh, int p_surface) const {
@@ -3662,6 +3680,7 @@ RID RasterizerStorageGLES2::reflection_probe_create() {
 	reflection_probe->intensity = 1.0;
 	reflection_probe->interior_ambient = Color();
 	reflection_probe->interior_ambient_energy = 1.0;
+	reflection_probe->interior_ambient_probe_contrib = 0.0;
 	reflection_probe->max_distance = 0;
 	reflection_probe->extents = Vector3(1, 1, 1);
 	reflection_probe->origin_offset = Vector3(0, 0, 0);
@@ -3747,6 +3766,7 @@ void RasterizerStorageGLES2::reflection_probe_set_as_interior(RID p_probe, bool
 	ERR_FAIL_COND(!reflection_probe);
 
 	reflection_probe->interior = p_enable;
+	reflection_probe->instance_change_notify(true, false);
 }
 void RasterizerStorageGLES2::reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) {
 
@@ -4962,8 +4982,10 @@ void RasterizerStorageGLES2::initialize() {
 #endif
 #ifdef GLES_OVER_GL
 	config.use_rgba_2d_shadows = false;
+	config.use_rgba_3d_shadows = false;
 #else
 	config.use_rgba_2d_shadows = !(config.float_texture_supported && config.extensions.has("GL_EXT_texture_rg"));
+	config.use_rgba_3d_shadows = config.extensions.has("GL_OES_depth_texture");
 #endif
 
 #ifdef GLES_OVER_GL
@@ -4974,6 +4996,8 @@ void RasterizerStorageGLES2::initialize() {
 
 #ifdef GLES_OVER_GL
 	config.support_write_depth = true;
+#elif defined(JAVASCRIPT_ENABLED)
+	config.support_write_depth = false;
 #else
 	config.support_write_depth = config.extensions.has("GL_EXT_frag_depth");
 #endif
@@ -4995,7 +5019,7 @@ void RasterizerStorageGLES2::initialize() {
 
 	shaders.copy.init();
 	shaders.cubemap_filter.init();
-	bool ggx_hq = GLOBAL_GET("rendering/quality/reflections/high_quality_ggx.mobile");
+	bool ggx_hq = GLOBAL_GET("rendering/quality/reflections/high_quality_ggx");
 	shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::LOW_QUALITY, !ggx_hq);
 
 	{
@@ -5115,10 +5139,20 @@ void RasterizerStorageGLES2::initialize() {
 		}
 
 		glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 512, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, radical_inverse);
+		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); //need this for proper sampling
 
 		glBindTexture(GL_TEXTURE_2D, 0);
 	}
 
+	{
+
+		glGenFramebuffers(1, &resources.mipmap_blur_fbo);
+		glGenTextures(1, &resources.mipmap_blur_color);
+	}
+
 #ifdef GLES_OVER_GL
 	//this needs to be enabled manually in OpenGL 2.1
 

+ 4 - 0
drivers/gles2/rasterizer_storage_gles2.h

@@ -78,6 +78,7 @@ public:
 		bool force_vertex_shading;
 
 		bool use_rgba_2d_shadows;
+		bool use_rgba_3d_shadows;
 
 		bool support_32_bits_indices;
 		bool support_write_depth;
@@ -92,6 +93,9 @@ public:
 		GLuint normal_tex;
 		GLuint aniso_tex;
 
+		GLuint mipmap_blur_fbo;
+		GLuint mipmap_blur_color;
+
 		GLuint radical_inverse_vdc_cache_tex;
 		bool use_rgba_2d_shadows;
 

+ 13 - 0
drivers/gles2/shaders/cubemap_filter.glsl

@@ -187,6 +187,18 @@ void main() {
 	vec2 uv = (uv_interp * 2.0) - 1.0;
 	vec3 N = texelCoordToVec(uv, face_id);
 
+#ifdef USE_DIRECT_WRITE
+
+#ifdef USE_SOURCE_PANORAMA
+
+	gl_FragColor = vec4(texturePanorama(source_panorama, N).rgb, 1.0);
+#else
+
+	gl_FragColor = vec4(textureCube(source_cube,N).rgb, 1.0);
+#endif //USE_SOURCE_PANORAMA
+
+#else
+
 	vec4 sum = vec4(0.0);
 
 	for (int sample_num = 0; sample_num < SAMPLE_COUNT; sample_num++) {
@@ -221,4 +233,5 @@ void main() {
 	sum.rgb = mix((vec3(1.0) + a) * pow(sum.rgb, vec3(1.0 / 2.4)) - a, 12.92 * sum.rgb, vec3(lessThan(sum.rgb, vec3(0.0031308))));
 
 	gl_FragColor = vec4(sum.rgb, 1.0);
+#endif
 }

+ 41 - 5
drivers/gles2/shaders/scene.glsl

@@ -96,6 +96,10 @@ uniform float light_normal_bias;
 // varyings
 //
 
+#if defined(RENDER_DEPTH) && defined(USE_RGBA_SHADOWS)
+varying highp vec4 position_interp;
+#endif
+
 varying highp vec3 vertex_interp;
 varying vec3 normal_interp;
 
@@ -355,7 +359,7 @@ void main() {
 	uv2_interp = uv2_attrib;
 #endif
 
-#ifdef OVERRIDE_POSITION
+#if defined(OVERRIDE_POSITION)
 	highp vec4 position;
 #endif
 
@@ -647,11 +651,16 @@ VERTEX_SHADER_CODE
 
 #endif //use vertex lighting
 
-#ifdef OVERRIDE_POSITION
+#if defined(OVERRIDE_POSITION)
 	gl_Position = position;
 #else
 	gl_Position = projection_matrix * vec4(vertex_interp, 1.0);
 #endif
+
+#if defined(RENDER_DEPTH) && defined(USE_RGBA_SHADOWS)
+	position_interp = gl_Position;
+#endif
+
 }
 
 /* clang-format off */
@@ -975,6 +984,10 @@ uniform vec4 light_clamp;
 // varyings
 //
 
+#if defined(RENDER_DEPTH) && defined(USE_RGBA_SHADOWS)
+varying highp vec4 position_interp;
+#endif
+
 varying highp vec3 vertex_interp;
 varying vec3 normal_interp;
 
@@ -1335,8 +1348,21 @@ LIGHT_SHADER_CODE
 
 #ifdef USE_SHADOW
 
-#define SAMPLE_SHADOW_TEXEL(p_shadow, p_pos, p_depth) step(p_depth, texture2D(p_shadow, p_pos).r)
-#define SAMPLE_SHADOW_TEXEL_PROJ(p_shadow, p_pos) step(p_pos.z, texture2DProj(p_shadow, p_pos).r)
+#ifdef USE_RGBA_SHADOWS
+
+#define SHADOW_DEPTH(m_val) dot(m_val, vec4(1.0 / (256.0 * 256.0 * 256.0), 1.0 / (256.0 * 256.0), 1.0 / 256.0, 1.0))
+
+#else
+
+#define SHADOW_DEPTH(m_val) (m_val).r
+
+#endif
+
+
+#define SAMPLE_SHADOW_TEXEL(p_shadow, p_pos, p_depth) step(p_depth, SHADOW_DEPTH(texture2D(p_shadow, p_pos)))
+#define SAMPLE_SHADOW_TEXEL_PROJ(p_shadow, p_pos) step(p_pos.z, SHADOW_DEPTH(texture2DProj(p_shadow, p_pos)))
+
+
 
 float sample_shadow(highp sampler2D shadow, highp vec4 spos) {
 
@@ -2105,5 +2131,15 @@ FRAGMENT_SHADER_CODE
 
 #endif // defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED)
 
-#endif // not RENDER_DEPTH
+#else // not RENDER_DEPTH
+//depth render
+#ifdef USE_RGBA_SHADOWS
+
+	highp float depth = ((position_interp.z / position_interp.w) + 1.0) * 0.5 + 0.0; // bias
+	highp vec4 comp = fract(depth * vec4(256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0));
+	comp -= comp.xxyz * vec4(0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0);
+	gl_FragColor = comp;
+
+#endif
+#endif
 }

+ 1 - 0
drivers/gles3/rasterizer_storage_gles3.cpp

@@ -5522,6 +5522,7 @@ void RasterizerStorageGLES3::reflection_probe_set_as_interior(RID p_probe, bool
 	ERR_FAIL_COND(!reflection_probe);
 
 	reflection_probe->interior = p_enable;
+	reflection_probe->instance_change_notify(true, false);
 }
 void RasterizerStorageGLES3::reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) {
 

+ 1 - 1
scene/resources/material.cpp

@@ -721,7 +721,7 @@ void SpatialMaterial::_update_shader() {
 		code += "\tvec2 base_uv2 = UV2;\n";
 	}
 
-	if (features[FEATURE_DEPTH_MAPPING] && !flags[FLAG_UV1_USE_TRIPLANAR]) { //depthmap not supported with triplanar
+	if (!VisualServer::get_singleton()->is_low_end() && features[FEATURE_DEPTH_MAPPING] && !flags[FLAG_UV1_USE_TRIPLANAR]) { //depthmap not supported with triplanar
 		code += "\t{\n";
 		code += "\t\tvec3 view_dir = normalize(normalize(-VERTEX)*mat3(TANGENT*depth_flip.x,-BINORMAL*depth_flip.y,NORMAL));\n"; // binormal is negative due to mikktspace, flip 'unflips' it ;-)