簡體   English   中英

有沒有辦法將 Y 旋轉軸壓縮到一個字節?

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

我正在制作一個 Unity 多人游戲,我想將 Y 旋轉軸從發送整個四元數壓縮到只發送一個字節。

  1. 我的第一次壓縮嘗試:
  • 我沒有發送四元數,而是發送了一個 Y 軸浮點值
  • 結果: 16 個字節 -> 4 個字節(總共節省了 12 個字節)
  1. 第二次壓縮嘗試:
  • 我緩存了 lastSentAxis 變量(浮點數),其中包含已發送到服務器的最后一個 Y 軸值
  • 當玩家改變他們的旋轉(看右/左),然后一個新的 Y 軸與緩存的 Y 軸進行比較,並准備一個 delta 值(delta 保證小於 255)。
  • 然后,我創建一個新的 sbyte - 包含旋轉方式(-1,如果向左轉,1,如果向右轉)
  • 結果: 4 個字節 -> 2 個字節(保存 2 個字節,總共 14 個)
  1. 第三次壓縮嘗試(失敗)
  • 定義一個字節標志而不是創建前面提到的分隔字節(1 - 左,2 - 右)
  • 獲取一個增量旋轉值(如前所述),但將其添加到字節標志
  • 問題:我已經遍歷 0 到 255 來查找哪些數字會與字節標志沖突。
  • 可能的解決方案:檢查 flag + delta 是否在沖突號碼列表中。 如果是,請不要發送輪換請求。
  • 每 X 個請求,發送一個修正浮點值
  • 潛在結果: 2 個字節 -> 1 個字節(保存 1 個字節,總共 15 個)

我的問題是,是否有可能以更...正確的方式進行第三次壓縮嘗試,或者我的潛在解決方案是我能實現的唯一可能的事情?

我不會聲稱您總共節省了 15 個字節^^

如果無論如何您只需要一個旋轉組件,那么同步單個浮點數(4 個字節)的第一步實際上非常明顯;)

我還要說,超越這聽起來有點像不必要的微優化。


增量同步非常聰明,乍一看是從 4 字節到 2 字節的 100% 改進。

  • 它也很容易出錯,如果只有一次傳輸失敗,go 可能會不同步。

  • 這當然會將精度降低到 1 度 integer 步長而不是全float值。

老實說,為了穩定性和精確性,我會堅持使用 4 個字節。


2 個字節 - 大約 0.0055° 精度

使用 2 個字節,您實際上可以 go 比您的嘗試更好!

為什么僅僅為了值的符號而浪費整個字節?

使用short

  • 使用單個作為符號
  • 值還剩下15 位

你只需要 map 你的浮點范圍-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的值,因此僅 map 可能是 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° 精度

如果您無論如何都可以選擇較低的精度,那么您可以選擇 go 並說您不會以度數同步每個精確的旋轉角度,而是將圓除以 360 而不是 256 步。

然后你可以 map 增量到你的較小粒度的“度”角,並且可以在一個字節中覆蓋整個圓:

發送

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

接收

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

其精度約為1.4度。


但老實說,所有這些來回計算真的值得節省 2/3 字節嗎?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM