在单个float变量中存储两个float值

时间:2013-07-14 10:59:14

标签: c# hlsl

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

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

123.456 -> 12.3 and 45.6

它无法处理负值,但没关系。

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

编辑:关于该任务的更多细节:

我在Unity中使用固定数据结构,其中顶点数据存储为浮点数。 (Float2表示UV,float3正常,依此类推。)显然没有办法正确添加额外的数据,所以我必须在这些限制范围内工作,这就是为什么我认为这完全是一个更普遍的编码数据问题。例如,我可以牺牲二级UV数据来传输2x2额外数据通道。

目标是着色器模型3.0,但我不介意解码是否在SM2.0上合理运行。

只要数据丢失“合理”,数据丢失就可以了。预期的值范围是0..64,但是当我想到它时,0..1也会很好,因为重新映射到着色器内的任何范围都很便宜。重要的是保持尽可能高的精度。负值并不重要。

1 个答案:

答案 0 :(得分: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上的结果会更糟。

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