Improve compress quaternion by only dropping the largest value out of 4

This commit is contained in:
Benau 2018-07-13 12:56:55 +08:00
parent 565dfcef96
commit 5330951842
2 changed files with 111 additions and 35 deletions

View File

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

View File

@ -21,6 +21,7 @@
#include "LinearMath/btQuaternion.h"
#include "utils/vec3.hpp"
#include <algorithm>
#include <array>
#include <cassert>
#include <cstdint>
@ -231,7 +232,8 @@ namespace MiniGLM
}
} // toFloat16
// ------------------------------------------------------------------------
inline uint32_t normalizedSignedFloatsTo1010102(std::array<float, 4> src)
inline uint32_t normalizedSignedFloatsTo1010102
(const std::array<float, 3>& 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<short, 4> vertexType2101010RevTo4HF(uint32_t packed)
{
@ -329,7 +329,7 @@ namespace MiniGLM
inline std::array<float, 4> extractNormalizedSignedFloats(uint32_t packed,
bool calculate_w = false)
{
std::array<float, 4> ret;
std::array<float, 4> 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<float, 4> tmp_2 =
{{
q.x() / length,
q.y() / length,
q.z() / length,
q.w() / length
}};
std::array<float, 3> 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<float, 4> 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<float, 4> out = extractNormalizedSignedFloats(packed,