1. 程式人生 > >OpenGL——理解HDR與Bloom

OpenGL——理解HDR與Bloom

學習資料連結

https://learnopengl-cn.github.io/05%20Advanced%20Lighting/06%20HDR/

https://learnopengl-cn.github.io/05%20Advanced%20Lighting/07%20Bloom/

HDR

一句話定義HDR:HDR是一個後期效果 一句話描述HDR:先渲染其他模型,並且過度曝光之,然後寫入幀緩衝,然後通過HDR Shader進行修正。當然,Unity裡面,後期是通過取出GPU中的資料,然後CPU裡面計算,在寫回GPU的方式,所以比較耗啦。 一句話說明HDR的目的:為了能夠正確的顯示那些亮度明顯應該超過1.0的顏色的細節。 [1.1]小結:何時需要
FrameBuffer
後期處理通常需要以下要求之一(才顯得有必要): (1)需要知道相鄰其他畫素的資料,這是正常渲染所不能提供的。 (2)需要擴充套件資料位,比如HDR需要擴充套件顏色範圍,使之超過1。 [1.2]高動態範圍與Tone Mapping 光照方程中,顏色值大於1是沒錯的,只是無法被顯示出來而已。通過使片段的顏色超過1.0,我們有了一個更大的顏色範圍,這也被稱作 HDR(High Dynamic Range, 高動態範圍)。轉換HDR值到(LDRLow Dynamic Range,低動態範圍)值得過程叫做色調對映(Tone Mapping), [1.3]實現步驟 實際操作步驟簡述: 1使用更大Size的FrameBuffer,為顏色提供更大的範圍(顏色值超過1.0) 2在FrameBuffer中進行後期處理,使用函式進行色調對映(tone mapping) Reinhard公式: finalcolor = hdrColor / (hdrColor + vec3(1.0) 曝光引數公式: finalcolor = vec3(1.0) - exp(-hdrColor * exposure); 高曝光值會使黑暗部分顯示更多的細節,然而低曝光值會顯著減少黑暗區域的細節,但允許我們看到更多明亮區域的細節。也有一些技巧被稱作自動曝光調整(Automatic Exposure Adjustment)或者叫人眼適應(Eye Adaptation)技術,它能夠檢測前一幀場景的亮度並且緩慢調整曝光引數模仿人眼使得場景在黑暗區域逐漸變亮或者在明亮區域逐漸變暗。 e exp 0 = 1,e exp x(x<0) HdrColor越大,光強越強,exp(-HdrColor*exposure)的結果值越小。

Bloom

Bloom和HDR並沒有必須與否的關係,但是由於HDR提供了更大的顏色範圍,Bloom的效果將更精準,顏色值在[0,1],很多非發光體,也會被模糊化,模糊的閾值很難界定。 Bloom的原理是,將高亮部分提取出來做高斯模糊,然後在寫回FrameBuffer。 具體操作略微複雜,步驟如下:
(1)準備一個FrameBuffer,繫結兩個ColorBuffer。在一個FragmentShader裡面,同時寫入兩個ColorBuffer。 一個寫入基礎片段資訊(Fragment ColorBuffer) 另一個只寫入高亮部分資訊(Bloom ColorBuffer),寫入高亮資訊時需要一個顏色過濾器。 (2)另外準備兩個FrameBuffer A(Horizontal)和B(Vertical),用作二次高斯運算。也就是先做水平高斯計算,在做垂直高斯計算,並且重複迭代這個過程,直到N次,N越大,模糊效果明顯。 第一次將BloomFrameBuff寫入FrameBufferA,這之後就在AB之前乒乓交換進行模糊值計算。 反覆N次。 最後將兩個FrameBuffer的片段的顏色值相加相加之後再通過Tone Mapping,將顏色值,根據一定的曝光度,對映到LDR顏色範圍內。HDR+Bloom的後期特效就完成了!
其他問題
兩個值得稱道的地方 第一個問題是:用作過濾高亮顏色的Filter
//float brightness = dot(result, vec3(0.7152,0.2126,  0.0722));
	float brightness = dot(result, vec3(0.333, 0.333, 0.333));
    if(brightness > 1.0)
        BrightColor = vec4(result, 1.0);
    else
        BrightColor = vec4(0.0, 0.0, 0.0, 1.0);

第一個傾向於讓紅色產生Bloom 第二個對於各種顏色的Bloom是均等的,但是要求亮度大於3才會產生Bloom 第二個問題是GaussBlur的Weight陣列
uniform float weight[5] = float[] (0.2270270270, 0.1945945946, 0.1216216216, 0.0540540541, 0.0162162162);
參考:
    if(horizontal)
     {
         for(int i = 1; i < 5; ++i)
         {
            result += texture(image, TexCoords + vec2(tex_offset.x * i, 0.0)).rgb * weight[i];
            result += texture(image, TexCoords - vec2(tex_offset.x * i, 0.0)).rgb * weight[i];
         }
     }......
為了顏色的亮度守恆,需要保證:[0] + 2[1]+2[2]+2[3]+2[4] = 1.0f