有没有办法将Y旋转轴压缩到一个字节?

Is there a way to compress Y rotation axis to one byte?

我正在制作一个 Unity 多人游戏,我想将 Y 旋转轴从发送整个四元数压缩为只发送一个字节。

  1. 我的第一次压缩尝试:
  1. 第二次压缩尝试:
  1. 第三次压缩尝试(失败)

我的问题是,是否有可能以更...正确的方式进行第三次压缩尝试,或者我的潜在解决方案是我唯一可能实现的?

我不会说你总共节省了 15 个字节 ^^

如果您只需要旋转的一个组成部分,那么同步单个浮点数(4 字节)的第一步似乎非常明显;)

我还要说,超出这个范围听起来有点像不必要的微优化。


增量同步非常巧妙,乍一看是从 4 字节到 2 字节的 100% 改进。

但是

  • 它也很容易出错,如果只有一个传输失败,可能会不同步。

  • 这当然会将精度降低到 1 度整数步,而不是完整的 float 值。

老实说,为了稳定性和精度,我会坚持使用 4 个字节。


2 个字节 - 大约 0.0055° 精度

有了 2 个字节,您实际上可以比您的尝试做得更好!

为什么仅仅为了值的符号就浪费整个字节?

使用 short

  • 对符号
  • 使用单个
  • 还有 15 位 留给值!

您只需要将 -180180 的浮点范围映射到 -3276832767 的范围。

发送中

// your delta between -180 and 180
float actualAngleDelta;

var shortAngleDelta = (short)Mathf.RondToInt(actualAngleDelta / 180f * shortMaxValue);
var sendBytes = BitConverter.GetBytes(shortAngleDelta);

正在接收

short shortAngleDelta = BitConverter.ToInt16(receivedBytes);
float actualAngleDelta = (float) shortAngleDelta / (float)short.MaxValue * 360f;

但老实说,您不应该同步增量,而应该同步实际值。

所以,使用 ushort!

它涵盖了从 065535 的值,因此只需在其上映射可能的 360 度。当然,您在精度上有所损失,但不会完全下降;)

// A value between 0 and 360
float actualAngle;

ushort ushortAngle = (ushort) Mathf.RoundToInt((actualAngle % 360f) / 360f * ushort.MaxValue);
byte[] sendBytes = BitConverter.GetBytes(ushortAngle);

正在接收

ushort ushortAngle = BitConverter.ToUInt16(receivedBytes, 0);
float actualAngle = (float)ushortAngle / (float)ushort.MaxValue * 360f;

两者都将精度保持在大约 0.0055 (= 360/65535) 度!


单字节 - 约 1.41° 精度

如果您无论如何都可以选择较低的精度,您可以完全花哨并说您不同步每个精确的旋转角度,而是将一个圆划分为 256 步而不是 360 步。

然后您可以将增量映射到粒度较小的“度”角,并可以在单个字节中覆盖整个圆:

发送中

byte sendByte = (byte)Mathf.RoundToInt((actualAngle % 360f) / 360f * (float)byte.MaxValue); 

正在接收

float actualAngle = receivedByte / (float)byte.MaxValue * 360f;

其精度约为 1.4 度。


但是老实说,所有这些来回计算真的值得节省 2/3 字节吗?