天天看點

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個部分。

首先将場景渲染到一個高精度高範圍的紋理(也就是HDR)中,這樣我們能真實的記錄場景的顔色和亮度。但這個紋理拿去顯示同樣和LDR一樣,因為顯示器把超出1的部分截斷,是以即使你有完整的資料也别想着可以顯示出來。我們還需要把HDR紋理轉換到LDR紋理中。

我們将得到的場景的HDR圖進行亮度求值,我們使用Down Samples(降低樣本,也就是大圖檔平均到小圖檔)方法求出整個場景的平均亮度,和最大亮度。我們同樣采用Down Samples的方法是為了減小計算量,因為我們要進行很多次顔色填充,是以填充量讓程式很吃力,為了減少計算負擔,經常采用Down Samples的方法。首先我們采用rgb中最大的分量表示該色素的亮度。我們計算平均亮度是使用幾何平均的方法。也就是說使用不是使用n個樣本相加再除以個數的方法,而是采用n的樣本亮度相乘然後開n方根。幾何平均亮度也可以采用log平均方法,這兩種幾何平均方法是等價的。

我們需要從場景出截出比較亮的區域。首先我們設定一個較亮區域的亮度門限值,如0.8。我們将HDR圖檔Down Sample并截出較亮的區域。并進一步進行Down Samples。然後采用高斯模糊方法(一種經常用于圖檔模糊化的模糊方法)對圖檔進行模糊化,這樣将能讓較亮區域感染其鄰近區域。得模糊後的圖檔,Bloom圖檔。

我們得到這些基本部件後,就可以進行我們最關鍵的一步,将HDR映射到LDR。首先是作者采用标準Bilinear對Bloom圖檔進行取值,其實一般不必這麼做,因為現在絕大多數顯示卡已經完全硬體支援Bilinear了。然後把取得的這些顔色添加到HDR中顔色中,得到新的HDR顔色。然後用新的HDR顔色映射到LDR。首先求出新的HDR顔色的亮度值,然後用該亮度除以先前求出的平均亮度得到解調後的新亮度。調節後的新亮度需要再次調節,這樣非常亮的地方才能不至于丢失。有兩種方法。如下圖中的兩個公式。其中L(x,y)是講過調節的亮度值。Ld(x,y)是最後的亮度值。第一個公式是最簡單的,第一個公式可以讓較亮的區域縮放大約1/L(x,

y)。而讓較暗的區域幾乎沒有改變。第一個公式保證HDR映射到LDR的範圍中。但較亮的區域會讓細節難以辨識。第二個公式克服了這個問題。其中的L(White)是圖檔中的最大亮度。

HDRPipeline DX9

最後我要說一下我的經驗,在這次學習和程式設計中重新認識了下MS系統中光栅化和紋理讀取的沖突。

如果想用頂點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)

進行DownSample的時候,偶數采樣和奇數采樣有差别。如果偶數降采樣。也就是如2x2區域降采樣到一個像素。第一個偏移量為0.5。而奇數采樣第一個偏移量為1.因為偶數采樣的時候采樣點在方格角落處,而奇數采樣中采樣點在方格中心。如下圖,如果采用經驗1的方法,那麼我們看看将2x2降采樣到1個像素是怎麼的情況。

HDRPipeline DX9
HDRPipeline DX9
下一篇: ShadowMap DX9