在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。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.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
总结
-
PackInt
:- 将整数归一化到
[0, 1]
范围,用于存储到浮点数中。
- 将整数归一化到
-
UnpackInt
:- 将浮点数还原为整数,用于从浮点数中提取整数值。
-
UnpackFloatInt
:- 将浮点数解包为整数部分和浮点数部分,用于高级数据存储和解包。
这些函数通常用于将多个数据(如整数和浮点数)打包到一个浮点数中,以节省存储空间或优化数据传输。