float16xyz编码

2019-05-06

float16xyz编码

原理

  • 服务器往客户端发送坐标的时候,通常用三位的float类型的xyz来同步位置,占用3个float的带宽
  • float16xyz编码通过压缩存储,在保存数值的同时,减少一半的带宽 ,但是会有少许的精度损失,只能用来坐标这类型的数值

测试实现

  • main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#include <iostream>
#include <cstdint>

#define uint unsigned int
#define uint16 short int
class Float16XYZ
{
public:
Float16XYZ();
Float16XYZ( float x, float y, float z );

inline void packXYZ( float x, float y, float z );
inline void unpackXYZ( float & x, float & y, float & z ) const;

inline void dx( float value );
inline float dx() const;
inline void dy( float value );
inline float dy() const;
inline void dz( float value );
inline float dz() const;


private:
union MultiType
{
float asFloat;
uint asUint;
int asInt;
};
unsigned char data_x_[2], data_y_[2], data_z_[2];
};


/**
* Constructor.
*/
inline Float16XYZ::Float16XYZ()
{
}


/**
* Constructor.
*/
inline Float16XYZ::Float16XYZ( float x, float y, float z )
{
this->dx( x );
this->dy( y );
this->dz( z );
}


/**
* This method packs the three input floats into this object.
*/
inline void Float16XYZ::packXYZ( float x, float y, float z )
{
this->dx( x );
this->dy( y );
this->dz( z );
}


/**
* This method unpacks this object into the three input floats.
*/
inline void Float16XYZ::unpackXYZ( float & x, float & y, float & z ) const
{
x = this->dx();
y = this->dy();
z = this->dz();
}


/**
* This method sets the packed a value from a float.
*/
#define SET_ATTR_DATA( ATTR_NAME ) inline void Float16XYZ::d##ATTR_NAME( float ATTR_NAME ) \
{ \
const float addValues[] = { 2.f, -2.f }; \
MultiType a; a.asFloat = ATTR_NAME; \
a.asFloat += addValues[ a.asInt < 0 ]; \
uint16& aDataInt = *(uint16*)data_##ATTR_NAME##_; \
aDataInt = (a.asUint >> 12) & 0x7fff; \
aDataInt |= ((a.asUint >> 16) & 0x8000); \
}

SET_ATTR_DATA(x)
SET_ATTR_DATA(y)
SET_ATTR_DATA(z)

/**
* This method returns the packed a value as a float.
*/
#define GET_ATTR_DATA( ATTR_NAME ) inline float Float16XYZ::d##ATTR_NAME() const \
{ \
MultiType a; \
a.asUint = 0x40000000; \
uint16& aDataInt = *(uint16*)data_##ATTR_NAME##_; \
a.asUint |= (aDataInt & 0x7fff) << 12; \
a.asFloat -= 2.f; \
a.asUint |= (aDataInt & 0x8000) << 16; \
return a.asFloat; \
}

GET_ATTR_DATA(x)
GET_ATTR_DATA(y)
GET_ATTR_DATA(z)


int main( int argc, char * argv[] )
{
float x = 10.34;
float y = 1.25;
float z = 53.89;
Float16XYZ a;
a.packXYZ(x,y,z);
std::cout << "float input: "<< x << "," << y << "," << z << std::endl;
a.unpackXYZ(x,y,z);
std::cout << "sizeof before:" << 3 * sizeof(x) << ", after" << sizeof(a) << std::endl;
std::cout << "result:" << x << "," << y << "," << z << std::endl;
}