diff --git a/src/utils/mini_glm.cpp b/src/utils/mini_glm.cpp index 066e13981..6bc584107 100644 --- a/src/utils/mini_glm.cpp +++ b/src/utils/mini_glm.cpp @@ -55,35 +55,35 @@ namespace MiniGLM Log::info("MiniGLM::unitTesting", "Quaternion compression"); core::quaternion quat(11.0f, 44.0f, 55.0f, 77.0f); quat.normalize(); - packed = compressQuaternion(quat); + packed = compressIrrQuaternion(quat); core::quaternion out_quat = decompressQuaternion(packed); Log::info("MiniGLM::unitTesting", "Result before: x:%f y:%f z:%f w:%f," " after: x:%f y:%f z:%f w:%f", quat.X, quat.Y, quat.Z, quat.W, out_quat.X, out_quat.Y, out_quat.Z, out_quat.W); quat = core::quaternion(-23.0f, -44.0f, -7.0f, 0.0f); quat.normalize(); - packed = compressQuaternion(quat); + packed = compressIrrQuaternion(quat); out_quat = decompressQuaternion(packed); Log::info("MiniGLM::unitTesting", "Result before: x:%f y:%f z:%f w:%f," " after: x:%f y:%f z:%f w:%f", quat.X, quat.Y, quat.Z, quat.W, out_quat.X, out_quat.Y, out_quat.Z, out_quat.W); quat = core::quaternion(0.0f, 0.0f, 0.0f, 1.0f); quat.normalize(); - packed = compressQuaternion(quat); + packed = compressIrrQuaternion(quat); out_quat = decompressQuaternion(packed); Log::info("MiniGLM::unitTesting", "Result before: x:%f y:%f z:%f w:%f," " after: x:%f y:%f z:%f w:%f", quat.X, quat.Y, quat.Z, quat.W, out_quat.X, out_quat.Y, out_quat.Z, out_quat.W); quat = core::quaternion(0.0f, 0.0f, 0.0f, -1.0f); quat.normalize(); - packed = compressQuaternion(quat); + packed = compressIrrQuaternion(quat); out_quat = decompressQuaternion(packed); Log::info("MiniGLM::unitTesting", "Result before: x:%f y:%f z:%f w:%f," " after: x:%f y:%f z:%f w:%f", quat.X, quat.Y, quat.Z, quat.W, out_quat.X, out_quat.Y, out_quat.Z, out_quat.W); quat = core::quaternion(-43.0f, 20.0f, 16.0f, -88.0f); quat.normalize(); - packed = compressQuaternion(quat); + packed = compressIrrQuaternion(quat); out_quat = decompressQuaternion(packed); Log::info("MiniGLM::unitTesting", "Result before: x:%f y:%f z:%f w:%f," " after: x:%f y:%f z:%f w:%f", quat.X, quat.Y, quat.Z, quat.W, diff --git a/src/utils/mini_glm.hpp b/src/utils/mini_glm.hpp index 1e99c8377..56db5b856 100644 --- a/src/utils/mini_glm.hpp +++ b/src/utils/mini_glm.hpp @@ -21,6 +21,7 @@ #include "LinearMath/btQuaternion.h" #include "utils/vec3.hpp" +#include #include #include #include @@ -231,7 +232,8 @@ namespace MiniGLM } } // toFloat16 // ------------------------------------------------------------------------ - inline uint32_t normalizedSignedFloatsTo1010102(std::array src) + inline uint32_t normalizedSignedFloatsTo1010102 + (const std::array& src, int extra_2_bit = -1) { int part = 0; uint32_t packed = 0; @@ -265,19 +267,17 @@ namespace MiniGLM part = (int)((v * 512.0f) - 0.5f); } packed |= ((uint32_t)part & 1023) << 20; - v = fminf(1.0f, fmaxf(-1.0f, src[3])); - if (v > 0.0f) + if (extra_2_bit >= 0) { - part = (int)((v * 1.0f) + 0.5f); + part = extra_2_bit; } else { - part = (int)((v * 2.0f) - 0.5f); + part = (int)(-0.5f); } - part = (int)((v * 2.0f) - 0.5f); packed |= ((uint32_t)part & 3) << 30; return packed; - } // fourFloatsTo1010102 + } // normalizedSignedFloatsTo1010102 // ------------------------------------------------------------------------ inline std::array vertexType2101010RevTo4HF(uint32_t packed) { @@ -329,7 +329,7 @@ namespace MiniGLM inline std::array extractNormalizedSignedFloats(uint32_t packed, bool calculate_w = false) { - std::array ret; + std::array ret = {}; int part = packed & 1023; if (part & 512) { @@ -357,29 +357,56 @@ namespace MiniGLM { ret[2] = (float)part * (1.0f / 511.0f); } - part = (packed >> 30) & 3; - if (part & 2) - { - ret[3] = (float)(4 - part) * (-1.0f / 2.0f); - } - else - { - ret[3] = (float)part; - } if (calculate_w) { - float w = sqrtf(fmaxf(0.0f, 1.0f - + float largest_val = sqrtf(fmaxf(0.0f, 1.0f - (ret[0] * ret[0]) - (ret[1] * ret[1]) - (ret[2] * ret[2]))); - ret[3] = ret[3] > 0.0f ? w : -w; + part = (packed >> 30) & 3; + switch(part) + { + case 0: + { + auto tmp = ret; + ret[0] = largest_val; + ret[1] = tmp[0]; + ret[2] = tmp[1]; + ret[3] = tmp[2]; + break; + } + case 1: + { + auto tmp = ret; + ret[0] = tmp[0]; + ret[1] = largest_val; + ret[2] = tmp[1]; + ret[3] = tmp[2]; + break; + } + case 2: + { + auto tmp = ret; + ret[0] = tmp[0]; + ret[1] = tmp[1]; + ret[2] = largest_val; + ret[3] = tmp[2]; + break; + } + case 3: + ret[3] = largest_val; + break; + default: + assert(false); + break; + } } return ret; } // extractNormalizedSignedFloats // ------------------------------------------------------------------------ - // Please normalize vector and quaternion before compressing + // Please normalize vector before compressing // ------------------------------------------------------------------------ inline uint32_t compressVector3(const irr::core::vector3df& vec) { - return normalizedSignedFloatsTo1010102({{vec.X, vec.Y, vec.Z, 0.0f}}); + return normalizedSignedFloatsTo1010102({{vec.X, vec.Y, vec.Z}}); } // compressVector3 // ------------------------------------------------------------------------ inline core::vector3df decompressVector3(uint32_t packed) @@ -389,12 +416,67 @@ namespace MiniGLM return ret.normalize(); } // decompressVector3 // ------------------------------------------------------------------------ - inline uint32_t compressQuaternion(const core::quaternion& q) + inline uint32_t compressQuaternion(const btQuaternion& q) { - return normalizedSignedFloatsTo1010102({{q.X, q.Y, q.Z, - q.W >= 0.0f ? 1.0f : -1.0f}}); + const float length = q.length(); + assert(length != 0.0f); + std::array tmp_2 = + {{ + q.x() / length, + q.y() / length, + q.z() / length, + q.w() / length + }}; + std::array tmp_3; + auto ret = std::max_element(tmp_2.begin(), tmp_2.end(), + [](float a, float b) { return std::abs(a) < std::abs(b); }); + int extra_2_bit = int(std::distance(tmp_2.begin(), ret)); + switch (extra_2_bit) + { + case 0: + { + float neg = tmp_2[0] < 0.0f ? -1.0f : 1.0f; + tmp_3[0] = tmp_2[1] * neg; + tmp_3[1] = tmp_2[2] * neg; + tmp_3[2] = tmp_2[3] * neg; + break; + } + case 1: + { + float neg = tmp_2[1] < 0.0f ? -1.0f : 1.0f; + tmp_3[0] = tmp_2[0] * neg; + tmp_3[1] = tmp_2[2] * neg; + tmp_3[2] = tmp_2[3] * neg; + break; + } + case 2: + { + float neg = tmp_2[2] < 0.0f ? -1.0f : 1.0f; + tmp_3[0] = tmp_2[0] * neg; + tmp_3[1] = tmp_2[1] * neg; + tmp_3[2] = tmp_2[3] * neg; + break; + } + case 3: + { + float neg = tmp_2[3] < 0.0f ? -1.0f : 1.0f; + tmp_3[0] = tmp_2[0] * neg; + tmp_3[1] = tmp_2[1] * neg; + tmp_3[2] = tmp_2[2] * neg; + break; + } + default: + assert(false); + break; + } + return normalizedSignedFloatsTo1010102(tmp_3, extra_2_bit); } // compressQuaternion // ------------------------------------------------------------------------ + inline uint32_t compressIrrQuaternion(const core::quaternion& q) + { + return compressQuaternion(btQuaternion(q.X, q.Y, q.Z, q.W)); + } + // ------------------------------------------------------------------------ inline core::quaternion decompressQuaternion(uint32_t packed) { const std::array out = extractNormalizedSignedFloats(packed, @@ -403,12 +485,6 @@ namespace MiniGLM return ret.normalize(); } // decompressQuaternion // ------------------------------------------------------------------------ - inline uint32_t compressbtQuaternion(const btQuaternion& q) - { - return normalizedSignedFloatsTo1010102({{q.x(), q.y(), q.z(), - q.w() >= 0.0f ? 1.0f : -1.0f}}); - } // compressbtQuaternion - // ------------------------------------------------------------------------ inline btQuaternion decompressbtQuaternion(uint32_t packed) { const std::array out = extractNormalizedSignedFloats(packed,