Several fixes to make GLES2 on HTML5 work much better.

Changed math class error reporting to be a bit less paranoid.
This commit is contained in:
Juan Linietsky 2019-02-25 21:46:24 -03:00
parent 51c1d55cf9
commit a32b26dfa2
16 changed files with 315 additions and 100 deletions

View file

@ -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'])

View file

@ -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()); /* Allow getting a quaternion from an unnormalized transform */
#endif Basis m = *this;
real_t trace = elements[0][0] + elements[1][1] + elements[2][2]; 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[0] = ((m.elements[2][1] - m.elements[1][2]) * s);
temp[1] = ((elements[0][2] - elements[2][0]) * s); temp[1] = ((m.elements[0][2] - m.elements[2][0]) * s);
temp[2] = ((elements[1][0] - elements[0][1]) * s); temp[2] = ((m.elements[1][0] - m.elements[0][1]) * s);
} else { } else {
int i = elements[0][0] < elements[1][1] ? int i = m.elements[0][0] < m.elements[1][1] ?
(elements[1][1] < elements[2][2] ? 2 : 1) : (m.elements[1][1] < m.elements[2][2] ? 2 : 1) :
(elements[0][0] < elements[2][2] ? 2 : 0); (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[3] = (m.elements[k][j] - m.elements[j][k]) * s;
temp[j] = (elements[j][i] + elements[i][j]) * s; temp[j] = (m.elements[j][i] + m.elements[i][j]) * s;
temp[k] = (elements[k][i] + elements[i][k]) * 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;
} }

View file

@ -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 {

View file

@ -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) {

View file

@ -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 {

View file

@ -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 {

View file

@ -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 {

View file

@ -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();

View file

@ -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); glGenTextures(1, &rpi->depth);
glGenRenderbuffers(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 //Generate framebuffers for rendering
#ifdef JAVASCRIPT_ENABLED
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, size, size);
#else
glRenderbufferStorage(GL_RENDERBUFFER, _DEPTH_COMPONENT24_OES, size, size);
#endif
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); glBindTexture(GL_TEXTURE_2D, rpi->color[i]);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rpi->depth); 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) {
for (int i = 0; i < 6; i++) { glActiveTexture(GL_TEXTURE3);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _cube_side_enum[i], rpi->cubemap, lod); 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++) {
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");

View file

@ -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 cubemap;
GLuint fbo_blur;
int current_resolution; int current_resolution;
mutable bool dirty; mutable bool dirty;

View file

@ -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); glBindFramebuffer(GL_FRAMEBUFFER, resources.mipmap_blur_fbo);
shaders.cubemap_filter.bind();
lod = 0;
mm_level = mipmaps;
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();
glActiveTexture(GL_TEXTURE2); //back to panorama
for (int i = 0; i < 6; i++) { 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);
bind_quad_array();
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

View file

@ -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;

View file

@ -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
} }

View file

@ -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) #ifdef USE_RGBA_SHADOWS
#define SAMPLE_SHADOW_TEXEL_PROJ(p_shadow, p_pos) step(p_pos.z, texture2DProj(p_shadow, p_pos).r)
#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
} }

View file

@ -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) {

View file

@ -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 ;-)