【问题标题】:Storing 2 Single Floats in One将 2 个单浮点数存储在一个中
【发布时间】:2013-12-23 22:49:58
【问题描述】:

我已经阅读了几个讨论在一个浮点数中存储 2 或 3 个浮点数的链接。这是一个例子:

Storing two float values in a single float variable

还有一个:

http://uncommoncode.wordpress.com/2012/11/07/float-packing-in-shaders-encoding-multiple-components-in-one-float/

还有一个:

decode rgb value to single float without bit-shift in glsl

我见过其他人,但他们都使用相同的原则。如果要对 x 和 y 进行编码,它们会将 y 乘以某个因子,然后将 x 添加到其中。好吧,这在纸上是这样,但我不明白它在存储为浮点值时如何工作。浮点值只有 7 位有效数字。如果将大数和小数相加,则小数只会被截断并丢失。精度只显示大数的值。

由于似乎每个人都开出相同的方法,所以我自己尝试了一下,结果完全符合我的想法。当我解码这些数字时,没有相乘的数字变成了 0.0。它完全丢失在编码的浮点数中。

这是我尝试测试的一些 MaxScript 示例:

cp = 256.0 * 256.0
scaleFac = 16777215

for i = 1 to 20 do (
    for j = 1 to 20 do (
            x = (i as float / 20.01f) as float;
            y = (j as float / 20.01f) as float;
            xScaled = x * scaleFac;
            yScaled = y * scaleFac;

            f = (xScaled + yScaled * cp) as float
            print ("x[" + xScaled as string + "] y[" + yScaled as string + "]" + " e[" + f as string + "]")

            dy = floor(f / cp)
            dx = (f - dy * cp)

            print ("x[" + dx as string + "] y[" + dy as string + "]" + " e[" + f as string + "]")
    )
)

dx 每次都是 0.0。任何人都可以对此有所了解吗?注意:我是否使 cp = 128、256、512 或其他任何值都没有关系。它仍然给我相同类型的结果。

【问题讨论】:

  • 这纯粹是一种学术练习,还是您真的希望从中获得一些价值?
  • 这不是学术性的。我试图弄清楚如何合法地将两个花车打包成一个。如果您查看任何链接,您会看到其他人显示类似的代码并声称它工作正常,但我对它如何实际工作感到困惑。我自己似乎无法让它工作。也许我在自己的实现中一直遗漏一些数学错误,但它背后的整个理论似乎并不应该奏效。
  • 如果我有时间,我会详细查看这些链接。但是,如果我在你的鞋子里,我不会用十英尺长的杆子碰它。我有 Tuple<float, float> 将两个浮点数存储在一个值中。
  • 这是一个实时渲染限制问题。我需要将要解码的数据打包到顶点着色器中。其他人在现实世界的应用程序中也做过同样的事情。当你让它工作时,它非常实用。

标签: c# c++ encoding floating-point glsl


【解决方案1】:

此方法适用于存储两个整数。通过乘以scaleFac,您可以有效地将浮点数转换为大整数,这很好,但最好使用int() 使其明确。然后,您需要确保两件事:cp 大于您正在使用的最大数字 (scaleFac),并且 cp 的平方小到足以放入浮点数而无需截断 (单精度浮点数约为 7 位)。

【讨论】:

  • 嗯。这两件事在我看过的任何其他材料中都没有提到。这只是头脑的知识,还是在某处有关编码技术的书中提到过?
  • 我只使用了你提出的两点就让它工作了。谢谢。我不认为我看到的其他示例使用的是现实范围或其他东西。我不知道到底是什么让我用我使用的数字走错了路。我再看看。我想我现在一切都很好!
  • @Jim,还有一件事 - 如果您使用 int 而不是 float,您将可以使用更多数字。
【解决方案2】:

这是 C 中的一个工作代码,用于将两个 floats 打包成一个 float 并解压缩它们。

您应该根据可能的值范围 (yourBiggestNumber * scaleFactor < cp) 更改 scaleFactor 和 cp 参数。这是一场精确的战斗。尝试打印一些结果,为您的案例找到合适的值。下面的示例允许在 [0 to 1) 范围内浮动。

#include <math.h>

/* yourBiggestNumber * scaleFactor < cp */
double scaleFactor = 65530.0;
double cp = 256.0 * 256.0;

/* packs given two floats into one float */
float pack_float(float x, float y) {
    int x1 = (int) (x * scaleFactor);
    int y1 = (int) (y * scaleFactor);
    float f = (y1 * cp) + x1;
    return f;
}

/* unpacks given float to two floats */
int unpack_float(float f, float* x, float* y){
  double dy = floor(f / cp);
  double dx = f - (dy * cp);
  *y = (float) (dy / scaleFactor);
  *x = (float) (dx / scaleFactor);
  return 0;
}

【讨论】:

    【解决方案3】:

    只有当您的个人花车小到可以装入一个花车位置时,它才会起作用。

    因此,您可以通过将其“划分”成两个来存储 2 个可以用一半空间表示的数字来打包 2 个数字。

    【讨论】:

      【解决方案4】:

      这是我用来打包和解包浮动的代码。它的工作原理是将第一个浮点数 (0..1) 打包到 8 位 (0..256) 数字的前四个字节中,然后将下一个浮点数打包到剩余的 4 位中。结果数字有 16 个可能的组合,每个 (2^4)。在某些情况下,这已经足够了:

      private float PackFloatsInto8Bits( float v1, float v2 )
      {
          var a = Mathf.Round( v1 * 15f );
          var b = Mathf.Round( v2 * 15f );
      
          var bitShiftVector = new Vector2( 1f/( 255f/16f ), 1f/255f );
      
          return Vector2.Dot( new Vector2( a, b ), bitShiftVector );
      }
      
      private Vector2 UnpackFloatsFrom8Bits( float input )
      {
          float temp = input * 15.9375f;
      
          float a = Mathf.Floor(temp) / 15.0f;
          float b = Frac( temp ) * 1.0667f;
      
          return new Vector2(a, b);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-10-21
        • 2018-11-19
        • 1970-01-01
        • 1970-01-01
        • 2019-11-16
        • 2012-07-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多