Browse Source

Merge pull request #60309 from The-O-King/oct

Rémi Verschelde 3 years ago
parent
commit
7b4927bb5f

+ 16 - 0
core/math/vector3.cpp

@@ -117,6 +117,22 @@ Vector3 Vector3::octahedron_decode(const Vector2 &p_oct) {
 	return n.normalized();
 }
 
+Vector2 Vector3::octahedron_tangent_encode(const float sign) const {
+	Vector2 res = this->octahedron_encode();
+	res.y = res.y * 0.5f + 0.5f;
+	res.y = sign >= 0.0f ? res.y : 1 - res.y;
+	return res;
+}
+
+Vector3 Vector3::octahedron_tangent_decode(const Vector2 &p_oct, float *sign) {
+	Vector2 oct_compressed = p_oct;
+	oct_compressed.y = oct_compressed.y * 2 - 1;
+	*sign = oct_compressed.y >= 0.0f ? 1.0f : -1.0f;
+	oct_compressed.y = Math::abs(oct_compressed.y);
+	Vector3 res = Vector3::octahedron_decode(oct_compressed);
+	return res;
+}
+
 Basis Vector3::outer(const Vector3 &p_with) const {
 	Vector3 row0(x * p_with.x, x * p_with.y, x * p_with.z);
 	Vector3 row1(y * p_with.x, y * p_with.y, y * p_with.z);

+ 2 - 0
core/math/vector3.h

@@ -112,6 +112,8 @@ struct _NO_DISCARD_ Vector3 {
 
 	Vector2 octahedron_encode() const;
 	static Vector3 octahedron_decode(const Vector2 &p_oct);
+	Vector2 octahedron_tangent_encode(const float sign) const;
+	static Vector3 octahedron_tangent_decode(const Vector2 &p_oct, float *sign);
 
 	_FORCE_INLINE_ Vector3 cross(const Vector3 &p_with) const;
 	_FORCE_INLINE_ real_t dot(const Vector3 &p_with) const;

+ 15 - 7
drivers/gles3/shaders/scene.glsl

@@ -35,8 +35,8 @@ USE_RADIANCE_MAP = true
 /*
 from RenderingServer:
 ARRAY_VERTEX = 0, // RG32F or RGB32F (depending on 2D bit)
-ARRAY_NORMAL = 1, // A2B10G10R10, A is ignored.
-ARRAY_TANGENT = 2, // A2B10G10R10, A flips sign of binormal.
+ARRAY_NORMAL = 1, // RG16 octahedral compression
+ARRAY_TANGENT = 2, // RG16 octahedral compression, sign stored in sign of G
 ARRAY_COLOR = 3, // RGBA8
 ARRAY_TEX_UV = 4, // RG32F
 ARRAY_TEX_UV2 = 5, // RG32F
@@ -54,11 +54,11 @@ layout(location = 0) in highp vec3 vertex_attrib;
 /* clang-format on */
 
 #ifdef NORMAL_USED
-layout(location = 1) in vec3 normal_attrib;
+layout(location = 1) in vec2 normal_attrib;
 #endif
 
 #if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
-layout(location = 2) in vec4 tangent_attrib;
+layout(location = 2) in vec2 tangent_attrib;
 #endif
 
 #if defined(COLOR_USED)
@@ -97,6 +97,13 @@ layout(location = 10) in uvec4 bone_attrib;
 layout(location = 11) in vec4 weight_attrib;
 #endif
 
+vec3 oct_to_vec3(vec2 e) {
+	vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y));
+	float t = max(-v.z, 0.0);
+	v.xy += t * -sign(v.xy);
+	return v;
+}
+
 #ifdef USE_INSTANCING
 layout(location = 12) in highp vec4 instance_xform0;
 layout(location = 13) in highp vec4 instance_xform1;
@@ -209,13 +216,14 @@ void main() {
 #endif
 
 #ifdef NORMAL_USED
-	vec3 normal = normal_attrib * 2.0 - 1.0;
+	vec3 normal = oct_to_vec3(normal_attrib * 2.0 - 1.0);
 #endif
 	highp mat3 model_normal_matrix = mat3(model_matrix);
 
 #if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
-	vec3 tangent = tangent_attrib.xyz * 2.0 - 1.0;
-	float binormalf = tangent_attrib.a * 2.0 - 1.0;
+	vec2 signed_tangent_attrib = tangent_attrib * 2.0 - 1.0;
+	vec3 tangent = oct_to_vec3(vec2(signed_tangent_attrib.x, abs(signed_tangent_attrib.y) * 2.0 - 1.0));
+	float binormalf = sign(signed_tangent_attrib.y);
 	vec3 binormal = normalize(cross(normal, tangent) * binormalf);
 #endif
 

+ 8 - 9
drivers/gles3/storage/mesh_storage.cpp

@@ -124,11 +124,11 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
 
 					} break;
 					case RS::ARRAY_NORMAL: {
-						stride += sizeof(int32_t);
+						stride += sizeof(uint16_t) * 2;
 
 					} break;
 					case RS::ARRAY_TANGENT: {
-						stride += sizeof(int32_t);
+						stride += sizeof(uint16_t) * 2;
 
 					} break;
 					case RS::ARRAY_COLOR: {
@@ -604,17 +604,16 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
 			} break;
 			case RS::ARRAY_NORMAL: {
 				attribs[i].offset = vertex_stride;
-				// Will need to change to accommodate octahedral compression
-				attribs[i].size = 4;
-				attribs[i].type = GL_UNSIGNED_INT_2_10_10_10_REV;
-				vertex_stride += sizeof(float);
+				attribs[i].size = 2;
+				attribs[i].type = GL_UNSIGNED_SHORT;
+				vertex_stride += sizeof(uint16_t) * 2;
 				attribs[i].normalized = GL_TRUE;
 			} break;
 			case RS::ARRAY_TANGENT: {
 				attribs[i].offset = vertex_stride;
-				attribs[i].size = 4;
-				attribs[i].type = GL_UNSIGNED_INT_2_10_10_10_REV;
-				vertex_stride += sizeof(float);
+				attribs[i].size = 2;
+				attribs[i].type = GL_UNSIGNED_SHORT;
+				vertex_stride += sizeof(uint16_t) * 2;
 				attribs[i].normalized = GL_TRUE;
 			} break;
 			case RS::ARRAY_COLOR: {

+ 3 - 3
scene/3d/soft_dynamic_body_3d.cpp

@@ -88,10 +88,10 @@ void SoftDynamicBodyRenderingServerHandler::set_normal(int p_vertex_id, const vo
 	memcpy(&n, p_vector3, sizeof(Vector3));
 	n *= Vector3(0.5, 0.5, 0.5);
 	n += Vector3(0.5, 0.5, 0.5);
+	Vector2 res = n.octahedron_encode();
 	uint32_t value = 0;
-	value |= CLAMP(int(n.x * 1023.0), 0, 1023);
-	value |= CLAMP(int(n.y * 1023.0), 0, 1023) << 10;
-	value |= CLAMP(int(n.z * 1023.0), 0, 1023) << 20;
+	value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535);
+	value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16;
 	memcpy(&write_buffer[p_vertex_id * stride + offset_normal], &value, sizeof(uint32_t));
 }
 

+ 13 - 18
scene/3d/sprite_3d.cpp

@@ -562,23 +562,21 @@ void Sprite3D::_draw() {
 	{
 		Vector3 n = normal * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5);
 
+		Vector2 res = n.octahedron_encode();
 		uint32_t value = 0;
-		value |= CLAMP(int(n.x * 1023.0), 0, 1023);
-		value |= CLAMP(int(n.y * 1023.0), 0, 1023) << 10;
-		value |= CLAMP(int(n.z * 1023.0), 0, 1023) << 20;
+		value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535);
+		value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16;
 
 		v_normal = value;
 	}
 	uint32_t v_tangent;
 	{
 		Plane t = tangent;
+		Vector2 res = t.normal.octahedron_tangent_encode(t.d);
 		uint32_t value = 0;
-		value |= CLAMP(int((t.normal.x * 0.5 + 0.5) * 1023.0), 0, 1023);
-		value |= CLAMP(int((t.normal.y * 0.5 + 0.5) * 1023.0), 0, 1023) << 10;
-		value |= CLAMP(int((t.normal.z * 0.5 + 0.5) * 1023.0), 0, 1023) << 20;
-		if (t.d > 0) {
-			value |= 3UL << 30;
-		}
+		value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535);
+		value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16;
+
 		v_tangent = value;
 	}
 
@@ -929,23 +927,20 @@ void AnimatedSprite3D::_draw() {
 	{
 		Vector3 n = normal * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5);
 
+		Vector2 res = n.octahedron_encode();
 		uint32_t value = 0;
-		value |= CLAMP(int(n.x * 1023.0), 0, 1023);
-		value |= CLAMP(int(n.y * 1023.0), 0, 1023) << 10;
-		value |= CLAMP(int(n.z * 1023.0), 0, 1023) << 20;
+		value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535);
+		value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16;
 
 		v_normal = value;
 	}
 	uint32_t v_tangent;
 	{
 		Plane t = tangent;
+		Vector2 res = t.normal.octahedron_tangent_encode(t.d);
 		uint32_t value = 0;
-		value |= CLAMP(int((t.normal.x * 0.5 + 0.5) * 1023.0), 0, 1023);
-		value |= CLAMP(int((t.normal.y * 0.5 + 0.5) * 1023.0), 0, 1023) << 10;
-		value |= CLAMP(int((t.normal.z * 0.5 + 0.5) * 1023.0), 0, 1023) << 20;
-		if (t.d > 0) {
-			value |= 3UL << 30;
-		}
+		value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535);
+		value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16;
 		v_tangent = value;
 	}
 

+ 47 - 102
scene/resources/mesh.cpp

@@ -865,27 +865,6 @@ static Mesh::PrimitiveType _old_primitives[7] = {
 };
 #endif // DISABLE_DEPRECATED
 
-// Convert Octahedron-mapped normalized vector back to Cartesian
-// Assumes normalized format (elements of v within range [-1, 1])
-Vector3 _oct_to_norm(const Vector2 v) {
-	Vector3 res(v.x, v.y, 1 - (Math::absf(v.x) + Math::absf(v.y)));
-	float t = MAX(-res.z, 0.0f);
-	res.x += t * -SIGN(res.x);
-	res.y += t * -SIGN(res.y);
-	return res.normalized();
-}
-
-// Convert Octahedron-mapped normalized tangent vector back to Cartesian
-// out_sign provides the direction for the original cartesian tangent
-// Assumes normalized format (elements of v within range [-1, 1])
-Vector3 _oct_to_tangent(const Vector2 v, float *out_sign) {
-	Vector2 v_decompressed = v;
-	v_decompressed.y = Math::absf(v_decompressed.y) * 2 - 1;
-	Vector3 res = _oct_to_norm(v_decompressed);
-	*out_sign = SIGN(v[1]);
-	return res;
-}
-
 void _fix_array_compatibility(const Vector<uint8_t> &p_src, uint32_t p_old_format, uint32_t p_new_format, uint32_t p_elements, Vector<uint8_t> &vertex_data, Vector<uint8_t> &attribute_data, Vector<uint8_t> &skin_data) {
 	uint32_t dst_vertex_stride;
 	uint32_t dst_attribute_stride;
@@ -956,127 +935,93 @@ void _fix_array_compatibility(const Vector<uint8_t> &p_src, uint32_t p_old_forma
 					if ((p_old_format & OLD_ARRAY_COMPRESS_NORMAL) && (p_old_format & OLD_ARRAY_FORMAT_TANGENT) && (p_old_format & OLD_ARRAY_COMPRESS_TANGENT)) {
 						for (uint32_t i = 0; i < p_elements; i++) {
 							const int8_t *src = (const int8_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
-							uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
-							const Vector2 src_vec(src[0] / 127.0f, src[1] / 127.0f);
-
-							const Vector3 res = _oct_to_norm(src_vec) * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5);
-							*dst = 0;
-							*dst |= CLAMP(int(res.x * 1023.0f), 0, 1023);
-							*dst |= CLAMP(int(res.y * 1023.0f), 0, 1023) << 10;
-							*dst |= CLAMP(int(res.z * 1023.0f), 0, 1023) << 20;
+							int16_t *dst = (int16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
+
+							dst[0] = (int16_t)CLAMP(src[0] / 127.0f * 32767, -32768, 32767);
+							dst[1] = (int16_t)CLAMP(src[1] / 127.0f * 32767, -32768, 32767);
 						}
-						src_offset += sizeof(int8_t) * 2;
+						src_offset += sizeof(int16_t) * 2;
 					} else {
 						for (uint32_t i = 0; i < p_elements; i++) {
 							const int16_t *src = (const int16_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
-							uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
-							const Vector2 src_vec(src[0] / 32767.0f, src[1] / 32767.0f);
-
-							const Vector3 res = _oct_to_norm(src_vec) * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5);
-							*dst = 0;
-							*dst |= CLAMP(int(res.x * 1023.0f), 0, 1023);
-							*dst |= CLAMP(int(res.y * 1023.0f), 0, 1023) << 10;
-							*dst |= CLAMP(int(res.z * 1023.0f), 0, 1023) << 20;
+							int16_t *dst = (int16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
+
+							dst[0] = src[0];
+							dst[1] = src[1];
 						}
 						src_offset += sizeof(int16_t) * 2;
 					}
 				} else { // No Octahedral compression
 					if (p_old_format & OLD_ARRAY_COMPRESS_NORMAL) {
-						const float multiplier = 1.f / 127.f * 1023.0f;
-
 						for (uint32_t i = 0; i < p_elements; i++) {
 							const int8_t *src = (const int8_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
-							uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
+							const Vector3 original_normal(src[0], src[1], src[2]);
+							Vector2 res = original_normal.octahedron_encode();
 
-							*dst = 0;
-							*dst |= CLAMP(int(src[0] * multiplier), 0, 1023);
-							*dst |= CLAMP(int(src[1] * multiplier), 0, 1023) << 10;
-							*dst |= CLAMP(int(src[2] * multiplier), 0, 1023) << 20;
+							uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
+							dst[0] = (uint16_t)CLAMP(res.x * 65535, 0, 65535);
+							dst[1] = (uint16_t)CLAMP(res.y * 65535, 0, 65535);
 						}
-						src_offset += sizeof(uint32_t);
+						src_offset += sizeof(uint16_t) * 2;
 					} else {
 						for (uint32_t i = 0; i < p_elements; i++) {
 							const float *src = (const float *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
-							uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
+							const Vector3 original_normal(src[0], src[1], src[2]);
+							Vector2 res = original_normal.octahedron_encode();
 
-							*dst = 0;
-							*dst |= CLAMP(int(src[0] * 1023.0), 0, 1023);
-							*dst |= CLAMP(int(src[1] * 1023.0), 0, 1023) << 10;
-							*dst |= CLAMP(int(src[2] * 1023.0), 0, 1023) << 20;
+							uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
+							dst[0] = (uint16_t)CLAMP(res.x * 65535, 0, 65535);
+							dst[1] = (uint16_t)CLAMP(res.y * 65535, 0, 65535);
 						}
-						src_offset += sizeof(float) * 3;
+						src_offset += sizeof(uint16_t) * 2;
 					}
 				}
 
 			} break;
 			case OLD_ARRAY_TANGENT: {
 				if (p_old_format & OLD_ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) {
-					if (p_old_format & OLD_ARRAY_COMPRESS_TANGENT) { // int8
+					if (p_old_format & OLD_ARRAY_COMPRESS_TANGENT) { // int8 SNORM -> uint16 UNORM
 						for (uint32_t i = 0; i < p_elements; i++) {
 							const int8_t *src = (const int8_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
-							uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]];
-							const Vector2 src_vec(src[0] / 127.0f, src[1] / 127.0f);
-							float out_sign;
-							const Vector3 res = _oct_to_tangent(src_vec, &out_sign) * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5);
-
-							*dst = 0;
-							*dst |= CLAMP(int(res.x * 1023.0), 0, 1023);
-							*dst |= CLAMP(int(res.y * 1023.0), 0, 1023) << 10;
-							*dst |= CLAMP(int(res.z * 1023.0), 0, 1023) << 20;
-							if (out_sign > 0) {
-								*dst |= 3 << 30;
-							}
+							uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]];
+
+							dst[0] = (uint16_t)CLAMP((src[0] / 127.0f * .5f + .5f) * 65535, 0, 65535);
+							dst[1] = (uint16_t)CLAMP((src[1] / 127.0f * .5f + .5f) * 65535, 0, 65535);
 						}
-						src_offset += sizeof(int8_t) * 2;
-					} else { // int16
+						src_offset += sizeof(uint16_t) * 2;
+					} else { // int16 SNORM -> uint16 UNORM
 						for (uint32_t i = 0; i < p_elements; i++) {
 							const int16_t *src = (const int16_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
-							uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]];
-							const Vector2 src_vec(src[0] / 32767.0f, src[1] / 32767.0f);
-							float out_sign;
-							Vector3 res = _oct_to_tangent(src_vec, &out_sign) * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5);
-
-							*dst = 0;
-							*dst |= CLAMP(int(res.x * 1023.0), 0, 1023);
-							*dst |= CLAMP(int(res.y * 1023.0), 0, 1023) << 10;
-							*dst |= CLAMP(int(res.z * 1023.0), 0, 1023) << 20;
-							if (out_sign > 0) {
-								*dst |= 3 << 30;
-							}
+							uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]];
+
+							dst[0] = (uint16_t)CLAMP((src[0] / 32767.0f * .5f + .5f) * 65535, 0, 65535);
+							dst[1] = (uint16_t)CLAMP((src[1] / 32767.0f * .5f + .5f) * 65535, 0, 65535);
 						}
-						src_offset += sizeof(int16_t) * 2;
+						src_offset += sizeof(uint16_t) * 2;
 					}
 				} else { // No Octahedral compression
 					if (p_old_format & OLD_ARRAY_COMPRESS_TANGENT) {
-						const float multiplier = 1.f / 127.f * 1023.0f;
-
 						for (uint32_t i = 0; i < p_elements; i++) {
 							const int8_t *src = (const int8_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
-							uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]];
-
-							*dst = 0;
-							*dst |= CLAMP(int(src[0] * multiplier), 0, 1023);
-							*dst |= CLAMP(int(src[1] * multiplier), 0, 1023) << 10;
-							*dst |= CLAMP(int(src[2] * multiplier), 0, 1023) << 20;
-							if (src[3] > 0) {
-								*dst |= 3 << 30;
-							}
+							const Vector3 original_tangent(src[0], src[1], src[2]);
+							Vector2 res = original_tangent.octahedron_tangent_encode(src[3]);
+
+							uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
+							dst[0] = (uint16_t)CLAMP(res.x * 65535, 0, 65535);
+							dst[1] = (uint16_t)CLAMP(res.y * 65535, 0, 65535);
 						}
-						src_offset += sizeof(uint32_t);
+						src_offset += sizeof(uint16_t) * 2;
 					} else {
 						for (uint32_t i = 0; i < p_elements; i++) {
 							const float *src = (const float *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
-							uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]];
-
-							*dst = 0;
-							*dst |= CLAMP(int(src[0] * 1023.0), 0, 1023);
-							*dst |= CLAMP(int(src[1] * 1023.0), 0, 1023) << 10;
-							*dst |= CLAMP(int(src[2] * 1023.0), 0, 1023) << 20;
-							if (src[3] > 0) {
-								*dst |= 3 << 30;
-							}
+							const Vector3 original_tangent(src[0], src[1], src[2]);
+							Vector2 res = original_tangent.octahedron_tangent_encode(src[3]);
+
+							uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
+							dst[0] = (uint16_t)CLAMP(res.x * 65535, 0, 65535);
+							dst[1] = (uint16_t)CLAMP(res.y * 65535, 0, 65535);
 						}
-						src_offset += sizeof(float) * 4;
+						src_offset += sizeof(uint16_t) * 2;
 					}
 				}
 			} break;

+ 13 - 5
servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl

@@ -15,11 +15,11 @@ layout(location = 0) in vec3 vertex_attrib;
 //only for pure render depth when normal is not used
 
 #ifdef NORMAL_USED
-layout(location = 1) in vec3 normal_attrib;
+layout(location = 1) in vec2 normal_attrib;
 #endif
 
 #if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
-layout(location = 2) in vec4 tangent_attrib;
+layout(location = 2) in vec2 tangent_attrib;
 #endif
 
 #if defined(COLOR_USED)
@@ -58,6 +58,13 @@ layout(location = 10) in uvec4 bone_attrib;
 layout(location = 11) in vec4 weight_attrib;
 #endif
 
+vec3 oct_to_vec3(vec2 e) {
+	vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y));
+	float t = max(-v.z, 0.0);
+	v.xy += t * -sign(v.xy);
+	return v;
+}
+
 /* Varyings */
 
 layout(location = 0) out vec3 vertex_interp;
@@ -231,12 +238,13 @@ void vertex_shader(in uint instance_index, in bool is_multimesh, in SceneData sc
 
 	vec3 vertex = vertex_attrib;
 #ifdef NORMAL_USED
-	vec3 normal = normal_attrib * 2.0 - 1.0;
+	vec3 normal = oct_to_vec3(normal_attrib * 2.0 - 1.0);
 #endif
 
 #if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
-	vec3 tangent = tangent_attrib.xyz * 2.0 - 1.0;
-	float binormalf = tangent_attrib.a * 2.0 - 1.0;
+	vec2 signed_tangent_attrib = tangent_attrib * 2.0 - 1.0;
+	vec3 tangent = oct_to_vec3(vec2(signed_tangent_attrib.x, abs(signed_tangent_attrib.y) * 2.0 - 1.0));
+	float binormalf = sign(signed_tangent_attrib.y);
 	vec3 binormal = normalize(cross(normal, tangent) * binormalf);
 #endif
 

+ 13 - 5
servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl

@@ -16,11 +16,11 @@ layout(location = 0) in vec3 vertex_attrib;
 //only for pure render depth when normal is not used
 
 #ifdef NORMAL_USED
-layout(location = 1) in vec3 normal_attrib;
+layout(location = 1) in vec2 normal_attrib;
 #endif
 
 #if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
-layout(location = 2) in vec4 tangent_attrib;
+layout(location = 2) in vec2 tangent_attrib;
 #endif
 
 #if defined(COLOR_USED)
@@ -59,6 +59,13 @@ layout(location = 10) in uvec4 bone_attrib;
 layout(location = 11) in vec4 weight_attrib;
 #endif
 
+vec3 oct_to_vec3(vec2 e) {
+	vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y));
+	float t = max(-v.z, 0.0);
+	v.xy += t * -sign(v.xy);
+	return v;
+}
+
 /* Varyings */
 
 layout(location = 0) highp out vec3 vertex_interp;
@@ -229,12 +236,13 @@ void main() {
 
 	vec3 vertex = vertex_attrib;
 #ifdef NORMAL_USED
-	vec3 normal = normal_attrib * 2.0 - 1.0;
+	vec3 normal = oct_to_vec3(normal_attrib * 2.0 - 1.0);
 #endif
 
 #if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
-	vec3 tangent = tangent_attrib.xyz * 2.0 - 1.0;
-	float binormalf = tangent_attrib.a * 2.0 - 1.0;
+	vec3 signed_tangent_attrib = tangent_attrib * 2.0 - 1.0;
+	vec3 tangent = oct_to_vec3(vec2(signed_tangent_attrib.x, abs(signed_tangent_attrib.y) * 2.0 - 1.0));
+	float binormalf = sign(signed_tangent_attrib.y);
 	vec3 binormal = normalize(cross(normal, tangent) * binormalf);
 #endif
 

+ 52 - 12
servers/rendering/renderer_rd/shaders/skeleton.glsl

@@ -54,14 +54,54 @@ layout(push_constant, std430) uniform Params {
 }
 params;
 
-vec4 decode_abgr_2_10_10_10(uint base) {
-	uvec4 abgr_2_10_10_10 = (uvec4(base) >> uvec4(0, 10, 20, 30)) & uvec4(0x3FF, 0x3FF, 0x3FF, 0x3);
-	return vec4(abgr_2_10_10_10) / vec4(1023.0, 1023.0, 1023.0, 3.0) * 2.0 - 1.0;
+vec2 uint_to_vec2(uint base) {
+	uvec2 decode = (uvec2(base) >> uvec2(0, 16)) & uvec2(0xFFFF, 0xFFFF);
+	return vec2(decode) / vec2(65535.0, 65535.0) * 2.0 - 1.0;
 }
 
-uint encode_abgr_2_10_10_10(vec4 base) {
-	uvec4 abgr_2_10_10_10 = uvec4(clamp(ivec4((base * 0.5 + 0.5) * vec4(1023.0, 1023.0, 1023.0, 3.0)), ivec4(0), ivec4(0x3FF, 0x3FF, 0x3FF, 0x3))) << uvec4(0, 10, 20, 30);
-	return abgr_2_10_10_10.x | abgr_2_10_10_10.y | abgr_2_10_10_10.z | abgr_2_10_10_10.w;
+vec3 oct_to_vec3(vec2 oct) {
+	vec3 v = vec3(oct.xy, 1.0 - abs(oct.x) - abs(oct.y));
+	float t = max(-v.z, 0.0);
+	v.xy += t * -sign(v.xy);
+	return v;
+}
+
+vec3 decode_uint_oct_to_norm(uint base) {
+	return oct_to_vec3(uint_to_vec2(base));
+}
+
+vec4 decode_uint_oct_to_tang(uint base) {
+	vec2 oct_sign_encoded = uint_to_vec2(base);
+	// Binormal sign encoded in y component
+	vec2 oct = vec2(oct_sign_encoded.x, abs(oct_sign_encoded.y) * 2.0 - 1.0);
+	return vec4(oct_to_vec3(oct), sign(oct_sign_encoded.y));
+}
+
+vec2 signNotZero(vec2 v) {
+	return mix(vec2(-1.0), vec2(1.0), greaterThanEqual(v.xy, vec2(0.0)));
+}
+
+uint vec2_to_uint(vec2 base) {
+	uvec2 enc = uvec2(clamp(ivec2(base * vec2(65535, 65535)), ivec2(0), ivec2(0xFFFF, 0xFFFF))) << uvec2(0, 16);
+	return enc.x | enc.y;
+}
+
+vec2 vec3_to_oct(vec3 e) {
+	e /= abs(e.x) + abs(e.y) + abs(e.z);
+	vec2 oct = e.z >= 0.0f ? e.xy : (vec2(1.0f) - abs(e.yx)) * signNotZero(e.xy);
+	return oct * 0.5f + 0.5f;
+}
+
+uint encode_norm_to_uint_oct(vec3 base) {
+	return vec2_to_uint(vec3_to_oct(base));
+}
+
+uint encode_tang_to_uint_oct(vec4 base) {
+	vec2 oct = vec3_to_oct(base.xyz);
+	// Encode binormal sign in y component
+	oct.y = oct.y * 0.5f + 0.5f;
+	oct.y = base.w >= 0.0f ? oct.y : 1 - oct.y;
+	return vec2_to_uint(oct);
 }
 
 void main() {
@@ -131,12 +171,12 @@ void main() {
 	src_offset += 3;
 
 	if (params.has_normal) {
-		normal = decode_abgr_2_10_10_10(src_vertices.data[src_offset]).rgb;
+		normal = decode_uint_oct_to_norm(src_vertices.data[src_offset]);
 		src_offset++;
 	}
 
 	if (params.has_tangent) {
-		tangent = decode_abgr_2_10_10_10(src_vertices.data[src_offset]);
+		tangent = decode_uint_oct_to_tang(src_vertices.data[src_offset]);
 	}
 
 	if (params.has_blend_shape) {
@@ -155,12 +195,12 @@ void main() {
 				base_offset += 3;
 
 				if (params.has_normal) {
-					blend_normal += decode_abgr_2_10_10_10(src_blend_shapes.data[base_offset]).rgb * w;
+					blend_normal += decode_uint_oct_to_norm(src_blend_shapes.data[base_offset]) * w;
 					base_offset++;
 				}
 
 				if (params.has_tangent) {
-					blend_tangent += decode_abgr_2_10_10_10(src_blend_shapes.data[base_offset]).rgb * w;
+					blend_tangent += decode_uint_oct_to_tang(src_blend_shapes.data[base_offset]).rgb * w;
 				}
 
 				blend_total += w;
@@ -234,12 +274,12 @@ void main() {
 	dst_offset += 3;
 
 	if (params.has_normal) {
-		dst_vertices.data[dst_offset] = encode_abgr_2_10_10_10(vec4(normal, 0.0));
+		dst_vertices.data[dst_offset] = encode_norm_to_uint_oct(normal);
 		dst_offset++;
 	}
 
 	if (params.has_tangent) {
-		dst_vertices.data[dst_offset] = encode_abgr_2_10_10_10(tangent);
+		dst_vertices.data[dst_offset] = encode_tang_to_uint_oct(tangent);
 	}
 
 #endif

+ 4 - 5
servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp

@@ -1073,10 +1073,9 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
 				} break;
 				case RS::ARRAY_NORMAL: {
 					vd.offset = stride;
+					vd.format = RD::DATA_FORMAT_R16G16_UNORM;
+					stride += sizeof(uint16_t) * 2;
 
-					vd.format = RD::DATA_FORMAT_A2B10G10R10_UNORM_PACK32;
-
-					stride += sizeof(uint32_t);
 					if (mis) {
 						buffer = mis->vertex_buffer;
 					} else {
@@ -1085,9 +1084,9 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
 				} break;
 				case RS::ARRAY_TANGENT: {
 					vd.offset = stride;
+					vd.format = RD::DATA_FORMAT_R16G16_UNORM;
+					stride += sizeof(uint16_t) * 2;
 
-					vd.format = RD::DATA_FORMAT_A2B10G10R10_UNORM_PACK32;
-					stride += sizeof(uint32_t);
 					if (mis) {
 						buffer = mis->vertex_buffer;
 					} else {

+ 24 - 27
servers/rendering_server.cpp

@@ -398,16 +398,14 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
 
 				const Vector3 *src = array.ptr();
 				for (int i = 0; i < p_vertex_array_len; i++) {
-					Vector3 n = src[i] * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5);
-
-					uint32_t value = 0;
-					value |= CLAMP(int(n.x * 1023.0), 0, 1023);
-					value |= CLAMP(int(n.y * 1023.0), 0, 1023) << 10;
-					value |= CLAMP(int(n.z * 1023.0), 0, 1023) << 20;
+					Vector2 res = src[i].octahedron_encode();
+					int16_t vector[2] = {
+						(int16_t)CLAMP(res.x * 65535, 0, 65535),
+						(int16_t)CLAMP(res.y * 65535, 0, 65535),
+					};
 
-					memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], &value, 4);
+					memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], vector, 4);
 				}
-
 			} break;
 
 			case RS::ARRAY_TANGENT: {
@@ -416,33 +414,32 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
 				if (type == Variant::PACKED_FLOAT32_ARRAY) {
 					Vector<float> array = p_arrays[ai];
 					ERR_FAIL_COND_V(array.size() != p_vertex_array_len * 4, ERR_INVALID_PARAMETER);
-					const float *src = array.ptr();
+					const float *src_ptr = array.ptr();
 
 					for (int i = 0; i < p_vertex_array_len; i++) {
-						uint32_t value = 0;
-						value |= CLAMP(int((src[i * 4 + 0] * 0.5 + 0.5) * 1023.0), 0, 1023);
-						value |= CLAMP(int((src[i * 4 + 1] * 0.5 + 0.5) * 1023.0), 0, 1023) << 10;
-						value |= CLAMP(int((src[i * 4 + 2] * 0.5 + 0.5) * 1023.0), 0, 1023) << 20;
-						if (src[i * 4 + 3] > 0) {
-							value |= 3UL << 30;
-						}
-
-						memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], &value, 4);
+						const Vector3 src(src_ptr[i * 4 + 0], src_ptr[i * 4 + 1], src_ptr[i * 4 + 2]);
+						Vector2 res = src.octahedron_tangent_encode(src_ptr[i * 4 + 3]);
+						int16_t vector[2] = {
+							(int16_t)CLAMP(res.x * 65535, 0, 65535),
+							(int16_t)CLAMP(res.y * 65535, 0, 65535),
+						};
+
+						memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], vector, 4);
 					}
 				} else { // PACKED_FLOAT64_ARRAY
 					Vector<double> array = p_arrays[ai];
 					ERR_FAIL_COND_V(array.size() != p_vertex_array_len * 4, ERR_INVALID_PARAMETER);
-					const double *src = array.ptr();
+					const double *src_ptr = array.ptr();
 
 					for (int i = 0; i < p_vertex_array_len; i++) {
-						uint32_t value = 0;
-						value |= CLAMP(int((src[i * 4 + 0] * 0.5 + 0.5) * 1023.0), 0, 1023);
-						value |= CLAMP(int((src[i * 4 + 1] * 0.5 + 0.5) * 1023.0), 0, 1023) << 10;
-						value |= CLAMP(int((src[i * 4 + 2] * 0.5 + 0.5) * 1023.0), 0, 1023) << 20;
-						if (src[i * 4 + 3] > 0) {
-							value |= 3UL << 30;
-						}
-						memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], &value, 4);
+						const Vector3 src(src_ptr[i * 4 + 0], src_ptr[i * 4 + 1], src_ptr[i * 4 + 2]);
+						Vector2 res = src.octahedron_tangent_encode(src_ptr[i * 4 + 3]);
+						int16_t vector[2] = {
+							(int16_t)CLAMP(res.x * 65535, 0, 65535),
+							(int16_t)CLAMP(res.y * 65535, 0, 65535),
+						};
+
+						memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], vector, 4);
 					}
 				}
 			} break;