8

2 つの float 値を 1 つの 32 ビット float 変数に格納したいと思います。エンコードは C# で行われ、デコードは HLSL シェーダーで行われます。

これまでに見つけた最善の解決策は、エンコードされた値の小数のオフセットを配線し、それらを「キャリア」浮動小数点数の整数と小数として格納することです。

123.456 -> 12.3 and 45.6

負の値は処理できませんが、問題ありません。

しかし、これを行うためのより良い方法があるかどうか疑問に思っていました。

編集:タスクに関するいくつかの詳細:

頂点データが float として格納される Unity の固定データ構造を使用しています。(UV の場合は Float2、法線の場合は float3 など。)どうやら余分なデータを適切に追加する方法がないため、これらの制限内で作業する必要があります。そのため、データのエンコードに関するより一般的な問題が原因であると考えました。 . たとえば、2x2 の余分なデータ チャネルを転送するために、セカンダリ UV データを犠牲にすることができます。

ターゲットはシェーダーモデル 3.0 ですが、SM2.0 でもデコードが適切に機能していれば問題ありません。

「合理的」である限り、データの損失は問題ありません。期待される値の範囲は 0..64 ですが、考えてみると 0..1 でも問題ないでしょう。重要なことは、精度をできるだけ高く保つことです。負の値は重要ではありません。

4

1 に答える 1

3

Gnietschow の推奨に従い、 YellPika のアルゴリズムを採用しました。(Unity 3d の C# です。)

float Pack(Vector2 input, int precision)
{
    Vector2 output = input;
    output.x = Mathf.Floor(output.x * (precision - 1));
    output.y = Mathf.Floor(output.y * (precision - 1));

    return (output.x * precision) + output.y;
}

Vector2 Unpack(float input, int precision)
{
    Vector2 output = Vector2.zero;

    output.y = input % precision;
    output.x = Mathf.Floor(input / precision);

    return output / (precision - 1);
}

簡易テストでは、次の統計が生成されました (0 ~ 1 の範囲の 100 万のランダムな値のペア)。

Precision: 2048 | Avg error: 0.00024424 | Max error: 0.00048852
Precision: 4096 | Avg error: 0.00012208 | Max error: 0.00024417
Precision: 8192 | Avg error: 0.00011035 | Max error: 0.99999940

4096 の精度がスイート スポットのようです。これらのテストでは、パッキングとアンパッキングの両方が CPU で実行されたため、GPU で float 精度で手抜きをすると結果が悪化する可能性があることに注意してください。

とにかく、これが最良のアルゴリズムかどうかはわかりませんが、私の場合は十分に良さそうです。

于 2013-07-17T08:55:40.763 に答える