From 56d3abdbcce1a82c9d94dd4a3e7d0e0b854fb7e2 Mon Sep 17 00:00:00 2001 From: Omar El Sheikh Date: Sun, 6 Mar 2022 10:57:05 -0500 Subject: [PATCH] GLES2 Compression on Blend Shapes Fix When compressed vertex positions are used in a blend shapes mesh, we need to make sure we set the w-component of the position vector to 1.0 When octahedral compression is used on normals/tangents, they need to be converted to cartesian floats to be used for blend shapes This conversion also changes the number of components of that vertex attribute, which caused issues because previously there was an assumption that you had the same number of components in the blend shape buffer as you did in the original mesh's buffer (which is not true for oct norm/tang) (cherry picked from commit 733a84f7a4c40750fd3a633e0e3442a4d13914a8) --- drivers/gles2/rasterizer_scene_gles2.cpp | 20 ++- drivers/gles2/rasterizer_storage_gles2.cpp | 138 ++++++++++++++++----- 2 files changed, 124 insertions(+), 34 deletions(-) diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp index 4464b7bdc90..b9a25578ac0 100644 --- a/drivers/gles2/rasterizer_scene_gles2.cpp +++ b/drivers/gles2/rasterizer_scene_gles2.cpp @@ -1401,7 +1401,21 @@ void RasterizerSceneGLES2::_setup_geometry(RenderList::Element *p_element, Raste if (!s->blend_shape_data.empty() && i != VS::ARRAY_BONES && s->blend_shape_buffer_size > 0) { glBindBuffer(GL_ARRAY_BUFFER, s->blend_shape_buffer_id); - glVertexAttribPointer(s->attribs[i].index, s->attribs[i].size, GL_FLOAT, GL_FALSE, 8 * 4 * sizeof(float), CAST_INT_TO_UCHAR_PTR(i * 4 * sizeof(float))); + // When using octahedral compression (2 component normal/tangent) + // decompression changes the component count to 3/4 + int size; + switch (i) { + case VS::ARRAY_NORMAL: { + size = 3; + } break; + case VS::ARRAY_TANGENT: { + size = 4; + } break; + default: + size = s->attribs[i].size; + } + + glVertexAttribPointer(s->attribs[i].index, size, GL_FLOAT, GL_FALSE, 8 * 4 * sizeof(float), CAST_INT_TO_UCHAR_PTR(i * 4 * sizeof(float))); } else { glBindBuffer(GL_ARRAY_BUFFER, s->vertex_id); @@ -2429,7 +2443,9 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, state.scene_shader.set_conditional(SceneShaderGLES2::USE_PHYSICAL_LIGHT_ATTENUATION, storage->config.use_physical_light_attenuation); - bool octahedral_compression = e->instance->base_type != VS::INSTANCE_IMMEDIATE && ((RasterizerStorageGLES2::Surface *)e->geometry)->format & VisualServer::ArrayFormat::ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION; + bool octahedral_compression = e->instance->base_type != VS::INSTANCE_IMMEDIATE && + ((RasterizerStorageGLES2::Surface *)e->geometry)->format & VisualServer::ArrayFormat::ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION && + (((RasterizerStorageGLES2::Surface *)e->geometry)->blend_shape_data.empty() || ((RasterizerStorageGLES2::Surface *)e->geometry)->blend_shape_buffer_size == 0); if (octahedral_compression != prev_octahedral_compression) { state.scene_shader.set_conditional(SceneShaderGLES2::ENABLE_OCTAHEDRAL_COMPRESSION, octahedral_compression); rebind = true; diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp index be103155549..5c891bd53f6 100644 --- a/drivers/gles2/rasterizer_storage_gles2.cpp +++ b/drivers/gles2/rasterizer_storage_gles2.cpp @@ -3790,6 +3790,7 @@ void RasterizerStorageGLES2::update_dirty_blend_shapes() { wr[0] = Math::halfptr_to_float(&((uint16_t *)rd)[0]) * base_weight; wr[1] = Math::halfptr_to_float(&((uint16_t *)rd)[1]) * base_weight; wr[2] = Math::halfptr_to_float(&((uint16_t *)rd)[2]) * base_weight; + wr[3] = 1.0f; } else { float a[3] = { 0 }; a[0] = wr[0] = rd[0] * base_weight; @@ -3799,27 +3800,63 @@ void RasterizerStorageGLES2::update_dirty_blend_shapes() { } } break; case VS::ARRAY_NORMAL: { - if (s->format & VS::ARRAY_COMPRESS_NORMAL) { - wr[0] = (((int8_t *)rd)[0] / 127.0) * base_weight; - wr[1] = (((int8_t *)rd)[1] / 127.0) * base_weight; - wr[2] = (((int8_t *)rd)[2] / 127.0) * base_weight; + if (s->format & VS::ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) { + if (s->format & VS::ARRAY_COMPRESS_NORMAL && s->format & VS::ARRAY_FORMAT_TANGENT && s->format & VS::ARRAY_COMPRESS_TANGENT) { + Vector2 oct(((int8_t *)rd)[0] / 127.0, ((int8_t *)rd)[1] / 127.0); + Vector3 vec = VS::oct_to_norm(oct); + wr[0] = vec.x * base_weight; + wr[1] = vec.y * base_weight; + wr[2] = vec.z * base_weight; + } else { + Vector2 oct(((int16_t *)rd)[0] / 32767.0, ((int16_t *)rd)[1] / 32767.0); + Vector3 vec = VS::oct_to_norm(oct); + wr[0] = vec.x * base_weight; + wr[1] = vec.y * base_weight; + wr[2] = vec.z * base_weight; + } } else { - wr[0] = rd[0] * base_weight; - wr[1] = rd[1] * base_weight; - wr[2] = rd[2] * base_weight; + if (s->format & VS::ARRAY_COMPRESS_NORMAL) { + wr[0] = (((int8_t *)rd)[0] / 127.0) * base_weight; + wr[1] = (((int8_t *)rd)[1] / 127.0) * base_weight; + wr[2] = (((int8_t *)rd)[2] / 127.0) * base_weight; + } else { + wr[0] = rd[0] * base_weight; + wr[1] = rd[1] * base_weight; + wr[2] = rd[2] * base_weight; + } } } break; case VS::ARRAY_TANGENT: { - if (s->format & VS::ARRAY_COMPRESS_TANGENT) { - wr[0] = (((int8_t *)rd)[0] / 127.0) * base_weight; - wr[1] = (((int8_t *)rd)[1] / 127.0) * base_weight; - wr[2] = (((int8_t *)rd)[2] / 127.0) * base_weight; - wr[3] = (((int8_t *)rd)[3] / 127.0) * base_weight; + if (s->format & VS::ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) { + if (s->format & VS::ARRAY_COMPRESS_TANGENT && s->format & VS::ARRAY_FORMAT_NORMAL && s->format & VS::ARRAY_COMPRESS_NORMAL) { + Vector2 oct(((int8_t *)rd)[0] / 127.0, ((int8_t *)rd)[1] / 127.0); + float sign; + Vector3 vec = VS::oct_to_tangent(oct, &sign); + wr[0] = vec.x * base_weight; + wr[1] = vec.y * base_weight; + wr[2] = vec.z * base_weight; + wr[3] = sign * base_weight; + } else { + Vector2 oct(((int16_t *)rd)[0] / 32767.0, ((int16_t *)rd)[1] / 32767.0); + float sign; + Vector3 vec = VS::oct_to_tangent(oct, &sign); + wr[0] = vec.x * base_weight; + wr[1] = vec.y * base_weight; + wr[2] = vec.z * base_weight; + wr[3] = sign * base_weight; + } } else { - wr[0] = rd[0] * base_weight; - wr[1] = rd[1] * base_weight; - wr[2] = rd[2] * base_weight; - wr[3] = rd[3] * base_weight; + if (s->format & VS::ARRAY_COMPRESS_TANGENT) { + wr[0] = (((int8_t *)rd)[0] / 127.0) * base_weight; + wr[1] = (((int8_t *)rd)[1] / 127.0) * base_weight; + wr[2] = (((int8_t *)rd)[2] / 127.0) * base_weight; + wr[3] = (((int8_t *)rd)[3] / 127.0) * base_weight; + } else { + wr[0] = rd[0] * base_weight; + wr[1] = rd[1] * base_weight; + wr[2] = rd[2] * base_weight; + wr[3] = rd[3] * base_weight; + } } } break; case VS::ARRAY_COLOR: { @@ -3884,6 +3921,7 @@ void RasterizerStorageGLES2::update_dirty_blend_shapes() { wr[0] += Math::halfptr_to_float(&((uint16_t *)br)[0]) * weight; wr[1] += Math::halfptr_to_float(&((uint16_t *)br)[1]) * weight; wr[2] += Math::halfptr_to_float(&((uint16_t *)br)[2]) * weight; + wr[3] = 1.0f; } else { wr[0] += br[0] * weight; wr[1] += br[1] * weight; @@ -3891,27 +3929,63 @@ void RasterizerStorageGLES2::update_dirty_blend_shapes() { } } break; case VS::ARRAY_NORMAL: { - if (s->format & VS::ARRAY_COMPRESS_NORMAL) { - wr[0] += (float(((int8_t *)br)[0]) / 127.0) * weight; - wr[1] += (float(((int8_t *)br)[1]) / 127.0) * weight; - wr[2] += (float(((int8_t *)br)[2]) / 127.0) * weight; + if (s->format & VS::ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) { + if (s->format & VS::ARRAY_COMPRESS_NORMAL && s->format & VS::ARRAY_FORMAT_TANGENT && s->format & VS::ARRAY_COMPRESS_TANGENT) { + Vector2 oct(((int8_t *)br)[0] / 127.0, ((int8_t *)br)[1] / 127.0); + Vector3 vec = VS::oct_to_norm(oct); + wr[0] += vec.x * weight; + wr[1] += vec.y * weight; + wr[2] += vec.z * weight; + } else { + Vector2 oct(((int16_t *)br)[0] / 32767.0, ((int16_t *)br)[1] / 32767.0); + Vector3 vec = VS::oct_to_norm(oct); + wr[0] += vec.x * weight; + wr[1] += vec.y * weight; + wr[2] += vec.z * weight; + } } else { - wr[0] += br[0] * weight; - wr[1] += br[1] * weight; - wr[2] += br[2] * weight; + if (s->format & VS::ARRAY_COMPRESS_NORMAL) { + wr[0] += (float(((int8_t *)br)[0]) / 127.0) * weight; + wr[1] += (float(((int8_t *)br)[1]) / 127.0) * weight; + wr[2] += (float(((int8_t *)br)[2]) / 127.0) * weight; + } else { + wr[0] += br[0] * weight; + wr[1] += br[1] * weight; + wr[2] += br[2] * weight; + } } } break; case VS::ARRAY_TANGENT: { - if (s->format & VS::ARRAY_COMPRESS_TANGENT) { - wr[0] += (float(((int8_t *)br)[0]) / 127.0) * weight; - wr[1] += (float(((int8_t *)br)[1]) / 127.0) * weight; - wr[2] += (float(((int8_t *)br)[2]) / 127.0) * weight; - wr[3] = (float(((int8_t *)br)[3]) / 127.0); + if (s->format & VS::ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) { + if (s->format & VS::ARRAY_COMPRESS_TANGENT && s->format & VS::ARRAY_FORMAT_NORMAL && s->format & VS::ARRAY_COMPRESS_NORMAL) { + Vector2 oct(((int8_t *)br)[0] / 127.0, ((int8_t *)br)[1] / 127.0); + float sign; + Vector3 vec = VS::oct_to_tangent(oct, &sign); + wr[0] += vec.x * weight; + wr[1] += vec.y * weight; + wr[2] += vec.z * weight; + wr[3] = sign * weight; + } else { + Vector2 oct(((int16_t *)rd)[0] / 32767.0, ((int16_t *)rd)[1] / 32767.0); + float sign; + Vector3 vec = VS::oct_to_tangent(oct, &sign); + wr[0] += vec.x * weight; + wr[1] += vec.y * weight; + wr[2] += vec.z * weight; + wr[3] = sign * weight; + } } else { - wr[0] += br[0] * weight; - wr[1] += br[1] * weight; - wr[2] += br[2] * weight; - wr[3] = br[3]; + if (s->format & VS::ARRAY_COMPRESS_TANGENT) { + wr[0] += (float(((int8_t *)br)[0]) / 127.0) * weight; + wr[1] += (float(((int8_t *)br)[1]) / 127.0) * weight; + wr[2] += (float(((int8_t *)br)[2]) / 127.0) * weight; + wr[3] = (float(((int8_t *)br)[3]) / 127.0); + } else { + wr[0] += br[0] * weight; + wr[1] += br[1] * weight; + wr[2] += br[2] * weight; + wr[3] = br[3]; + } } } break; case VS::ARRAY_COLOR: {