所谓HDR就是高动态范围的意思。在普通的显示器和位图里,每通道都是8-bit,也就是说RGB分量的范围都是0-255,这用来表示现实中的颜色显然是远远不够的。现实中的图像的动态范围远远大的多,那么如何在现有的显示设备里尽可能的保持更大的动态范围,而且让它能更符合人眼的习惯就成了图形学研究的一个热点。通常真正的HDR的做法都是采用浮点纹理,把渲染运算的过程中,我们使用16bit的动态范围来保存运算结果,然后对运算结果进行分析,求出这个图像的中间灰度值,然后对图像进行调整映射到LDR的设备中。但是这样的算法有两个非常耗资源的过程,其中一个是浮点纹理,另外一个就是求图像中间灰度(通常情况是把图像不停的渲染到RenderTarget,每渲染一次,图像大小缩小一半,直到缩小到1x1大,一个1024 x1024的图像需要渲染10次!)。因此虽然HDR的效果非常漂亮,但是目前还是只有为数不多的产品采用了这样的算法,大部分都是采用的伪HDR+blow效果。
伪HDR效果通常是重新调整图像的亮度曲线,让亮的更亮,暗的更暗一些,而Blow效果则是图像的亮度扩散开来,产生柔和的效果。
在这里采用一个二次曲线来重新调整图像的亮度,这个曲线的方程是
x [ (2-4k) x + 4k-1 ).
K的取值范围为0.5 – 2.0
经过这个公式调整以后,图像上亮的区域将更加的亮,并且整体亮度会提高。那么接下来,如何使图像的亮度扩散开来呢?一种可行的方法就是对场景图像做一次downsample。把它变成原来的1/4次大小,那样就等于亮度往外扩散了4x4个象素的区域。
技术方案已经基本有了。接下来将要在RenderMonkey里实现它,和前面的例子不同,这里需要使用RenderMonkey的多pass渲染:
第一个pass我们先对图像进行downsample操作。首先在原来的pass前增加一个新的pass,并命名为downsample pass。然后建立一个render to texture的纹理节点,设定它的大小(原图像大小的1/4),并在新建立的pass里建立一个render target的节点指向它。这样,这个pass的渲染结果就会保存到这个render to texture中。这个pass的pixel shader只要使用前面模糊效果的shader就可以了。
接下来,将另外一个pass命名为render pass,并增加一个新的纹理对象。并把纹理对象指向刚才增加的render to texture,以便能在该pass中使用这个downsample过的图像。然后增加一个float类型的变量,用来表示上面公式中提到的k值;最终工作区的结构如下图:
接下来编辑render pass的pixel shader。代码如下:
下面是原图像和经过处理后图像的对比:
原图
k = 1.1
k = 1.6
图:经过伪HDR+Blow处理过的图像和原图的对比