简体   繁体   English

在单个浮点变量中存储两个浮点值

[英]Storing two float values in a single float variable

I'd like to store two float values in a single 32 bit float variable.我想在一个 32 位浮点变量中存储两个浮点值。 The encoding will happen in C# while the decoding is to be done in a HLSL shader.编码将在 C# 中进行,而解码将在 HLSL 着色器中完成。

The best solution I've found so far is hard-wiring the offset of the decimal in the encoded values and storing them as integer and decimal of the "carrier" float:到目前为止,我发现的最佳解决方案是在编码值中硬连接小数点的偏移量,并将它们存储为“载体”浮点数的整数和小数:

123.456 -> 12.3 and 45.6

It can't handle negative values but that's ok.它无法处理负值,但没关系。

However I was wondering if there is a better way to do this.但是我想知道是否有更好的方法来做到这一点。

EDIT: A few more details about the task:编辑:有关该任务的更多详细信息:

I'm working with a fixed data structure in Unity where the vertex data is stored as floats.我正在 Unity 中使用固定数据结构,其中顶点数据存储为浮点数。 (Float2 for a UV, float3 the normal, and so on.) Apparently there is no way to properly add extra data so I have to work within these limits, that's why I figured it was all down to a more general issue of encoding data. (Float2 表示 UV,float3 表示正常,等等。)显然没有办法正确添加额外的数据,所以我必须在这些限制内工作,这就是为什么我认为这一切都归结为编码数据的更普遍的问题. For example I could sacrifice the secondary UV data to transfer the 2x2 extra data channels.例如,我可以牺牲辅助 UV 数据来传输 2x2 额外数据通道。

The target is shader model 3.0 but I wouldn't mind if the decoding was working reasonably on SM2.0 too.目标是着色器模型 3.0,但我不介意解码在 SM2.0 上是否也能正常工作。

Data loss is fine as long as it's "reasonable".只要“合理”,数据丢失就可以。 The expected value range is 0..64 but as I come to think of it 0..1 would be fine too since that is cheap to remap to any range inside the shader.预期值范围是 0..64,但我认为 0..1 也可以,因为重新映射到着色器内的任何范围都很便宜。 The important thing is to keep precision as high as possible.重要的是保持尽可能高的精度。 Negative values are not important.负值并不重要。

Following Gnietschow's recommendation I adapted the algo of YellPika .根据 Gnietschow 的建议,我改编了YellPika的算法。 (It's C# for Unity 3d.) (这是 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);
}

The quick and dirty testing produced the following stats (1 million random value pairs in the 0..1 range):快速而肮脏的测试产生了以下统计数据(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

Precision of 4096 seems to be the sweet spot. 4096 的精度似乎是最佳点。 Note that both packing and unpacking in these tests ran on the CPU so the results could be worse on a GPU if it cuts corners with float precision.请注意,这些测试中的打包和解包都在 CPU 上运行,因此如果 GPU 以浮点精度偷工减料,结果可能会更糟。

Anyway, I don't know if this is the best algorithm but it seems good enough for my case.无论如何,我不知道这是否是最好的算法,但对于我的情况来说似乎已经足够了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM