把float编码到RGBA8

编码和解码

单通道的float是32-bit,RGBA8也是,所以按说把float编码到RGBA8的纹理中应该没啥问题。很可惜的是,不支持浮点纹理的硬件往往也不支持整数指令和位运算操作。所以在这里需要有些限制。在网上搜了一下,最靠谱的应该是大牛Aras Pranckevičius(aras-p)多年前的帖子。他的做法可以把[0, 1)范围内的浮点数,仅仅用shader model 2的指令,就编码到RGBA8。其实[0, 1)基本就够用了,其他的只要除个常数,读取后乘回去就可以了。编码和解码的函数很简单:

float4 EncodeFloatRGBA(float v) 
{
     float4 enc = float4(1.0f, 255.0f, 65025.0f, 16581375.0f) * v; 
     enc = frac(enc); 
     enc -= enc.yzww * float4(1 / 255.0f, 1 / 255.0f, 1 / 255.0f, 0); 
     return enc; 

 float DecodeFloatRGBA(float4 rgba) 
{
     return dot(rgba, float4(1, 1 / 255.0f, 1 / 65025.0f, 1 / 16581375.0f)); 
}

这里的65025和16581375其实就是255的平方和立方。(aras-p的原文有一处笔误,把16581375写成了160581375。)

长啥样


用途

这个东西能用在什么地方呢?流水线中目前有三处可能可以用到的:

HDR post process

在HDR post process里面,通过统计图像来产生自适应亮度调整的时候,只用到了单通道的float16和float32纹理,所以这里可以用这个方法进行编码。

Depth

在Pre-depth的时候,也可以把32-bit的depth编码后存到RGBA8。

ESM

Exponential shadow map只需要用到一个通道,也能顺利使用这个技巧。

这些应用我以后都会有专门的帖子展开讨论。





posted @ 2013-11-06 09:07  EnoroF  阅读(1515)  评论(0编辑  收藏  举报