在HLSL中对浮点数和整数之间进行转换

Table of Contents

以下是逐行注释和详细说明的Unity Shader代码分析:


1. 打包整数函数 PackInt

float PackInt(uint i, uint numBits) // 打包整数
{
    uint maxInt = (1u << numBits) - 1u; // 计算最大整数值
    return saturate(i * rcp(maxInt)); // 将整数归一化到[0, 1]范围
}

功能说明

  • 该函数将一个无符号整数 i 打包为一个浮点数,范围在 [0, 1] 之间。
  • 通过将整数 i 除以最大整数值 maxInt,将其归一化到 [0, 1] 范围。

参数说明

  • i:需要打包的无符号整数。
  • numBits:整数的位数,用于计算最大整数值。

关键点

  • 1u << numBits:通过左移操作计算 2^numBits,即最大整数值加1。
  • maxInt = (1u << numBits) - 1u:计算最大整数值。例如,numBits = 8 时,maxInt = 255
  • rcp(maxInt):计算 1.0 / maxInt,用于归一化。
  • saturate:将结果限制在 [0, 1] 范围内,防止溢出。

示例

  • 输入:i = 128, numBits = 8
  • 计算:
    • maxInt = (1u << 8) - 1u = 255
    • rcp(maxInt) = 1.0 / 255
    • i * rcp(maxInt) = 128 / 255 ≈ 0.50196
  • 输出:0.50196

2. 解包整数函数 UnpackInt

uint UnpackInt(float f, uint numBits) // 解包整数
{
    uint maxInt = (1u << numBits) - 1u; // 计算最大整数值
    return (uint)(f * maxInt + 0.5); // 将浮点数还原为整数
}

功能说明

  • 该函数将一个浮点数 f 解包为一个无符号整数。
  • 通过将浮点数 f 乘以最大整数值 maxInt,将其还原为整数。

参数说明

  • f:需要解包的浮点数,范围在 [0, 1] 之间。
  • numBits:整数的位数,用于计算最大整数值。

关键点

  • f * maxInt:将浮点数 f 映射到 [0, maxInt] 范围。
  • + 0.5:四舍五入,确保整数精度。
  • (uint):将结果转换为无符号整数。

示例

  • 输入:f = 0.50196, numBits = 8
  • 计算:
    • maxInt = (1u << 8) - 1u = 255
    • f * maxInt = 0.50196 * 255 ≈ 128
    • f * maxInt + 0.5 ≈ 128.5
  • 输出:128

3. 解包浮点数和整数函数 UnpackFloatInt

void UnpackFloatInt(float val, float maxi, float precision, out float f, out uint i) // 解包浮点数和整数
{
    float precisionMinusOne = precision - 1.0; // 计算精度减1
    float t1 = ((precision / maxi) - 1.0) / precisionMinusOne; // 计算系数t1
    float t2 = (precision / maxi) / precisionMinusOne; // 计算系数t2

    i = int((val / t2) + rcp(precisionMinusOne)); // 解包整数部分
    f = saturate((-t2 * float(i) + val) / t1); // 解包浮点数部分
}

功能说明

  • 该函数将一个浮点数 val 解包为一个浮点数 f 和一个整数 i
  • 通过数学公式,将 val 分解为整数部分和浮点数部分。

参数说明

  • val:需要解包的浮点数。
  • maxi:整数的最大值。
  • precision:精度值,用于控制解包的精度。
  • f:输出的浮点数部分。
  • i:输出的整数部分。

关键点

  • precisionMinusOne = precision - 1.0:计算精度减1。
  • t1t2:计算解包系数。
  • i = int((val / t2) + rcp(precisionMinusOne)):解包整数部分。
  • f = saturate((-t2 * float(i) + val) / t1):解包浮点数部分。

数学原理

  • 该函数基于以下公式:
    • val = t1 * f + t2 * i
    • 通过解方程,得到 fi 的值。

示例

  • 输入:val = 0.75, maxi = 10.0, precision = 256.0
  • 计算:
    • precisionMinusOne = 256.0 - 1.0 = 255.0
    • t1 = ((256.0 / 10.0) - 1.0) / 255.0 ≈ 0.0980392
    • t2 = (256.0 / 10.0) / 255.0 ≈ 0.100392
    • i = int((0.75 / 0.100392) + (1.0 / 255.0)) ≈ 7
    • f = saturate((-0.100392 * 7 + 0.75) / 0.0980392) ≈ 0.5
  • 输出:f = 0.5, i = 7

总结

  1. PackInt

    • 将整数归一化到 [0, 1] 范围,用于存储到浮点数中。
  2. UnpackInt

    • 将浮点数还原为整数,用于从浮点数中提取整数值。
  3. UnpackFloatInt

    • 将浮点数解包为整数部分和浮点数部分,用于高级数据存储和解包。

这些函数通常用于将多个数据(如整数和浮点数)打包到一个浮点数中,以节省存储空间或优化数据传输。

kumakoko avatar
kumakoko
pure coder
comments powered by Disqus