HDRPipeline DX9

 HDR这个词汇在我看过的书或资料中多次出现,从《Real-time Rendering》到SDK里面的偶尔出现,一直对其是一种莫名的感觉,HDR是什么,High Dynamic Range,范围很广,为什么要HDR呢?因为了更好的画面。这些很浅显的认识让我一直云里雾里。终于在DX9的sample中有这么个简单的HDR教学实例,确实让我了解很多。在网上看到3d本身渲染的未经过HDR处理的图片和经过HDR处理过的图片比较起来,HDR所带来的图片确实让我折服。因为HDR处理后的图片让人感到身临其境的感觉。记得很多次拍照片,回来看的时候总觉得不是当时看到的那种感觉,现在我才终于知道因为不经过处理的照片是LDR(Low Dynamic Range)的,也就是照片记录不了大世界的HDR。所以我们感觉不一样。聊了一会后让我们开始认识HDR吧。

 

HDR的英文就是High Dynamic Range,也就是高动态范围。这是指的一个场景汇中最亮区域和最暗区域之间的光亮范围。在我们所处的世界中,这个范围是很广的,或者说光亮的梯度很多。但是我们的显示器,我们颜色表示确很小,255个亮度梯度变化。如果将HDR的场景,直接不经处理的传递给LDR,我们将会失去超过LDR的那部分信息。这样我们就得不到近似我们世界的大范围场景了。那我们应该怎么做的,从照相机发明一来,摄影师们早就发现这个问题,并且相处了处理这种问题的方案。这个方案也类似于我们将要讲述的HDRpipeline。那就是从场景中找出能大体表示场景总体亮度的灰度颜色(Key Value),然后将亮度范围根据KeyValue重新映射到相机的亮度范围内。其中包含了很多冲洗照片的标准过程。我们的程序也将使用类似的思路来完成HDR往LDR的映射。

 

相关素材(tonemap.pdf)请到我的资源中下载。

 

回到程序。我们的大体思路是,首先让程序中较亮的部分感染其邻近的颜色,这样能让图片较亮的部分呈现类似我们世界的现象感染其邻近区域。染色后,再将我们图片通过某种变换映射到LDR中。

我们大体分4个部分。

  1. 首先将场景渲染到一个高精度高范围的纹理(也就是HDR)中,这样我们能真实的记录场景的颜色和亮度。但这个纹理拿去显示同样和LDR一样,因为显示器把超出1的部分截断,所以即使你有完整的数据也别想着可以显示出来。我们还需要把HDR纹理转换到LDR纹理中。
  2. 我们将得到的场景的HDR图进行亮度求值,我们使用Down Samples(降低样本,也就是大图片平均到小图片)方法求出整个场景的平均亮度,和最大亮度。我们同样采用Down Samples的方法是为了减小计算量,因为我们要进行很多次颜色填充,所以填充量让程序很吃力,为了减少计算负担,经常采用Down Samples的方法。首先我们采用rgb中最大的分量表示该色素的亮度。我们计算平均亮度是使用几何平均的方法。也就是说使用不是使用n个样本相加再除以个数的方法,而是采用n的样本亮度相乘然后开n方根。几何平均亮度也可以采用log平均方法,这两种几何平均方法是等价的。
  3. 我们需要从场景出截出比较亮的区域。首先我们设定一个较亮区域的亮度门限值,如0.8。我们将HDR图片Down Sample并截出较亮的区域。并进一步进行Down Samples。然后采用高斯模糊方法(一种经常用于图片模糊化的模糊方法)对图片进行模糊化,这样将能让较亮区域感染其邻近区域。得模糊后的图片,Bloom图片。
  4. 我们得到这些基本部件后,就可以进行我们最关键的一步,将HDR映射到LDR。首先是作者采用标准Bilinear对Bloom图片进行取值,其实一般不必这么做,因为现在绝大多数显卡已经完全硬件支持Bilinear了。然后把取得的这些颜色添加到HDR中颜色中,得到新的HDR颜色。然后用新的HDR颜色映射到LDR。首先求出新的HDR颜色的亮度值,然后用该亮度除以先前求出的平均亮度得到解调后的新亮度。调节后的新亮度需要再次调节,这样非常亮的地方才能不至于丢失。有两种方法。如下图中的两个公式。其中L(x,y)是讲过调节的亮度值。Ld(x,y)是最后的亮度值。第一个公式是最简单的,第一个公式可以让较亮的区域缩放大约1/L(x, y)。而让较暗的区域几乎没有改变。第一个公式保证HDR映射到LDR的范围中。但较亮的区域会让细节难以辨别。第二个公式克服了这个问题。其中的L(White)是图片中的最大亮度。

 

 

最后我要说一下我的经验,在这次学习和编程中重新认识了下MS系统中光栅化和纹理读取的矛盾。

  1. 如果想用顶点XYZRHW格式的四边形,并采用Bilinear过滤将四边形的纹理正确的渲染到屏幕,我们需要将四边形往左上方向偏移0.5,因为Bilinear取值是用以该点的纹理坐标为中心,边长为1的方格中求值。为了将这个求值方格正确的对齐到相应的纹理方格中,我们只需要将把屏幕0.0点对应的纹理坐标改为0.5,0.5就可以了。为了实现这个,我们需要将四边形往左上偏移0.5,这样在0.0的纹理就变成0.5,0.5.(详细资料请参考:Directly Mapping Texels to Pixels)
  2. 进行DownSample的时候,偶数采样和奇数采样有差别。如果偶数降采样。也就是如2x2区域降采样到一个像素。第一个偏移量为0.5。而奇数采样第一个偏移量为1.因为偶数采样的时候采样点在方格角落处,而奇数采样中采样点在方格中心。如下图,如果采用经验1的方法,那么我们看看将2x2降采样到1个像素是怎么的情况。

HDRPipeline DX9_第1张图片

 

HDRPipeline DX9_第2张图片

你可能感兴趣的:(HDRPipeline DX9)