首页>
技术资讯>
详情

HDR渲染器的实现(基于OpenGL)

2016-05-24 来源:CC 阅读量: 0
关键词: 游戏图形图像

    HDR简介
    这篇教程讲解了如何实现一个高动态范围渲染系统。HDR(High Dynamic Range,高动态范围)是一种图像后处理技术,是一种表达超过了显示器所能表现的亮度范围的图像映射技术。高动态范围技术能够很好地再现现实生活中丰富的亮度级别,产生逼真的效果。HDR已成为目前游戏应用不可或缺的一部分。通常,显示器能够显示R、G、B分量在[0,255]之间的像素值。而256个不同的亮度级别显然不能表示自然界中光线的亮度情况。比如,太阳的亮度可能是一个白炽灯亮度的几千倍,是一个被白炽灯照亮的桌面的亮度的几十万倍,这远远超出了显示器的亮度表示能力。如何在有限的亮度范围内显示如此宽广的亮度范围,正是HDR技术所要解决的问题。
    将一个宽广的亮度范围映射到纸张或屏幕能表示的亮度范围类似于照相机的曝光功能。人眼也有类似的功能。通过照相机的光圈,可以控制进入感光器的光线数量,感光器得到的明暗程度经过一定的处理,就可以得到令人信服的照片。照相机是一个典型的从高动态范围映射到低动态范围的例子。如果我们能够在一定程度上模拟照相机的工作原理,就可以在屏幕上显示高动态范围的图像。对于人眼或镜头,过亮的光线射入时会产生光晕效果,这一点也可以通过一些方法模拟。动态曝光控制和光晕效果结合起来,就构成了一个经典的高动态范围渲染器。

    一个运行中的HDR渲染器,背景墙由于过亮而产生了光晕

    这组图像演示了动态曝光技术,图为从黑暗的隧道走向明亮的房间的一个过程,可以看到动态光线适应的过程:房间从全白色过渡到正常曝光颜色
    下面将结合OpenGL详细地介绍HDR的实现过程。其他图形API在方法上是一致的,只是具体的实现细节略有差异。
    HDR技术原理
    我们已经知道,HDR渲染包含两个步骤,一是曝光控制,即将高动态范围的图像映射到一个固定的低范围中,既屏幕能够显示的(0,1)的范围内。二是对于特别亮的部分实现光晕的效果。其中曝光控制是HDR渲染的核心环节,光晕效果对表现高亮的像素起了重要的作用。这里先分别介绍两个步骤的原理和方法,再介绍如何实现一个完整的HDR渲染器。
    在所有步骤开始之前,你必须已经通过某种方法得到了一个高动态范围的图像。高动态范围的图像每一个像素都由浮点型的R,G,B分量表示,这样每个分量都可以任意大。对于渲染器而言,这意味着一个浮点纹理。那么,如何将一个场景渲染到一个高动态范围的浮点纹理中呢?你可以为场景中的每个表面创建一张浮点格式的光照贴图,这张光照贴图的每个象素代表了表面上相应位置的光强。然后使用OpenGL的FBO(帧缓冲对象)将绑定了浮点光照贴图的场景渲染到一个同屏幕大小一致的浮点纹理中。关于FBO和浮点纹理的使用请参考《OpenGL中的浮点纹理和帧缓冲对象》 。
    好的,先来看看所谓得、的曝光控制。这个步骤在HDR渲染中被称为Tone Mapping。翻译成中文即“调和映射”。Tone Mapping有很多具体的方法,每个方法都是一个从高动态范围到低范围的一个映射,我们把这些方法统称为 Tone Mapping Operator(TMO),可见,TMO的好坏直接决定了图像的最终质量。例如,

    是一个简单的TMO,其中Lfinal是映射后的像素亮度值,L是映射前的像素亮度值,alpha是图像中的最小亮度值,beta是图像中的最大亮度值。
    又如:

    也是一个简单的TMO。这两个TMO都可以将高动态的像素值映射到(0,1)上。然而,这些TMO的效果并不令人满意。人的眼睛往往能适应场景中的光的强度,在一个黑暗的屋子里,你仍然能看见其中的东西,分辨物体的亮度和颜色,当你从屋子中突然走向明亮的室外时,会有刺眼的感觉,但很快眼睛优惠适应新的环境,从而能够看清更亮的场景。为了模拟人眼的这种特性,我们需要计算当前要渲染的高动态范围图像的平均亮度,然后根据平均亮度确定一个曝光参数,然后使用这个曝光参数将图像正确地映射到屏幕能现实的颜色区域内。这里介绍DirectX 9.0 SDK中所介绍的方法。假设Lumave(稍后介绍)为计算得到的原始图像平均亮度,那么对于原始图像中的任一像素点Lum(x,y),有下面的映射关系:

    其中,Lscaled为映射后的值,alpha为一个常数,alpha的大小决定了映射后场景的整体明暗程度,可以根据需要适当调整,这个值在以后的实现中称为Key值。经过这样的映射后,Lscaled并不一定处在(0,1)的范围中,我们再结合(1)式,使最终的像素值处在(0,1)上:

    这样就完成了最终的映射。 现在讨论如何计算原始图像的平均亮度。平均亮度的计算由下面的公式给出:

    上式中,δ是一个较小的常数,用于防止求对数的计算结果趋于负无穷的情况。如δ可取0.0001。这个式子的意义是,对于原始图像每个像素,计算出该像素的亮度值Lum(x,y),然后求出该亮度值的自然对数。接着对所有像素亮度值的对数求平均值,再求平均值的自

热门推荐 查看更多