本文同時發(fā)布在我的個人博客上:https://dragon_boy.gitee.io
??默認(rèn)情況下澈圈,存儲在幀緩沖的亮度和顏色值的范圍被限制在[0,1]支鸡。這種范圍在一般情況下可行敏晤,但如果場景中的片段的亮度本身超過1我們依舊把它限制在1以內(nèi)的話,場景的亮度或顏色就不太正常了,下面是一個例子:
??因為大量超過1.0亮度或顏色的片段的亮度或顏色被限制在[0,1]以內(nèi)磕昼,這些片段就會有完全相同的顏色服傍,這樣就會出現(xiàn)大片區(qū)域的顏色一樣钱雷,場景的細(xì)節(jié)也就丟失了。
??解決這一問題的方式是允許顏色值暫時超過[0,1]的范圍吹零,在最后的步驟中再將顏色轉(zhuǎn)化到[0,1]的范圍罩抗。
??顯示器的顏色顯示被限制在[0,1]范圍內(nèi),但光照計算時沒有這種限制灿椅。通過允許片段的顏色超過1.0套蒂,我們可以在更高的顏色范圍內(nèi)工作,這種方式稱為高動態(tài)范圍(HDR)茫蛹。通過使用這個高動態(tài)范圍操刀,亮的地方會保持亮,暗的地方會保持暗婴洼,二者的細(xì)節(jié)都不會丟失骨坑。
??HDR最初只是讓攝影師拍攝的技術(shù),可以通過調(diào)整曝光度拍攝同一場景獲得多張照片窃蹋,來獲取大范圍的顏色區(qū)域卡啰。將這些照片組合起來形成一張HDR圖片,在組合的曝光度上顯示大范圍的顏色細(xì)節(jié)警没,或者使用一個特別的曝光度來觀察匈辱。舉個例子,下面的三張照片中杀迹,左側(cè)的照片在低曝光度下亡脸,窗戶的細(xì)節(jié)比較豐富,中間的照片提高曝光度后,窗戶的細(xì)節(jié)就丟失了浅碾,但室內(nèi)的場景可以看的比較清楚大州,但細(xì)節(jié)不是很豐富,進(jìn)一步提升曝光度后垂谢,第三張照片的窗戶的細(xì)節(jié)徹底沒有了厦画,但室內(nèi)的細(xì)節(jié)反而更豐富了。
??上面的例子和人類的眼睛的工作原理很相似滥朱,也和高動態(tài)范圍渲染的原理很相似根暑。當(dāng)光照很弱時,人的眼睛適應(yīng)這一光照徙邻,暗處就會看的比較清晰排嫌,光照很強(qiáng)時同理$掷纾可以說人的眼睛可以根據(jù)場景的亮度自動調(diào)節(jié)曝光度淳地。
??HDR的工作原理和人的眼睛有一些像,我們允許渲染時使用大范圍內(nèi)的顏色值帅容,收集大范圍的暗處和亮處細(xì)節(jié)颇象,最后我們將所有HDR值轉(zhuǎn)化到低動態(tài)范圍(LDR),即[0.0,1.0]。這一將HDR轉(zhuǎn)化到LDR的過程稱為色調(diào)映射丰嘉,針對這一過程目前存在大量的算法來保證HDR的細(xì)節(jié)能夠傳遞至LDR夯到,這些算法也大都將曝光度作為參數(shù)來有選擇地影響亮處和暗處。
??在實時渲染中饮亏,高動態(tài)范圍不僅允許我們超過LDR的范圍耍贾,保留更多的細(xì)節(jié),也讓我們有能力去通過真實的亮度去調(diào)整光源的亮度路幸。例如荐开,太陽的亮度遠(yuǎn)高于手電筒的亮度,所以我們可以調(diào)整太陽的亮度(比如漫反射亮度值為100.0)简肴,這允許我們通過真實的參數(shù)去更為合適的調(diào)整場景的光照晃听。
??因為非HDR顯示器只顯示LDR范圍的顏色,所以我們需要將HDR的范圍調(diào)整回LDR砰识,但簡單的轉(zhuǎn)化會丟失很多的細(xì)節(jié)能扒,這樣就要用到我們之前說的色調(diào)映射。
??為了能夠使用HDR渲染辫狼,我們需要一些方法來保證顏色值不會再片段著色器渲染時被限制到[0,1]內(nèi)初斑。當(dāng)轉(zhuǎn)換沖使用類似GL_RGB的配置作為顏色緩沖類型時,OpenGL會自動進(jìn)行范圍限制膨处,然后才會將顏色存儲在幀緩沖中见秤。這一操作對大多數(shù)幀緩沖的附加項類型都是用砂竖,除了浮點格式。
??當(dāng)幀緩沖的顏色緩沖類型被配置為GL_RGB16F,GL_RGBA16F,GL_RGB32F或GL_RGBA32F時鹃答,幀緩沖就被稱為浮點型幀緩沖乎澄,可以存儲超出[0,1]范圍的浮點值,這對HDR來說非常適用测摔。
??創(chuàng)建浮點幀緩沖置济,我們只需要將其顏色緩沖附加項的格式進(jìn)行修改:
glBindTexture(GL_TEXTURE_2D, colorBuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, SCR_WIDTH, SCR_HEIGHT, 0, GL_RGBA, GL_FLOAT, NULL);
??接下來將這個顏色緩沖附加到幀緩沖上后,我們使用這個幀緩沖渲染避咆,場景中的顏色值不會被限制在[0,1]內(nèi)舟肉。渲染時我們首先將場景渲染至幀緩沖中,接著將其顏色緩沖顯示在屏幕平面上:
glBindFramebuffer(GL_FRAMEBUFFER, hdrFBO);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// [...] render (lit) scene
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// now render hdr colorbuffer to 2D screen-filling quad with tone mapping shader
hdrShader.use();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, hdrColorBufferTexture);
RenderQuad();
??針對設(shè)個場景查库,我們創(chuàng)建一個長立方體來作為通道,并設(shè)置4個點光源黄琼,其中一個在通道的盡頭樊销,亮度非常大:
std::vector<glm::vec3> lightColors;
lightColors.push_back(glm::vec3(200.0f, 200.0f, 200.0f));
lightColors.push_back(glm::vec3(0.1f, 0.0f, 0.0f));
lightColors.push_back(glm::vec3(0.0f, 0.0f, 0.2f));
lightColors.push_back(glm::vec3(0.0f, 0.1f, 0.0f));
??最后顯示在屏幕上時,我們定義一個簡單的著色器程序來顯示幀緩沖的顏色緩沖:
#version 330 core
out vec4 FragColor;
in vec2 TexCoords;
uniform sampler2D hdrBuffer;
void main()
{
vec3 hdrColor = texture(hdrBuffer, TexCoords).rgb;
FragColor = vec4(hdrColor, 1.0);
}
??不過這么直接轉(zhuǎn)換脏款,在片元著色器器運(yùn)行后围苫,顏色值還是會被限制在[0.0, 1.0]內(nèi),但我們實際的顏色應(yīng)該有的超過這個范圍撤师。
??所以說為了保留HDR的細(xì)節(jié)剂府,我們在片元著色器中實現(xiàn)色調(diào)映射算法。
色調(diào)映射
??色調(diào)映射算法將HDR的范圍的顏色值映射為LDR的范圍剃盾,但不丟失太多的細(xì)節(jié)腺占。
??有一種使用最多的是萊因哈特色調(diào)映射,它均衡的將向LDR范圍映射所有的亮度值痒谴,下面我們調(diào)整之前的片元著色器衰伯,并使用伽馬矯正來做一些顏色調(diào)整。
void main()
{
const float gamma = 2.2;
vec3 hdrColor = texture(hdrBuffer, TexCoords).rgb;
// reinhard tone mapping
vec3 mapped = hdrColor / (hdrColor + vec3(1.0));
// gamma correction
mapped = pow(mapped, vec3(1.0 / gamma));
FragColor = vec4(mapped, 1.0);
}
??這樣的話积蔚,場景中亮度過高的地方我們就看得清了:
??我們還可以使用不同的曝光度來進(jìn)行色調(diào)映射意鲸,之前提到過,在亮度太高的地方使用低曝光度尽爆,在較暗的地方使用高曝光度怎顾,下面是使用曝光度色調(diào)映射的一個例子:
uniform float exposure;
void main()
{
const float gamma = 2.2;
vec3 hdrColor = texture(hdrBuffer, TexCoords).rgb;
// Exposure tone mapping
vec3 mapped = vec3(1.0) - exp(-hdrColor * exposure);
// Gamma correction
mapped = pow(mapped, vec3(1.0 / gamma));
FragColor = vec4(mapped, 1.0);
}
??這樣,我們可以通過調(diào)整曝光度來獲得不同的映射效果漱贱,來適應(yīng)不同亮度的場景槐雾,下面是幾個例子:
??這里給出原文代碼參考:Code。
其它的HDR技術(shù)
??這里介紹的萊因哈特色調(diào)映射和曝光度色調(diào)映射只是色調(diào)映射技術(shù)的冰山一角饱亿,我們可以在網(wǎng)絡(luò)上查到更多的色調(diào)映射方式蚜退。還有一種HDR技術(shù)類別是自動曝光度調(diào)整或人眼適應(yīng)技術(shù)闰靴,顧名思義,可以根據(jù)場景的亮度自動調(diào)節(jié)曝光度來保留暗處或亮處的細(xì)節(jié)钻注。
??最后蚂且,貼出原文地址供參考:https://learnopengl.com/Advanced-Lighting/HDR