高动态范围光照(High Dynamic Range Imaging,简称HDRI或HDR)
1 HDR基本概念
高动态范围光照(High Dynamic Range Imaging,简称HDRI或HDR),是一种表达超过了显示器所能表现的亮度范围的图像映射技术,已成为目前游戏应用不可或缺的一部分。通常,显示器能够显示R、G、B分量在[0, 255]之间的像素值。而256个不同的亮度级别显然不能表示自然界中光线的亮度情况。比如,太阳的亮度可能是一个白炽灯亮度的几千倍,是一个被白炽灯照亮的桌面的亮度的几十万倍,这远远超出了显示器的亮度表示能力。
想象在一个房间中,刺眼的阳光从窗外照进来,若使用常规方法渲染这个房间,房间中白色的墙壁的颜色是(255, 255, 255),阳光的颜色也是(255, 255, 255),墙壁将表现得和窗外的阳光颜色一样。很明显,这和我们现实看到的差异很大,现实场景中阳光要比墙壁刺眼很多,我们需要使用某种技术对阳光的亮度和墙壁的亮度进行处理,让其在显示器上的效果接近现实效果。
简单的将高范围的亮度按比例缩放后映射到[0, 255]是不可行的,比如将[0, 511]的范围按照2:1映射到[0, 255],虽然表示的亮度范围扩大了,但是将导致色带(Color Banding)问题,色带如图1所示。
图1 左图有色带问题,右图显示正常
在有限的亮度范围内显示自然界中相当宽广的亮度范围,正是HDR技术所要解决的问题。
2 HDR渲染步骤
1)将整个场景渲染到一张浮点纹理上(16bit或32bit都可以);
2)色调映射(Tone Mapping);
3)渲染泛光(Bloom)效果;
4)将泛光和色调映射的结果进行叠加。
第一步很简单,只需要硬件支持浮点纹理即可,比较重要的是本文重点介绍的2、3两步,最后将2、3两步的结果进行叠加,形成最终效果图。
【显示设备上[0, 255]的亮度范围在着色器程序中使用[0, 1]的浮点数表示,下文的亮度和颜色值表示均使用着色器程序的标准。在算法中都用到了亮度的计算,每个像素的亮度的计算方法是L=0.27R+0.62G+0.06B】
3 色调映射
色调映射是在有限动态范围媒介上近似显示高动态范围图像的技术。对于人眼来说也有类似的映射方式,因为人眼对亮度的感知范围远低于自然界的亮度范围,只能感知到某个范围内的光照。和显示设备不同的是,人眼对光的感知范围是动态变化的,例如从光亮的室外环境突然走入一个黑暗的室内环境,刚刚开始一片漆黑,过一会儿才可以看清周围环境,人眼的这个调节过程叫做光适应(Light Adaptation)。所以要模拟出真实的光照效果,除了表现出合适的光照,还需要模拟出人眼对光线的调节过程。
最简单的色调映射是将亮度超过1的值置为1,这种做法会出现文章开始提到的墙壁和阳光一样亮的问题;另一种简单的色调映射是将每个像素的除以最高亮度像素的亮度值,可以很好的将所有像素的亮度映射到[0, 1]之间,这种方法会导致场景中某些特别亮的像素会导致场景中的其他部分特别暗。比较好的方式是采用平均亮度值进行调节,由于平均亮度值反映了场景中的整体亮度,所以受到场景中少部分过亮或过暗的像素影响不大。
3.1 计算平均亮度
计算平均亮度的公式为:
该公式先对亮度取对数,平均后再进行幂运算。之所以不是直接对亮度平均,而是取了对数,是为了防止过亮的像素对整体造成的影响过大,该公式来源于参考文献1。
计算平均亮度的最简单的方法是遍历所有像素,用上述公式求平均值。该方法需要CPU完成,效率不高,DirectX的“HDRLighting”例子采用了一种基于GPU加速的方法,利用像素着色器多次DownSampling,最后求得平均值,具体流程如下:
1)首先将场景渲染到纹理中,在此基础上,对该纹理取样并计算相应像素亮度的ln()值并进行平均(相当于上述公式去掉exp),存入64*64的纹理中;
2)对上一步的纹理4*4 DownSampling,生成16*16的纹理;
3)对上一步的纹理4*4 DownSampling,生成4*4的纹理;
4)对上一步的纹理4*4 DownSampling,生成1*1的纹理,并计算其exp()值。
最后生成的1*1的纹理中的像素为公式中要求的平均亮度Lavg。
3.2 光适应
为了模拟人眼对于不同光强会自动调节适应范围的效果,只需要对这一帧求出的平均亮度Lavg与上一帧的平均亮度Lavg进行插值即可,当然这个插值不是线性插值,“HDRLighting”中的代码如下:
float fNewAdaptation = fAdaptedLum + (fCurrentLum - fAdaptedLum) * ( 1 - pow( 0.98f, 30 * g_fElapsedTime ) );
其中,fAdaptedLum为上一帧的Lavg,fCurrentLum为当前帧的Lavg,g_fElapsedTime为当前帧和上一帧的时间间隔,fNewAdaptation为最终Lavg的计算结果。
3.3 计算缩放因子
场景的整体亮度可以通过缩放因子进行调节,公式如下:
其中Lscale(x,y)是当前像素的亮度值。Key是一个常数,Key 的大小决定了映射后场景的整体明暗程度,一般取0.18(在伽马校正理论中,0.18经过校正后大概是0.5,也就是我们感官上的中等灰度级)。Key值的选择可以看作摄像机的曝光程度,我们可以使用这个公式控制自由的摄像机的曝光程度,Key越大整个场景就显得越白。一般来说,高曝光的Key最高为0.72,低曝光的Key最低为0.045,一般程度的曝光Key选择0.18附近的值。
3.4 归一化处理
到此为止,色调映射已经基本完成,剩下的只需要将Lscale(x,y)映射到[0, 1]范围内即可,公式如下:
其中其中Color(x,y)是当前像素的颜色值。
4 渲染泛光效果
泛光是一种光学效应,它是指在来自于强光源的光线看起来像是影响到了周围物体。想象一间房间,窗户外面阳光明媚,若往窗外看去,感觉窗户光亮的边缘有一圈模糊,这就是泛光效果。在游戏中适当的增加泛光效果,能够增强画面的真实感。
渲染泛光效果的思路很简单,主要分为两个步骤,第一步是使用bright-pass filter提取出场景中高亮部分,第二步对高亮部分进行模糊处理。"HDRLighting"中bright-pass filter的代码如下:
// Determine what the pixel's value will be after tone mapping occurs
vSample.rgb *= g_fMiddleGray/(fAdaptedLum + 0.001f); // Subtract out dark pixels
vSample.rgb -= BRIGHT_PASS_THRESHOLD; // Clamp to 0
vSample = max(vSample, 0.0f); // Map the resulting value into the 0 to 1 range. Higher values for
// BRIGHT_PASS_OFFSET will isolate lights from illuminated scene
// objects.
vSample.rgb /= (BRIGHT_PASS_OFFSET+vSample);
第二步则是对第一步的结果进行模糊,首先对第一步的结果进行2*2或4*4的downsampling,再使用2*2的高斯核心对其进行模糊。其中先对图像downsampling再模糊的做法是利用GPU进行图像模糊的一种提高性能的方法,因为downsampling后图像分辨率降低了,计算量自然就少了;而downsampling后的图片再放大,本身又是一种模糊,可以减少高斯模糊的采样数量。最终效果如图2所示
图2 图片来源于微软DirectX SDK中“HDRLighting”例子,左图为过度曝光的场景,中间图片为bright-pass filter处理后的结果,右图为模糊之后的效果
5 融合
现在需要将色调映射的图像与泛光的图像进行融合。在融合操作中除了常见的α融合外,还有一种叠加(Additive Blending)操作,它可以将两种颜色的值进行加法操作,通常会使得颜色越变越白,这正是我们所要的效果。将色调映射的图像与泛光的图像进行叠加操作,即可生成最终图像。
6、最终效果
“HDRLighting”中LDR和HDR的效果对比如图3所示。
图3 “HDRLighting”中LDR和HDR的效果对比,左图为LDR,右图为HDR
其他的一些HDR渲染效果如图4-7所示。图4中很明显的观察到汽车窗户的镜面光,图5中蓝色的灯光显得比较亮,但是暗的地方也很清晰;图6和图7来自游戏“孤岛危机”,效果相当不错,其中就有HDR的功劳(当然要做到这样的画质,HDR只是冰山一角)。图6场景明暗得当,透过树叶可以看到天空略微模糊;图7中可以看到爆炸产生的碎片以及车上的显示屏有泛光效果,充分体现了亮度的差别,而这些细节让游戏更加逼真。
图4 Unity3D文档中的HDR渲染效果图1
图5 Unity3D文档中的HDR渲染效果图2
图6 “孤岛危机”截图1
图7 “孤岛危机”截图2
参考文献:
[1]Reinhard, Erik, Mike Stark, Peter Shirley, and James Ferwerda. "Photographic Tone Reproduction for Digital Images". ACM Transactions on Graphics (TOG), Proceedings of the 29th Annual Conference on Computer Graphics and Interactive Techniques (SIGGRAPH), pp. 267-276. New York, NY: ACM Press, 2002.
[2]Akenine-Möller T, Haines E, Hoffman N. Real-time rendering 3 [M].
[3]DirectX 9.0c SDK
[5]http://wenku.baidu.com/view/fe31607ea26925c52cc5bf97.html
[6]http://www.zwqxin.com/archives/shaderglsl/review-high-dynamic-range.html
[7]http://zh.wikipedia.org/wiki/%E9%AB%98%E5%8A%A8%E6%80%81%E8%8C%83%E5%9B%B4%E6%88%90%E5%83%8F
高动态范围光照(High Dynamic Range Imaging,简称HDRI或HDR)的更多相关文章
- paper 73 :HDR(High Dynamic Range Imaging)在摄影中指高动态范围成像
HDR(High Dynamic Range Imaging)在摄影中指高动态范围成像.国内的教程基本语焉不详,找到一篇比较详尽的国外教程翻译出来,希望对大家有帮助.^_^ 原文地址:http://p ...
- 高动态范围(High-Dynamic Range,简称HDR)
高动态范围(High-Dynamic Range,简称HDR) 一.HDR介绍 高动态范围(High-Dynamic Range,简称HDR),又称宽动态范围技术,是在非常强烈的对比下让摄像机看到影像 ...
- paper 72 :高动态范围(HDR)图像 HDR (High Dynamic Range)
In standard rendering, the red, green and blue values for a pixel are each represented by a fraction ...
- Unity Lighting - High Dynamic Range (HDR) 高动态范围(五)
High Dynamic Range (HDR) 高动态范围 As well as Color Space, the ‘dynamic range’ of your camera needs to ...
- HDR(High Dynamic Range) - 高动态范围
1. Dynamic Range 动态范围是指一个场景的最亮和最暗部分之间的相对比值 2. Tone-mapping 现实真正存在的亮度差,即最亮的物体亮度和最暗的物体亮度之比为 , 而人类的眼睛 ...
- Dynamic range compression
这段时间终于把手头的东西都搞完了,还剩下一个AEC这个模块,这个模块跟整个系统机制有很大关系,单独的模块意义不大. 另外,刚写完一个分类器,希望能大幅提升音乐流派分类的准确率. 下周正式开搞AEC,把 ...
- 动态规划算法(Dynamic Programming,简称 DP)
动态规划算法(Dynamic Programming,简称 DP) 浅谈动态规划 动态规划算法(Dynamic Programming,简称 DP)似乎是一种很高深莫测的算法,你会在一些面试或算法书籍 ...
- Unity3D所使用的第三方工具
前言 最近在研究Unity3D的结构和原理.关于Unity3D怎么用之类的教程在网上一找一大堆,想看教程之类的就不用看这篇文章了.我想做的是从使用Unity3D所看到的表象(表),摸透其设计原则和组织 ...
- 基于Fast Bilateral Filtering 算法的 High-Dynamic Range(HDR) 图像显示技术。
一.引言 本人初次接触HDR方面的知识,有描述不正确的地方烦请见谅. 为方便文章描述,引用部分百度中的文章对HDR图像进行简单的描述. 高动态范围图像(High-Dynamic Range,简称HDR ...
随机推荐
- https抓包判断证书问题
openssl s_client -connect 61.135.250.130:443这个是reg.163.com的 tcpdump 也可
- button轮番点击,只点击一次,鼠标hover
<!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml"><head><meta ...
- Ajax返回html和json格式数据
Ajax可以返回text和xml格式 可以用Ajax返回大段的html文本和json格式的字符串,然后用eval()方法 转化为json对象 php中的json编码:json_encode(); ph ...
- 使用ptrace向已运行进程中注入.so并执行相关函数
这个总结的很好,从前一个项目也用到这中技术 转自:http://blog.csdn.net/myarrow/article/details/9630377 1. 简介 使用ptrace向已运行进程中注 ...
- 第三十六篇、webService
在很多的情况下,我们会常常遇到webservive写的接口,往往这种情况下,我们就需要拼接一段报文去与服务器对接 首先要明白webService的工作原理,,,(http://www.cnblogs. ...
- Ajax和JSON基础
Ajax (核心是XMLHttpRequest对象) 1.XMLHttpRequest对象: request=new XMLHttpRequest() 支持Firefox opera Safari ...
- Android Studio生成APK自动追加版本号
转载说明 本篇文章可能已经更新,最新文章请转:http://www.sollyu.com/android-apk-studio-generated-automatically-appends-a-ve ...
- 基数排序(RadixSort)
1 基数排序的特点是研究多个关键字key,且多个key之间有权重之分, 或者可把单个key建模为含有多个key的排序 而计数排序.桶排序始终只有个一个key,或者说围绕着一个比较规则 Ex:比较 ...
- OpenCV和Matplotlib色彩空间模式不一致的问题
当用OpenCV读取彩色图像时,OpenCV是以(BGR)的顺序存储图像数据的,而Matplotlib是以(RGB)的顺序显示图像的. 可以用下面的程序来证明这一点 import cv2 import ...
- java.util.HashSet源码分析
public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java. ...