在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 = 255rcp(maxInt) = 1.0 / 255i * 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 = 255f * maxInt = 0.50196 * 255 ≈ 128f * 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。t1和t2:计算解包系数。i = int((val / t2) + rcp(precisionMinusOne)):解包整数部分。f = saturate((-t2 * float(i) + val) / t1):解包浮点数部分。
数学原理
- 该函数基于以下公式:
val = t1 * f + t2 * i- 通过解方程,得到
f和i的值。
示例
- 输入:
val = 0.75,maxi = 10.0,precision = 256.0 - 计算:
precisionMinusOne = 256.0 - 1.0 = 255.0t1 = ((256.0 / 10.0) - 1.0) / 255.0 ≈ 0.0980392t2 = (256.0 / 10.0) / 255.0 ≈ 0.100392i = int((0.75 / 0.100392) + (1.0 / 255.0)) ≈ 7f = saturate((-0.100392 * 7 + 0.75) / 0.0980392) ≈ 0.5
- 输出:
f = 0.5,i = 7
总结
-
PackInt:- 将整数归一化到
[0, 1]范围,用于存储到浮点数中。
- 将整数归一化到
-
UnpackInt:- 将浮点数还原为整数,用于从浮点数中提取整数值。
-
UnpackFloatInt:- 将浮点数解包为整数部分和浮点数部分,用于高级数据存储和解包。
这些函数通常用于将多个数据(如整数和浮点数)打包到一个浮点数中,以节省存储空间或优化数据传输。