2013-07-14 258 views
6

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

到目前为止我发现的最好的解决方法是硬接线在编码值小数点的偏移,并将其存储为“载体”浮动的整数和小数:

123.456 -> 12.3 and 45.6 

它可以”吨处理负值,但没关系。

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

编辑:关于任务的详细原因:

我与那里的顶点数据存储为花车在统一固定的数据结构的工作。 (Float2代表UV,float3代表正常,等等)。显然没有办法正确添加额外的数据,所以我必须在这些限制内工作,这就是为什么我认为这完全归结为更一般的编码数据问题。例如,我可以牺牲次要UV数据来传输2×2额外数据通道。

目标是着色器模型3.0,但我不介意解码在SM2.0上也可以合理工作。

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

+0

@ZoltanE:你知道你想要编码的变量的范围吗? –

+0

@ZoltanE:你的目标是什么着色器模型和DirectX版本?你能给出更多关于你为什么编码的细节吗?最后:考虑在[gamedev](http://gamedev.stackexchange.com/)网站上提问,你可能会得到更好的答案。 –

+3

也许这个问题http://stackoverflow.com/questions/4811219/pack-four-bytes-in-a-float可能会帮助你。 – Gnietschow

回答

2

按照Gnietschow的建议,我改编了YellPika的算法。 (它的C#团结3D)

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); 
} 

的快速和肮脏的测试产生了以下统计数据(100万随机值对在0..1范围):

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上的结果可能会更糟。

无论如何,我不知道这是否是最好的算法,但它似乎足够我的情况。

+0

你介意解释为什么'input%precision'部分工作吗?你正在做一个浮点数和一个整数模数,但模数只能在整数上定义。 – mrueg

+0

该定义不限于整数:“模运算找到一个数除以另一个的余数”。 问:“当我将7.7除以3.3时,余数是多少?” – ZoltanE

+0

注意:如果'input.y'超过'1'则会中断。在这种情况下,'+ output.y'只是增加了'precision'值的另一个增量 - 然后'input%precision'只能解压input.y的小数部分,并且它的整数部分(除以'精度“)被添加到'output.x'。 – meetar