8

我想将两个浮点值存储在一个 32 位浮点变量中。编码将在 C# 中进行,而解码将在 HLSL 着色器中完成。

到目前为止,我发现的最佳解决方案是将小数点的偏移量硬连接到编码值中,并将它们存储为“载体”浮点数的整数和小数:

123.456 -> 12.3 and 45.6

它不能处理负值,但没关系。

但是我想知道是否有更好的方法来做到这一点。

编辑:有关该任务的更多详细信息:

我正在使用 Unity 中的固定数据结构,其中顶点数据存储为浮点数。(Float2 表示 UV,float3 表示法线,等等。)显然没有办法正确添加额外的数据,所以我必须在这些限制内工作,这就是为什么我认为这一切都归结为更普遍的编码数据问题. 例如,我可以牺牲辅助 UV 数据来传输 2x2 额外数据通道。

目标是着色器模型 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 以浮点精度偷工减料,结果可能会更糟。

无论如何,我不知道这是否是最好的算法,但对于我的情况来说似乎已经足够了。

于 2013-07-17T08:55:40.763 回答