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的代碼如下:
1 // Determine what the pixel's value will be after tone mapping occurs 2 vSample.rgb *= g_fMiddleGray/(fAdaptedLum + 0.001f); 3 4 // Subtract out dark pixels 5 vSample.rgb -= BRIGHT_PASS_THRESHOLD; 6 7 // Clamp to 0 8 vSample = max(vSample, 0.0f); 9 10 // Map the resulting value into the 0 to 1 range. Higher values for 11 // BRIGHT_PASS_OFFSET will isolate lights from illuminated scene 12 // objects. 13 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