gpt4 book ai didi

unity3d - 理解 Unitys 中的 RGBA 编码 float (EncodeFloatRGBA)

转载 作者:行者123 更新时间:2023-12-04 19:34:25 24 4
gpt4 key购买 nike

内置的 Unity 着色器支持将 32 位 RGBA 值编码和解码为 32 位浮点数的技术。这可以通过简单地将每个 channel 与它之前的 channel 的最高可能值相乘来完成。由于它存储在浮点数中,因此预计会出现一些精度损失。

着色器显然有一些我试图理解的优化。

UnityCG.cginc 代码中的着色器如下所示:

// Encoding/decoding [0..1) floats into 8 bit/channel RGBA. Note that 1.0 will not be encoded properly.
inline float4 EncodeFloatRGBA( float v )
{
float4 kEncodeMul = float4(1.0, 255.0, 65025.0, 16581375.0);
float kEncodeBit = 1.0/255.0;
float4 enc = kEncodeMul * v;
enc = frac (enc);
enc -= enc.yzww * kEncodeBit;
return enc;
}
inline float DecodeFloatRGBA( float4 enc )
{
float4 kDecodeDot = float4(1.0, 1/255.0, 1/65025.0, 1/16581375.0);
return dot( enc, kDecodeDot );
}

所以我的问题:
  • 为什么G channel 乘以255而不是256(2^8=256),B channel 乘以65025而不是65536(2^16=65536),A channel 乘以16581375而不是16777216(2^72=1677) )。
  • 点积似乎与分数相乘,所以 f = R + 255 * G + 65025 * B + 16581375 * A不会给出兼容的结果。为什么要做出这个选择?
  • 最佳答案

    从检查来看,Unity 代码看起来像是要转换介于 0.0 之间的浮点值。和 1.0 (不包括 1)成 4 个介于 0.0 之间的浮点值和 1.0这样,这些值可以通过乘以 255 转换为从 0 到 255 的整数值。

    但是,该死,您对这段代码持怀疑态度确实是正确的。它有很多缺陷(但通常会产生足够接近的结果以供大部分使用)。

    他们乘以 255 而不是 256 的原因是因为他们错误地认为通过将值保持为浮点数可以获得合理的结果(并计划稍后将浮点数转换为 0-255 值的整数,正如其他人在注释)。但是,然后他们使用了 frac()称呼。您需要将看起来像这样的浮点代码识别为具有不良代码气味 TM。

    正确的代码如下所示:

    inline float4 EncodeFloatRGBA(float v)
    {
    var vi = (uint)(v * (256.0f * 256.0f * 256.0f * 256.0f));
    var ex = (int)(vi / (256 * 256 * 256) % 256);
    var ey = (int)((vi / (256 * 256)) % 256);
    var ez = (int)((vi / (256)) % 256);
    var ew = (int)(vi % 256);
    var e = float4(ex / 255.0f, ey / 255.0f, ez / 255.0f, ew / 255.0f);
    return e;
    }


    inline float DecodeFloatRGBA(float4 enc) 
    {
    var ex = (uint)(enc.x * 255);
    var ey = (uint)(enc.y * 255);
    var ez = (uint)(enc.z * 255);
    var ew = (uint)(enc.w * 255);
    var v = (ex << 24) + (ey << 16) + (ez << 8) + ew;
    return v / (256.0f * 256.0f * 256.0f * 256.0f);
    }

    在给定随机输入的情况下,Unity 代码在大约 23% 的时间内无法准确地执行往返(如果您不使用额外的处理,例如在乘以 255 后对编码值进行舍入,则大约有 90% 的时间会失败)。上面的代码在 100% 的时间里都有效。

    请注意,32 位浮点数只有 23 位精度,因此 32 位 RGBA 值将具有前导或尾随 0 位。当开头为 0 时,您关心使用尾随位的情况可能很少见,因此您可以简化代码以不使用 ew值并编码为 RGB 而不是 RGBA。

    <咆哮>
    总而言之,我发现 Unity 代码令人不安,因为它试图重新发明我们已经拥有的东西。我们有一个很好的 IEEE 754 标准,用于将浮点数编码为 32 位值,而 RGBA 通常至少为 32 位(Unity 代码当然假设它是)。我不确定为什么他们不只是将浮点数放入 RGBA(如果需要,您仍然可以使用中间的浮点数 4,就像下面的代码一样)。如果您只是将浮点数放入 RGBA,您就不必担心 23 位的精度,而且您不仅限于 0.0 之间的值。和 1.0 .您甚至可以编码无穷大和 NaN s。该代码如下所示:
    inline float4 EncodeFloatRGBA(float v)
    {
    byte[] eb = BitConverter.GetBytes(v);
    if (BitConverter.IsLittleEndian)
    {
    return float4(eb[3] / 255.0f, eb[2] / 255.0f, eb[1] / 255.0f, eb[0] / 255.0f);
    }

    return float4(eb[0] / 255.0f, eb[1] / 255.0f, eb[2] / 255.0f, eb[3] / 255.0f);
    }


    inline float DecodeFloatRGBA(float4 enc) 
    {
    var eb = BitConverter.IsLittleEndian ?
    new[] { (byte)(enc.w * 255), (byte)(enc.z * 255),
    (byte)(enc.y * 255), (byte)(enc.x * 255) } :
    new[] { (byte)(enc.x * 255), (byte)(enc.y * 255),
    (byte)(enc.z * 255), (byte)(enc.w * 255) };
    return BitConverter.ToSingle(eb, 0);
    }

    关于unity3d - 理解 Unitys 中的 RGBA 编码 float (EncodeFloatRGBA),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41566049/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com