| 2008年03月18日 21:48 | |
得益于近十年来硬件、内存密度和显示屏分辨率领域的飞速发展,计算机图形行业在视觉逼真度方面也取得了长足的进步。同时,计算机图形领域的研究人员也一直在探索视觉显示设备的动态范围,并试图充分利用显示屏有限的显示范围。采用高动态范围(HDR)图像的渲染算法是充分利用显示屏显示范围的方法之一。一旦可编程图形硬件得到广泛运用,游戏开发人员便可以在游戏引擎中充分发挥这些效果的优势。
本白皮书将论述 HDR 图像的捕获、存储和显示功能。显示和处理 HDR 图像的能力现今已广为应用,例如,在英特尔® 965 高速芯片组和移动式英特尔® 965 高速芯片组家族等主流电脑图形芯片组中便已具备上述功能。此外,本文还将介绍如何使用 HDR 图像来支持当前的浮点纹理格式。文中还展示了如何通过集成图形处理器,在采用 HDR 纹理的场景中实时实现环境映射对象。
图 1-1:采用高动态范围图像的色调映射
图 1-1 中的图像展示了采用 HDR 图像的色调映射的优势。我们对第一张图像进行了高光箝位处理,以期获得更好的显示效果。通过运用本文所述的色调映射操作,我们能够获得第二张图像所示的效果。请注意:第一张图像中亮度饱和的区域在第二张图像中清晰可见,尤其是窗外的区域。
本文首先介绍了与 HDR 图像相关的背景知识,阐述了 HDR 图像捕捉和显示的理论与算法,并重点讲解了 Erik Reinhard 的摄影色调再生算符。随后,作者在文中阐述了他们自己执行 HDR 环境映射的情况,其中包括英特尔® 965 高速芯片组和移动式英特尔® 965 高速芯片组家族上的浮点纹理支持,以及用于部署 HDR 色调映射的像素着色器(Pixel Shader) 2.0 的情况。图 1-1 所示图片便是他们所实现的效果之一。
2.1 图像采集流水线之旅
图 2-1:图像渲染流水线
图 2-1 描述的是从真实世界采集的光子映射进入 RGB 图像的路径。
图 2-1 描述的是一个由 [3] 产生的简化的图像采集流水线。经过透镜后,光子会穿过快门到达光敏感元件(通常为 CCD(电荷藕合器件))。快门用于控制光敏感元件累积光子的时量,透镜用于将进入的光子聚焦到光敏感元件上。到达光敏感元件后,光子会经过模拟数字转换器(ADC)转化为数字数值。这些数字数值将经过一些最终调整(视照相机制造商和照相机具体设置不同而有所差异),作为 RGB 值写入图像。
2.2 动态范围
图 2-2:自然光、感知光和可显示光的亮度范围
图 2-2 对我们所能体验到的光强范围与真实世界中的总光量进行了比较。自然可见光的绝对动态范围约为 10 个数量级 [5]。人类视觉系统能够看到大约 3 个以上的数量级变化,一个常见显示屏的动态范围大约在 2 个数量级左右 [19]。
在图 2-2 中,我们可以看到与可见光和 LCD 显示屏的动态范围相比,人类视觉系统的动态范围变化有些差异。人类视觉系统通过控制瞳孔、光感受器和神经元中的化学和神经过程来调整进入眼中的光量。摄影器件则通过采用镜头光圈和曝光时间来模拟这一行为。
然而,这样一来便永远丢失了镜头和曝光组合范围以外的其它信息,给日后这些图像的实时渲染工作带来了巨大的不便。因为只有能够感知到光,才能确保修正。换而言之,我们可能需要捕获一个场景中的全部动态范围里的所有信息,并且只有等到过后再决定选择丢弃哪些部分。正如我们将在本文中所展示的,使用 HDR 图像支持在源图像中存储更多光线的信息,因此可支持最终用户获得这些光信息并对它们进行运行时修正。
2.3 HDR 图像存储
我们应保存创建好的 HDR 图像,以便日后检索、处理和显示之用。[20] 归纳了 HDR 图像的不同存储格式。范例包括 Pixar 的 33 比特对数编码 TIFF(log encoded TIFF)、Radiance 的 32 位 RGBE 和 XYZE、IEEE 96 位 TIFF 和 Portable FloatMap 可携式点阵图格式、LogLuv TIFF 以及 ILM 的 48 位 OpenEXR 格式。在文件大小、动态范围和量化等方面,每种格式都各有优劣。我们提供的作品中使用的是 RGBE 文件格式和半精度浮点纹理。您最终所选择的格式将取决于您作品的内容和可用的工具。我们需要一种能够管理和操控 HDR 图像的工具。幸运的是,我们可以在网上找到这种工具:HDRShop。由于 HDRShop 可以导出 RGBE 文件,而 RGBE 文件拥有一个可接受的可显示范围,因此我们选择在我们的作品中使用该工具 [7]。另外,您还可以使用 HDRShop 2.0 版和 Photogenics [13] 等商业软件包。
3.1 对 HDR 图像的需求
一个图像由采样器件的每个像素的响应组成。光敏感元件在接近其最大输入值或最小输入值时具有最大误差。由于任何超过饱和点的值被映射到存储最大值,我们在给定的曝光时间内没有获得准确测量的到达像素的光量。因此,在很多情况下,如果不使用 HDR 图像技术,图像就无法准确取样和存储光强。不过,您可以变换曝光时间并拍摄一系列图像来弥补当前数码相机的功能缺陷。接着,您可以使用这些图像更精确地了解进入透镜、并被光敏感元件取样的光,以便将来作为 HDR 图像显示之用。
只要我们存储一套曝光时间各异的图像,便可以更轻松地将一个场景的真实亮度映射到我们可以使用的任何一台设备或应用限制的可显示范围中。电影业中的很多工作都要考虑该因素,即制作出的画面可与屏幕的可显示范围相匹配。
3.2 HDR 图像的使用
HDR 图像可用于在游戏引擎中实现对象环境映射。这样做的目的是基于当前硬件的功能,赋予用户更精准、更逼真的视觉体验。除了用于环境映射外,HDR 图像还可在渲染时用于进行运动模糊处理和模拟人类视觉系统的特征。例如,它们可在高亮度值不被箝位的情况下使用,并可用于展示景深效果 [11]、 [8]、[9]。
图 3-1:HDR 渲染样本
图 3-1 来自我们的“高动态范围环境映射”展示。我们在带有 16 位浮点纹理和 RGBE 图像的移动式英特尔® 965 高速芯片组显卡上,使用 DirectX 9.0 像素着色器 2.0 版* 来存储和渲染 HDR 环境映射。[1]
3.3 显示
到此,我们对 HDR 图像的采集、使用和存储已经全部描述完毕。下面,我们将重点讲述 HDR 图像的显示事宜。曾经有人对创建可以更精准地渲染 HDR 图像 [19] 的显示进行过研究。由于使用目前的图形技术能够支持浮点格式,因此我们需要研发一些技术,使存储在 HDR 纹理中的大亮度差异映射到可显示出此类差异的显示屏上。
鉴于当前硬件存在浮点纹理支持,无需“高动态范围纹理映射”([2] 中所述的 HDRTM 技术)即可保存亮度值。这样一来便无需使用 Alpha 通道临时存储 RGBE 亮度指数解码和编码 8 位色值,允许我们使用 16 位每 RGB 和 Alpha 通道格式,保留 A,pha 通道不用。
针对实时要求及可编程图形硬件的广为使用,作者选择实施 [17] 中所展示的色调映射技术(如图 3-1 演示中所示)。色调映射是指将真实世界亮度的 HDR 映射到显示设备的较低动态范围中。事实上,像素不能超过帧缓冲器中设定的最大值,因此为了执行色调映射,我们总是利用为每个像素应用一个箝位算符(clamp operator)的方法,将我们的显示器当作低通滤波器来使用。可是这样却使我们丧失了很多场景的更高亮度,因此我们理应采取一个更为巧妙的办法。安塞尔•亚当斯在摄影时也遇到过类似的问题。我们选择采用的一项技术,其灵感就来自于亚当斯的《分区曝光法》。直到现在,分区曝光法仍在模拟图像采集中广为采用。
如图 3-2 所示,一个区域是一个亮度值范围,其中底片的反射率也考虑在内。从纯黑色到纯白色一共有十一个底片区域,每个区域的强度依次增加一倍。每个区域用罗马数字表示,从 0* 区到 X 区。中灰值是模拟场景中的中等亮度区域,通常被映射到底片的 V 区上。摄影师会读取场景的中灰值,一般该值是引起底片上 18% 反射率的原因。如果场景色调暗,则该值也会处于底片区域范围中较低的分区。类似地,如果场景色调亮,则中灰值将处于底片区域的较高分区。
图 3-2:分区曝光亮度强度级
图 3-2 为安塞尔•亚当斯分区曝光法中所述的 11 个区域,每阶强度值从 0 到 255 呈指数级增长。IX 区和 Zone X 区均已饱和:我们只能制作密度值最大为 255 的图像,由于分区曝光中包含的有些值大于我们用传统的 8 位每像素图像可以表现的值,因此 X 区被箝位至 255。
‘0’不是罗马数字。事实上,罗马数字中不存在 0。
3.4 Reinhard 的摄影色调再生算符的算法
应用 Reinhard 色调再生算符的第一步是获取我们用于作为场景色调的平均亮度值。一般我们会采用简单平均法进行计算,但由于亮度值的分布呈指数曲线状,因此我们会采用对数平均亮度值或自然对数平均亮度值作为场景色调的近似值。要计算该值,我们首先应从下列 RGB 值中计算出亮度值:
等式 1
等式 1 使用了 [1] 中的亮度转换(基于现代 CRT 和 HDTV 荧光粉)。
接着,我们利用此值计算自然对数平均亮度值,求和得出整个图像的影调值:
等式 2
此处,像素数量是指图像中的像素总量。是一个小值,用来避免对亮度为零的全黑像素取对数。得到影调值后,我们可以将像素重新映射到新图像上对值进行分级,便于我们赋予更高范围的亮度值更大的动态分辨率。众所周知,18% 位于强度值 0-1 的对数阶的中间部位(V 区),我们采用下列比率公式:
等式 3
求解得出新亮度值:
等式 4
现在假定 V 区位于我们将要映射的范围的中部。对于影调值高于平均值的图像,提高中间调区亮度效果可能会更好。为此,我们总结出了下列公式:
等式 5
一般 midzone_luminance_value(中区亮度值)会在数量上有所不同,每一分区增加一倍:.045、.09、.18、.36、.72。
这里,我们还面临两个问题:第一个问题是,在太阳或窗口等光源下,只有少部分像素具有非常态的 HDR(大部分图像的动态范围正常)。等式 5 的前提是进行线性映射,但我们真正想做的是突出这些 HDR 区域的非线性映射。而第二个问题,则是等式 5 仍然能够生成显示屏上可显示的 0.0 - 1.0 范围以外的值。这样一来,我们需要最后校正一下我们的分级亮度值:
等式 6
注意:等式 6 在 0 和 1 之间对亮度值进行分级,按比例少量增加高亮度值,对低亮度值无影响,因为上限 1 决定了整个计算。这样做提高了高亮度区域的动态范围(如图 3-3 和图 3-4 所示)。
图 3-3:色调映射亮度级
图 3-2 中的图像已经色调映射修正。注意:从 0 到 X 的所有色调在图像中均可见,且在 255 强度值的可显示范围内。
图 3-4:色调映射对亮度的影响
图中列出了等式 1 到 6 中的色调映射算法前后的亮度值。此例代码请参见附录 A。关于影调值,我们选择 0.36。
等式 2、5 和 6 已足够作为目前的实时应用公式,使用它们得到的所有亮度值均在可显示范围内。不过结果并非总是尽如人意,我们有时反而希望使用这些公式计算出最高亮度范围内的某些值,我们可以采用下列不同的色调映射算符来实现:
等式 7
White_luminance(全白亮度值)是指映射到纯白区域上的最小亮度值。注意:如果 white_luminance 值较大,等式 7 的分子将趋于 0,我们应使用等式 6 进行计算;但是如果 white_luminance 值较小,则我们将获得较大的分子值,我们应提高较低动态范围像素。在我们的举例中,我们使用等式 6。
3.5 映射亮度至 RGB
下一步是获得最终 RGB 值,我们将最终的亮度值分别乘以每个原始 RGB 值,以计算出新像素 RGB 值。
3.6 转换
基于现有工具,获取 HDR 图像的过程比较简单。通过收集一套拍摄方位一样、曝光时间不同(通常依靠变换拍摄每个图像时的光圈系数)的传统照片,即可创建出 HDR 图像。创建 HDR 图像的一个方法是实施 [3] 中所示的算法,使用它可恢复照相机的响应功能,从而利用这一信息来构建 HDR 图像。此图像所拥有的像素值可表示场景中的真实辐射值。另外一个选择是使用 HDRShop,该工具支持操控一套标准相机拍摄的低分辨率图像,用于创建单一 HDR 图像 [7]。
对于众多关注射入辐射率的 HDR 图像娱乐应用而言,光探头是更适合的格式。光探头可通过在环境中安置镜面球、从两边拍摄来创建。这样做的结果是环境贴图的诞生:一套由空间中每一点的所有光线组成的光线样本(图像)在光探头中心交汇于一点。环境贴图随即会渲染成高分辨率球体贴图或立方体贴图,以便用于渲染流水线,以及用于接近横贯我们正在进行环境映射的对象的光线。
4.1 演示
本文包含
利用来自 Microsoft DirectX SDK 的 HDRFormat 演示,实施将 HDR 文件加载至半精度浮点纹理和进行影调值计算 [10]。此外,该演示还支持等式 5 中的 midzone_luminance(中区亮度值)(即演示中提及的 MIDDLE_GREY(中灰值))进行交互式调整,便于读者更好地了解中区亮度值对最终图像的影响。同时,我们还注意到单纯实施每个图像的色调映射算法都可能导致图像每帧色调发生显著变化。因此,我们限制各帧之间能够变化的 image_key 数量,防止图像发生显著变化,并允许图像经过几次迭代后“锁定”在正确的值不变。从美学角度看,最终图像更精确地反映了光照在光线发生显著变化的情形中所发挥的作用,效果十分令人满意。
4.2 RGBE 格式
RGBE 格式适用于存储实时图形中所使用的高动态图像,因此我们在实施过程中使用了该格式。RGBE 最初由 Greg Ward 创建,应用于其 Radiance 软件包 [15]。如图 4-1 所示,该格式包含面向每条红、绿、蓝通道的一个 8 位尾数,其中这三个通道均带有面向 32 位每像素的一个 8 位指数。由于它们共享指数,因此与 32 位每通道格式相比,它们所需的存储量大为减少(与 32 位每像素相比,32 位每浮点* 3 = 92 位每像素)。由于您在所有颜色通道间共享指数,导致各颜色通道间缺少动态分辨率,因此才会出现此情况。
图 4-1:32 位 RGBE 格式
图 4-1 展示的是面向红、绿、蓝通道的 8 位每通道和共享指数值,在我们的范例中用于表示 HDR 图像。共享指数通常位于图像中用作 alpha 通道的颜色通道中。
使用 RGBE 格式进行编解码操作也非常简单,因为使用 [21] 中的方法 RGBE_ReadPixels_RLE(…) 可自动返回 3 个 RGB 浮点值来调整共享指数。
4.3 高动态范围影调值计算
为免去经由总线传输图像计算影调值的麻烦,我们可以采用基于 [17] 中的亮度色调再生算符的范例中所含的 image_key 计算公式在 CPU 上计算影调。是否在 CPU 或 GPU 上计算影调,由应用程序、显卡和图形总线决定。
4.4 集成显卡中的像素着色器
我们还采用 HLSL 语言编写了像素着色器,用于支持在英特尔® 965 高速芯片组和移动式英特尔® 965 高速芯片组家族集成显卡上使用 HDR 图像进行环境映射。该芯片组家族经专门优化以支持 DirectX 9.0c,并采用了 DirectX 的英特尔架构优化平台特殊图形处理(PSGP Platform Specific Graphics Processing)顶点着色器 3.0* 和像素着色器 2.0*。先前阐述的像素着色器中的色调映射功能可将 RGBE 图像转换成浮点纹理。如欲获得完整的着色器源代码,请参阅演示中的效果文件。
4.5 Microsoft DirectX 9.0 SDK 中的 HDR 样本
微软在 DirectX SDK 中提供了一些实例,来演示上述技巧 [10]。此外他们还提供了一些实例来展示不同场景中的 HDR。HDRCubemap 是一个 HDR 光照和立方体环境映射演示,采用了浮点立方体纹理存储数值,其中用于表面光照的总光量大于 1.0。HDRFormats 阐述了一项在不能使用浮点纹理的硬件上显示 HDR 图像的技术。除了使用浮点纹理支持外,最显著的不同在于该样本不受 DDS 文件格式的束缚,因此可以使用采用 HDRShop 编码的任何 HDR 图像。HDRLighting 阐述了弱光下的蓝移、强照明条件下的 bloom 效果,以及照相机的曝光不足和曝光过度现象。
笔者认为,未来我们可在以下几个领域有所突破。其中之一便是将 OpenEXR 文件格式应用于存储和显示,以及使用能够充分利用该文件格式优势的编辑工具。尽管已经提供了一个用于读取和显示图像的 SDK,但迄今为止还没有一个公开可用的窗口导出程序。因此,我们正在考虑编写一个 HDRShop 插件。我们还希望试验其它色调映射操作。本文仅介绍了适用于当前图形硬件的一些技术,但有时由于所需效果的不同,使用其它技术可能更为适合。
最后,我们还计划进行每像素色调映射实验。[17] 论述了一项模拟摄影师使用减淡(dodge)和加深(burn)工具的技术。Dodge 和 burn 是指借助一张有洞的纸或小棍,添加或减少底片区域光照,以增加或限制曝光的一项常见操作。这就好比为每个像素选定一个色调值。由于我们需要一项快速的色调映射技术,因此我们选择不关注该算符本身。但是随着图形硬件执行速度的加快,每像素色调映射算符自然能够得以实时执行。此外,通过确定当时的色调,将其运用于每像素色调映射或我们在上文详述的平均亮度值算符,在亮度值区域运用色调映射,也是值得我们研究的另一个领域。
-
[Akenine-Moller02] Tomas Akenine-Moller 和 Erik Haines,《实时渲染(第二版)》,第 193 页,AK Peters 公司出版发行,2002 年。
-
[Debevec02] Paul Debevec,“基于图像的光照(Image-Based Lighting)”,《IEEE 计算机图学与应用(美)》。2002 年 3 月/4 月,第 26-34 页。
-
[Halsted93] Charles Halsted,《明度、亮度,混淆(Brightness, Luminance, and Confusion)》。Information Display 公司,1993 年。http://www.crompton.com/wa3dsp/light/lumin.html。
-
[HDRShop04] 制作、编辑和保存 HDR 图像的软件(Software for creating, editing, and saving HDR imagery)。http://www.ict.usc.edu/graphics/HDRShop/。2004 年 10 月 29 日。
-
[MSSDK04] 微软公司 DirectX 9.0 SDK 升级版(2004 年夏)。http://www.microsoft.com/downloads/search.aspx?displaylang=en&categoryid=2。2004 年 8 月。
-
[OpenEXR04] OpenEXR 网站:http://www.openexr.org/downloads.html。2004 年 8 月 19 日。
-
[Photogenics04] http://www.idruna.com/downloads.html。
-
[Probe04] “光探头图像展(Light Probe Image Gallery)”。http://athens.ict.usc.edu/Probes/。2004 年 9 月 8 日。
-
[Radiance04] http://radsite.lbl.gov/radiance/HOME.html。辐射成像系统。2004 年 8 月。
-
[Reinhard04] Erik Reinhard ,《个人电子邮件通讯(Personal Email Communication)》。2004 年 7 月 30 日。
-
[Shastry99] Anirudh S. Shastry,《高动态范围渲染》。http://www.gamedev.net/columns/hardcore/hdrrendering/。
-
[Walter04] Bruce Walter,《RGBE 文件格式》。http://www.graphics.cornell.edu/~bjw/rgbe.html。 2004 年。
//no warranties, expressed or implied, free for re-use
#include "stdafx.h"
#include "math.h"
#define N 11
#define delta 1.0f
#define MIDDLE_GRAY 0.36f
#define MAX_RGB 2048.0f
#define MAX_LUMINANCE ((0.2125f*MAX_RGB)+(0.7154*MAX_RGB)+(0.0721f*MAX_RGB))
// assume we have converted from RGB to luminance as described in the paper
float L[] ={ 0.0f, 1.0f, 3.0f, 7.0f, 15.0f, 31.0f, 63.0f, 127.0f, 255.0f,
511.0f, 1023.0f, 2047.0f};
/* L refers to Luminance, wanted to fit on a page */
float L_NormalizedFloats[N];
float scaled_L[N];
float final_L[N];
int final_pixel_vals[N];
void _tmain(int argc, _TCHAR* argv[])
{
float sum = 0.0f;
float log_avg_L = 0.0f;
float a = MIDDLE_GRAY;
for(int i=0;i<N;i++)
{
float max = 0.0f;
max = (float)MAX_LUMINANCE;
L_NormalizedFloats[i] = L[i]/max;
}
for(int i=0;i<N;i++)
{
sum += (float)log((double)(L_NormalizedFloats[i]+1.0f));
}
log_avg_L = (1.0f/((float)N));
log_avg_L *= exp(sum);
float weight = 0.0f;
weight = a/log_avg_L;
for(i=0;i<N;i++)
{
scaled_L[i] = (weight*L[i]);
}
for(i=0;i<N;i++)
{
final_L[i] = scaled_L[i]/(1.0f+scaled_L[i]);
int intL = (int)(final_L[i]*255.0f);
printf("[%d] = %f %d\n",i,final_L[i]*255.0f, intL);
}
}
[1] St. Peter 的光探头图像。版权所有 © 1999 Paul Debevec。未经许可,不得擅用。

