转自:http://blog.sina.com.cn/s/blog_70f96aa90102v0t7.html
U3D EncodeFloatRGBA&DecodeFloatRGBA
UnityCG.cginc中的原函数代码如下:
inline float4 EncodeFloatRGBA( float v )
{
float4 kEncodeMul = float4(1.0, 255.0, 65025.0, 160581375.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/160581375.0);
return dot( enc, kDecodeDot );
}
单单看代码实在让人摸不着头脑,展开后可得EncodeFloatRGBA的最终结果为:
x = 1/v - 1/(v*255^2); //R
y = 1/(v*255) - 1/(v*255^3); //G
z = 1/(v*255^2) - 1/(v*255^4); //B
w = 1/(v*255^3) - 1/(v*255^4); //A
感觉抓到了一点东西,但是还是不是很清楚,再看Decode函数计算结果:
[1/v-1/(v255^2)] + [1/(v2552)-1/(v*2554)] + [1/(v2554)-1/(v*2556)] + [1/(v2556)-1/(v*2557)]
=1/v-1/(v*255^7)
这下应该一目了然了,Encode函数是把一个float类型的值存进四个RGBA中,为了提高精度(float值的有效位数只有7位),R值存的是[0, 1/2552]段的值,G值存的是[1/2552, 1/255^4]的值,往后依次类推。GBA三个分量分别乘以了255, 2552,2553。这样保证其精度落在float类型的有效位数内。至于1/255^7后面的数值,则基本可以忽略不计了,而且float也存不下了。
说的再简单一点,举个例子,比如现在有个float类型的值h=1.23456…,我如果把h存在一个int整形的变量里面,那么小数后面的精度肯定丢失了。如果我想保留,那么可以用四个整形变量a, r, g, b来保存,a = 1, r = 2, g = 3, b = 4。这样g可以表示为:h = a+0.1r+0.01g+0.001*b。这个原理其实和上面的Encode和Decode是一样的,只不过这个例子用的是10倍,而U3D中是255倍。