ネットワーク その6 量子化で圧縮

ビット数の少ない方が多いものより消費するスペースは小さくなります。

もしint型の値が0~100までの範囲しか取らないと判っているのなら、そのまま4バイトのint型として送るより、byte型にキャストして送ることができます。

場合によっては値が表す範囲を値をずらすことによって減らすことができます。例えば、キャラクターの高さのデータを送る必要があり、高さはcmで表されるとします。このゲーム中のキャラクターの高さの範囲は、ドワーフ(100cm)から巨人(300cm)まであります。

300という値はbyteで表現できる範囲(0-255)を超えているので、キャストすることはできません。

しかし、100cm以下のキャラクターが存在しないと判っているのなら、100cmを基点とすることで値の取る範囲を小さくすることができます。

 PacketWriter.Write( (byte)( height - 100 ) );

 

受信側では値を使う前に100を足すだけです。これで、キャラクターの高さの範囲は0-200になり、byteにキャストすることができます。

 

他にもスケーリングすることで値の取る範囲を小さくすることができます。例えば、浮動小数点で表されるラジアン角度を送る場合があるとします。ラジアンで円を表す範囲は0~2πになります。この値を0~255の範囲に収まるようにスケーリングすれば、byteにキャストして送ることができます。

     float rotationEncodeScale = 255.0f / MathHelper.TwoPi;
    PacketWriter.Write( (byte)( rotation * rotationEncodeScale ) );

 

受信側では逆数を掛けることで、元の値にします。

     float rotationDecodeScale = MathHelper.TwoPi / 255.0f;
    float rotation = (float)PacketReader.ReadByte() * rotationDecodeScale;

 

この量子化では、精度が多少失われてしまいますが、通常は4バイトのデータを1/4に減らすことの方が価値があります。

 

訳注:
原文のコードでは255ではなく256を使っていますが、この場合に変換できる値は上限値未満の時に動作します。もし、上限値を指定した場合、結果は256になり、byteにキャストすると結果は0になってしまいます。ですが、この例で扱っている値はラジアンなので円を表す場合、値が0とMathHelper.TwoPiの時は結果が同じになるので問題なく動作します。

同じ手法はシェーダープログラムなどで使うのですが、この場合に良く用いられるのは0~1までの値で1以下の値を取るので、この場合はスケールを255にしないと動作しません。

以上の理由から、ここではスケール値を255に変更しました。

 

原文:
http://blogs.msdn.com/shawnhar/archive/2007/12/24/network-compression-quantization.aspx