From 78881b3cc3a389c21c1417ad05840e80a234e2d7 Mon Sep 17 00:00:00 2001 From: Omar El Sheikh Date: Tue, 22 Feb 2022 18:10:09 -0500 Subject: Octahedral Normal/Tangent Compression Implementation of Octahedral normal compression into Godot 4.0 --- scene/resources/mesh.cpp | 149 +++++++++++++++-------------------------------- 1 file changed, 47 insertions(+), 102 deletions(-) (limited to 'scene') diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index ec9db89794..b71682744f 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -863,27 +863,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 &p_src, uint32_t p_old_format, uint32_t p_new_format, uint32_t p_elements, Vector &vertex_data, Vector &attribute_data, Vector &skin_data) { uint32_t dst_vertex_stride; uint32_t dst_attribute_stride; @@ -954,127 +933,93 @@ void _fix_array_compatibility(const Vector &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; -- cgit v1.2.3 From 2425d798cdb928df979ee11e55c1a98f19f06125 Mon Sep 17 00:00:00 2001 From: Omar El Sheikh Date: Sat, 20 Aug 2022 10:01:46 -0700 Subject: Octahedral Normal Support for Sprite and Soft Body Properly encode the normal and tangent vectors with octahedral compression --- scene/3d/soft_dynamic_body_3d.cpp | 6 +++--- scene/3d/sprite_3d.cpp | 31 +++++++++++++------------------ 2 files changed, 16 insertions(+), 21 deletions(-) (limited to 'scene') diff --git a/scene/3d/soft_dynamic_body_3d.cpp b/scene/3d/soft_dynamic_body_3d.cpp index 15f050defb..c9eafc77e0 100644 --- a/scene/3d/soft_dynamic_body_3d.cpp +++ b/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)); } diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index ef2b9e1ce5..42ed502e18 100644 --- a/scene/3d/sprite_3d.cpp +++ b/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; } -- cgit v1.2.3