Browse Source

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

Juan Linietsky 6 years ago
parent
commit
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(EnumVariable('optimize', "Optimization type", 'speed', ('speed', 'size')))
 opts.Add(BoolVariable('tools', "Build the tools (a.k.a. the Godot editor)", True))
 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_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
 # Components
 opts.Add(BoolVariable('deprecated', "Enable deprecated features", True))
 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_exporters = platform_exporters
 env_base.platform_apis = platform_apis
 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'):
 if (env_base['target'] == 'debug'):
     env_base.Append(CPPDEFINES=['DEBUG_MEMORY_ALLOC','DISABLE_FORCED_INLINE'])
     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() {
 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
 #ifdef MATH_CHECKS
 	ERR_FAIL_COND(determinant() == 0);
 	ERR_FAIL_COND(determinant() == 0);
 #endif
 #endif
+*/
 	// Gram-Schmidt Process
 	// Gram-Schmidt Process
 
 
 	Vector3 x = get_axis(0);
 	Vector3 x = get_axis(0);
 	Vector3 y = get_axis(1);
 	Vector3 y = get_axis(1);
 	Vector3 z = get_axis(2);
 	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();
 	x.normalize();
 	y = (y - x * (x.dot(y)));
 	y = (y - x * (x.dot(y)));
 	y.normalize();
 	y.normalize();
@@ -118,16 +126,16 @@ bool Basis::is_diagonal() const {
 }
 }
 
 
 bool Basis::is_rotation() 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 {
 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;
 		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;
 		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 false;
 
 
 	return true;
 	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.
 // as the x, y, and z components of a Vector3 respectively.
 Vector3 Basis::get_euler_yxz() const {
 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.
 	// Euler angles in YXZ convention.
 	// See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix
 	// 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
 	//        cy*sx*sz-cz*sy    cy*cz*sx+sy*sz        cy*cx
 
 
 	Vector3 euler;
 	Vector3 euler;
-#ifdef MATH_CHECKS
-	ERR_FAIL_COND_V(!is_rotation(), euler);
-#endif
+
 	real_t m12 = elements[1][2];
 	real_t m12 = elements[1][2];
 
 
 	if (m12 < 1) {
 	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 i = 0; i < 3; i++) {
 		for (int j = 0; j < 3; j++) {
 		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;
 				return false;
 		}
 		}
 	}
 	}
@@ -599,10 +610,14 @@ Basis::operator String() const {
 }
 }
 
 
 Quat Basis::get_quat() 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];
 	real_t temp[4];
 
 
 	if (trace > 0.0) {
 	if (trace > 0.0) {
@@ -610,23 +625,23 @@ Quat Basis::get_quat() const {
 		temp[3] = (s * 0.5);
 		temp[3] = (s * 0.5);
 		s = 0.5 / s;
 		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 {
 	} 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 j = (i + 1) % 3;
 		int k = (i + 2) % 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;
 		temp[i] = s * 0.5;
 		s = 0.5 / s;
 		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]);
 	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 {
 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
 #ifdef MATH_CHECKS
 	ERR_FAIL_COND(!is_rotation());
 	ERR_FAIL_COND(!is_rotation());
 #endif
 #endif
+*/
 	real_t angle, x, y, z; // variables for result
 	real_t angle, x, y, z; // variables for result
 	real_t epsilon = 0.01; // margin to allow for rounding errors
 	real_t epsilon = 0.01; // margin to allow for rounding errors
 	real_t epsilon2 = 0.1; // margin to distinguish between 0 and 180 degrees
 	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 {
 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 from(*this);
 	Quat to(target);
 	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_EPSILON 0.00001
 #define CMP_EPSILON2 (CMP_EPSILON * CMP_EPSILON)
 #define CMP_EPSILON2 (CMP_EPSILON * CMP_EPSILON)
+
 #define CMP_NORMALIZE_TOLERANCE 0.000001
 #define CMP_NORMALIZE_TOLERANCE 0.000001
 #define CMP_POINT_IN_PLANE_EPSILON 0.00001
 #define CMP_POINT_IN_PLANE_EPSILON 0.00001
 
 
@@ -49,6 +50,14 @@
 #define MATH_CHECKS
 #define MATH_CHECKS
 #endif
 #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)
 #define USEC_TO_SEC(m_usec) ((m_usec) / 1000000.0)
 
 
 enum ClockDirection {
 enum ClockDirection {

+ 14 - 2
core/math/math_funcs.h

@@ -249,13 +249,25 @@ public:
 	static float random(float from, float to);
 	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 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.
 		// 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.
 		// 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.
 		// 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.
 		// 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) {
 	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 {
 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 {
 Quat Quat::inverse() const {

+ 1 - 1
core/math/vector2.cpp

@@ -65,7 +65,7 @@ Vector2 Vector2::normalized() const {
 
 
 bool Vector2::is_normalized() const {
 bool Vector2::is_normalized() const {
 	// use length_squared() instead of length() to avoid sqrt(), makes it more stringent.
 	// 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 {
 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 {
 bool Vector3::is_normalized() const {
 	// use length_squared() instead of length() to avoid sqrt(), makes it more stringent.
 	// 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 {
 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.init();
 
 
 	state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, true);
 	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();
 	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);
 	ShadowAtlas *shadow_atlas = memnew(ShadowAtlas);
 	shadow_atlas->fbo = 0;
 	shadow_atlas->fbo = 0;
 	shadow_atlas->depth = 0;
 	shadow_atlas->depth = 0;
+	shadow_atlas->color = 0;
 	shadow_atlas->size = 0;
 	shadow_atlas->size = 0;
 	shadow_atlas->smallest_subdiv = 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) {
 	if (shadow_atlas->fbo) {
 		glDeleteTextures(1, &shadow_atlas->depth);
 		glDeleteTextures(1, &shadow_atlas->depth);
 		glDeleteFramebuffers(1, &shadow_atlas->fbo);
 		glDeleteFramebuffers(1, &shadow_atlas->fbo);
+		if (shadow_atlas->color) {
+			glDeleteTextures(1, &shadow_atlas->color);
+		}
 
 
 		shadow_atlas->fbo = 0;
 		shadow_atlas->fbo = 0;
 		shadow_atlas->depth = 0;
 		shadow_atlas->depth = 0;
+		shadow_atlas->color = 0;
 	}
 	}
 
 
 	// erase shadow atlast references from lights
 	// 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);
 		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);
 		glViewport(0, 0, shadow_atlas->size, shadow_atlas->size);
 
 
 		glDepthMask(GL_TRUE);
 		glDepthMask(GL_TRUE);
@@ -459,10 +474,10 @@ RID RasterizerSceneGLES2::reflection_probe_instance_create(RID p_probe) {
 
 
 	for (int i = 0; i < 6; i++) {
 	for (int i = 0; i < 6; i++) {
 		glGenFramebuffers(1, &rpi->fbo[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;
 	rpi->cubemap = 0;
 	//glGenTextures(1, &rpi->cubemap);
 	//glGenTextures(1, &rpi->cubemap);
 
 
@@ -510,9 +525,14 @@ bool RasterizerSceneGLES2::reflection_probe_instance_begin_render(RID p_instance
 		GLenum type = GL_UNSIGNED_BYTE;
 		GLenum type = GL_UNSIGNED_BYTE;
 
 
 		glActiveTexture(GL_TEXTURE0);
 		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) {
 		if (rpi->cubemap != 0) {
 			glDeleteTextures(1, &rpi->cubemap);
 			glDeleteTextures(1, &rpi->cubemap);
 		}
 		}
+
 		glGenTextures(1, &rpi->cubemap);
 		glGenTextures(1, &rpi->cubemap);
 		glBindTexture(GL_TEXTURE_CUBE_MAP, rpi->cubemap);
 		glBindTexture(GL_TEXTURE_CUBE_MAP, rpi->cubemap);
 #if 1
 #if 1
@@ -523,17 +543,15 @@ bool RasterizerSceneGLES2::reflection_probe_instance_begin_render(RID p_instance
 
 
 		glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
 		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++) {
 		for (int i = 0; i < 6; i++) {
 			glBindFramebuffer(GL_FRAMEBUFFER, rpi->fbo[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
 #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_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_S, GL_CLAMP_TO_EDGE);
 		glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, 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;
 	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);
 	ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
 	ERR_FAIL_COND_V(!rpi, false);
 	ERR_FAIL_COND_V(!rpi, false);
+	ERR_FAIL_COND_V(rpi->current_resolution == 0, false);
 
 
 	int size = rpi->probe_ptr->resolution;
 	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
 	//vdc cache
 	glActiveTexture(GL_TEXTURE1);
 	glActiveTexture(GL_TEXTURE1);
 	glBindTexture(GL_TEXTURE_2D, storage->resources.radical_inverse_vdc_cache_tex);
 	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
 	// now render to the framebuffer, mipmap level for mipmap level
 	int lod = 1;
 	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;
 	size >>= 1;
 	int mipmaps = 6;
 	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.set_conditional(CubemapFilterShaderGLES2::USE_SOURCE_PANORAMA, false);
 	storage->shaders.cubemap_filter.bind();
 	storage->shaders.cubemap_filter.bind();
 
 
+	glBindFramebuffer(GL_FRAMEBUFFER, storage->resources.mipmap_blur_fbo);
+
 	//blur
 	//blur
 	while (size >= 1) {
 	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++) {
 		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->bind_quad_array();
 			storage->shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::FACE_ID, i);
 			storage->shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::FACE_ID, i);
 			float roughness = CLAMP(lod / (float)(mipmaps - 1), 0, 1);
 			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);
 			storage->shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::Z_FLIP, false);
 
 
 			glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
 			glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+			glCopyTexImage2D(_cube_side_enum[i], lod, GL_RGB, 0, 0, size, size, 0);
 		}
 		}
 
 
 		size >>= 1;
 		size >>= 1;
@@ -635,9 +671,14 @@ bool RasterizerSceneGLES2::reflection_probe_instance_postprocess_step(RID p_inst
 	}
 	}
 
 
 	// restore ranges
 	// restore ranges
-
+	glActiveTexture(GL_TEXTURE0);
 	glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
 	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;
 	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) {
 			if (!state.render_no_shadows && p_light->light_ptr->shadow) {
 				state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, true);
 				state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, true);
 				glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3);
 				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_5, shadow_filter_mode == SHADOW_FILTER_PCF5);
 				state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_13, shadow_filter_mode == SHADOW_FILTER_PCF13);
 				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) {
 			if (!state.render_no_shadows && shadow_atlas && p_light->light_ptr->shadow) {
 				state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, true);
 				state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, true);
 				glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3);
 				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_5, shadow_filter_mode == SHADOW_FILTER_PCF5);
 				state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_13, shadow_filter_mode == SHADOW_FILTER_PCF13);
 				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) {
 			if (!state.render_no_shadows && shadow_atlas && p_light->light_ptr->shadow) {
 				state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, true);
 				state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, true);
 				glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3);
 				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_5, shadow_filter_mode == SHADOW_FILTER_PCF5);
 				state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_13, shadow_filter_mode == SHADOW_FILTER_PCF13);
 				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_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_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_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);
 		state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_INTENSITY, p_refprobe2->probe_ptr->intensity);
 
 
 		Color ambient;
 		Color ambient;
@@ -2737,6 +2790,7 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
 
 
 	if (probe_interior) {
 	if (probe_interior) {
 		env_radiance_tex = 0; //do not use radiance texture on interiors
 		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
 	// 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);
 	glBindFramebuffer(GL_FRAMEBUFFER, fbo);
 
 
 	glDepthMask(GL_TRUE);
 	glDepthMask(GL_TRUE);
-	glColorMask(0, 0, 0, 0);
+	if (!storage->config.use_rgba_3d_shadows) {
+		glColorMask(0, 0, 0, 0);
+	}
 
 
 	if (custom_vp_size) {
 	if (custom_vp_size) {
 		glViewport(0, 0, custom_vp_size, 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) {
 	if (storage->frame.current_rt) {
 		glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height);
 		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) {
 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);
 		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_release_atlas_index(p_rid);
 		reflection_probe_instance_owner.free(p_rid);
 		reflection_probe_instance_owner.free(p_rid);
 		memdelete(reflection_instance);
 		memdelete(reflection_instance);
@@ -3124,6 +3192,8 @@ void RasterizerSceneGLES2::set_debug_draw_mode(VS::ViewportDebugDraw p_debug_dra
 
 
 void RasterizerSceneGLES2::initialize() {
 void RasterizerSceneGLES2::initialize() {
 	state.scene_shader.init();
 	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();
 	state.cube_to_dp_shader.init();
 
 
 	render_list.init();
 	render_list.init();
@@ -3202,6 +3272,7 @@ void RasterizerSceneGLES2::initialize() {
 			glBindTexture(GL_TEXTURE_CUBE_MAP, cube.cubemap);
 			glBindTexture(GL_TEXTURE_CUBE_MAP, cube.cubemap);
 
 
 			for (int i = 0; i < 6; i++) {
 			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);
 				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);
 		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);
 		GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
 		if (status != GL_FRAMEBUFFER_COMPLETE) {
 		if (status != GL_FRAMEBUFFER_COMPLETE) {
 			ERR_PRINT("Directional shadow framebuffer status invalid");
 			ERR_PRINT("Directional shadow framebuffer status invalid");

+ 4 - 3
drivers/gles2/rasterizer_scene_gles2.h

@@ -256,6 +256,7 @@ public:
 
 
 		GLuint fbo;
 		GLuint fbo;
 		GLuint depth;
 		GLuint depth;
+		GLuint color;
 
 
 		Map<RID, uint32_t> shadow_owners;
 		Map<RID, uint32_t> shadow_owners;
 	};
 	};
@@ -279,6 +280,7 @@ public:
 	struct DirectionalShadow {
 	struct DirectionalShadow {
 		GLuint fbo;
 		GLuint fbo;
 		GLuint depth;
 		GLuint depth;
+		GLuint color;
 
 
 		int light_count;
 		int light_count;
 		int size;
 		int size;
@@ -311,10 +313,9 @@ public:
 		int reflection_index;
 		int reflection_index;
 
 
 		GLuint fbo[6];
 		GLuint fbo[6];
-		GLuint cubemap;
+		GLuint color[6];
 		GLuint depth;
 		GLuint depth;
-
-		GLuint fbo_blur;
+		GLuint cubemap;
 
 
 		int current_resolution;
 		int current_resolution;
 		mutable bool dirty;
 		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);
 	glGenTextures(1, &sky->radiance);
 	glBindTexture(GL_TEXTURE_CUBE_MAP, 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 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 internal_format = GL_RGB;
 	GLenum format = GL_RGB;
 	GLenum format = GL_RGB;
 	GLenum type = GL_UNSIGNED_BYTE;
 	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);
 	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
 #else
 	while (size >= 1) {
 	while (size >= 1) {
 
 
@@ -1063,39 +1059,50 @@ void RasterizerStorageGLES2::sky_set_texture(RID p_sky, RID p_panorama, int p_ra
 	}
 	}
 #endif
 #endif
 	//framebuffer
 	//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;
 	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) {
 	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);
 			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
 			roughness = MIN(1.0, roughness); //keep max at 1
 			shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::ROUGHNESS, roughness);
 			shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::ROUGHNESS, roughness);
+			shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::Z_FLIP, false);
 
 
 			glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
 			glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+			glCopyTexImage2D(_cube_side_enum[i], lod, GL_RGB, 0, 0, size, size, 0);
 		}
 		}
 
 
 		size >>= 1;
 		size >>= 1;
@@ -1105,16 +1112,28 @@ void RasterizerStorageGLES2::sky_set_texture(RID p_sky, RID p_panorama, int p_ra
 		lod++;
 		lod++;
 	}
 	}
 
 
+	shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_SOURCE_PANORAMA, false);
+	shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_DIRECT_WRITE, false);
+
 	// restore ranges
 	// 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_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
 	glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_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_S, GL_CLAMP_TO_EDGE);
 	glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, 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
 	// Framebuffer did its job. thank mr framebuffer
+	glActiveTexture(GL_TEXTURE0); //back to panorama
 	glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo);
 	glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo);
-	glDeleteFramebuffers(1, &tmp_fb);
 }
 }
 
 
 /* SHADER API */
 /* 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 {
 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> >();
 	return Vector<PoolVector<uint8_t> >();
 }
 }
 Vector<AABB> RasterizerStorageGLES2::mesh_surface_get_skeleton_aabb(RID p_mesh, int p_surface) const {
 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->intensity = 1.0;
 	reflection_probe->interior_ambient = Color();
 	reflection_probe->interior_ambient = Color();
 	reflection_probe->interior_ambient_energy = 1.0;
 	reflection_probe->interior_ambient_energy = 1.0;
+	reflection_probe->interior_ambient_probe_contrib = 0.0;
 	reflection_probe->max_distance = 0;
 	reflection_probe->max_distance = 0;
 	reflection_probe->extents = Vector3(1, 1, 1);
 	reflection_probe->extents = Vector3(1, 1, 1);
 	reflection_probe->origin_offset = Vector3(0, 0, 0);
 	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);
 	ERR_FAIL_COND(!reflection_probe);
 
 
 	reflection_probe->interior = p_enable;
 	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) {
 void RasterizerStorageGLES2::reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) {
 
 
@@ -4962,8 +4982,10 @@ void RasterizerStorageGLES2::initialize() {
 #endif
 #endif
 #ifdef GLES_OVER_GL
 #ifdef GLES_OVER_GL
 	config.use_rgba_2d_shadows = false;
 	config.use_rgba_2d_shadows = false;
+	config.use_rgba_3d_shadows = false;
 #else
 #else
 	config.use_rgba_2d_shadows = !(config.float_texture_supported && config.extensions.has("GL_EXT_texture_rg"));
 	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
 #endif
 
 
 #ifdef GLES_OVER_GL
 #ifdef GLES_OVER_GL
@@ -4974,6 +4996,8 @@ void RasterizerStorageGLES2::initialize() {
 
 
 #ifdef GLES_OVER_GL
 #ifdef GLES_OVER_GL
 	config.support_write_depth = true;
 	config.support_write_depth = true;
+#elif defined(JAVASCRIPT_ENABLED)
+	config.support_write_depth = false;
 #else
 #else
 	config.support_write_depth = config.extensions.has("GL_EXT_frag_depth");
 	config.support_write_depth = config.extensions.has("GL_EXT_frag_depth");
 #endif
 #endif
@@ -4995,7 +5019,7 @@ void RasterizerStorageGLES2::initialize() {
 
 
 	shaders.copy.init();
 	shaders.copy.init();
 	shaders.cubemap_filter.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);
 	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);
 		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);
 		glBindTexture(GL_TEXTURE_2D, 0);
 	}
 	}
 
 
+	{
+
+		glGenFramebuffers(1, &resources.mipmap_blur_fbo);
+		glGenTextures(1, &resources.mipmap_blur_color);
+	}
+
 #ifdef GLES_OVER_GL
 #ifdef GLES_OVER_GL
 	//this needs to be enabled manually in OpenGL 2.1
 	//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 force_vertex_shading;
 
 
 		bool use_rgba_2d_shadows;
 		bool use_rgba_2d_shadows;
+		bool use_rgba_3d_shadows;
 
 
 		bool support_32_bits_indices;
 		bool support_32_bits_indices;
 		bool support_write_depth;
 		bool support_write_depth;
@@ -92,6 +93,9 @@ public:
 		GLuint normal_tex;
 		GLuint normal_tex;
 		GLuint aniso_tex;
 		GLuint aniso_tex;
 
 
+		GLuint mipmap_blur_fbo;
+		GLuint mipmap_blur_color;
+
 		GLuint radical_inverse_vdc_cache_tex;
 		GLuint radical_inverse_vdc_cache_tex;
 		bool use_rgba_2d_shadows;
 		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;
 	vec2 uv = (uv_interp * 2.0) - 1.0;
 	vec3 N = texelCoordToVec(uv, face_id);
 	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);
 	vec4 sum = vec4(0.0);
 
 
 	for (int sample_num = 0; sample_num < SAMPLE_COUNT; sample_num++) {
 	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))));
 	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);
 	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
 // varyings
 //
 //
 
 
+#if defined(RENDER_DEPTH) && defined(USE_RGBA_SHADOWS)
+varying highp vec4 position_interp;
+#endif
+
 varying highp vec3 vertex_interp;
 varying highp vec3 vertex_interp;
 varying vec3 normal_interp;
 varying vec3 normal_interp;
 
 
@@ -355,7 +359,7 @@ void main() {
 	uv2_interp = uv2_attrib;
 	uv2_interp = uv2_attrib;
 #endif
 #endif
 
 
-#ifdef OVERRIDE_POSITION
+#if defined(OVERRIDE_POSITION)
 	highp vec4 position;
 	highp vec4 position;
 #endif
 #endif
 
 
@@ -647,11 +651,16 @@ VERTEX_SHADER_CODE
 
 
 #endif //use vertex lighting
 #endif //use vertex lighting
 
 
-#ifdef OVERRIDE_POSITION
+#if defined(OVERRIDE_POSITION)
 	gl_Position = position;
 	gl_Position = position;
 #else
 #else
 	gl_Position = projection_matrix * vec4(vertex_interp, 1.0);
 	gl_Position = projection_matrix * vec4(vertex_interp, 1.0);
 #endif
 #endif
+
+#if defined(RENDER_DEPTH) && defined(USE_RGBA_SHADOWS)
+	position_interp = gl_Position;
+#endif
+
 }
 }
 
 
 /* clang-format off */
 /* clang-format off */
@@ -975,6 +984,10 @@ uniform vec4 light_clamp;
 // varyings
 // varyings
 //
 //
 
 
+#if defined(RENDER_DEPTH) && defined(USE_RGBA_SHADOWS)
+varying highp vec4 position_interp;
+#endif
+
 varying highp vec3 vertex_interp;
 varying highp vec3 vertex_interp;
 varying vec3 normal_interp;
 varying vec3 normal_interp;
 
 
@@ -1335,8 +1348,21 @@ LIGHT_SHADER_CODE
 
 
 #ifdef USE_SHADOW
 #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) {
 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 // 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);
 	ERR_FAIL_COND(!reflection_probe);
 
 
 	reflection_probe->interior = p_enable;
 	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) {
 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";
 		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{\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 ;-)
 		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 ;-)