OpenGL學(xué)習(xí)25——抗鋸齒化

抗鋸齒化(Anti Aliasing)

  • 鋸齒形邊緣(jagged edges) 出現(xiàn)的原因取決于光柵化時(shí)如何將頂點(diǎn)數(shù)據(jù)轉(zhuǎn)換為實(shí)際片元沮榜。
  • 最早,有一種叫做超分辨率抗鋸齒化(super sample anti-aliasing, SSAA) 的技術(shù)喻粹,它使用一個(gè)更高分辨率的渲染緩沖區(qū)來(lái)渲染場(chǎng)景蟆融,然后當(dāng)整個(gè)場(chǎng)景渲染完成時(shí)再通過(guò)降采樣將分辨率恢復(fù)正常。因?yàn)檫@項(xiàng)技術(shù)在性能上有重大缺點(diǎn)守呜,因此也只應(yīng)用一時(shí)型酥。
  • 從SSAA技術(shù)發(fā)展了更現(xiàn)代的抗鋸齒化技術(shù):多重采樣抗鋸齒化(multisample anti-aliasing, MSAA)山憨,它借用了SSAA的一些概念但以更高效的方式實(shí)現(xiàn)。本章節(jié)重點(diǎn)介紹OpenGL內(nèi)置的MSAA技術(shù)冕末。

1. 多重采樣

  • 想要了解多重采樣和它如何解決鋸齒化問(wèn)題萍歉,我們需要更深入的了解OpenGL的光柵化程序(rasterizer)。光柵化程序接收單個(gè)基元的頂點(diǎn)數(shù)據(jù)將其轉(zhuǎn)換為片元集合档桃。頂點(diǎn)坐標(biāo)理論上可以是任何坐標(biāo)枪孩,但是由于顯示屏幕分辨率的緣故,片元卻不能藻肄。因此頂點(diǎn)和片元之間的坐標(biāo)幾乎不可能進(jìn)行一對(duì)一轉(zhuǎn)換蔑舞,所以光柵化程序需要以某種方式將指定頂點(diǎn)坐標(biāo)轉(zhuǎn)換為最終的片元/屏幕坐標(biāo)。見(jiàn)下圖:(圖片取自書(shū)中
    光柵化
  • 如上圖所示嘹屯,在一個(gè)像素網(wǎng)格中攻询,每個(gè)像素的中心都有一個(gè)采樣點(diǎn)(sample point),采樣點(diǎn)決定了該像素是否包含在三角形中州弟。如果采樣點(diǎn)包含在三角形中(圖中紅色采樣點(diǎn))則為對(duì)應(yīng)的像素生成片元钧栖。但是在三角形的邊上,雖然三角形經(jīng)過(guò)屏幕像素婆翔,可采樣點(diǎn)并不包含在三角形中拯杠,因此片元著色器并不會(huì)影響到該屏幕像素。
  • 對(duì)于單個(gè)采樣點(diǎn)啃奴,上圖中的三角形最終渲染結(jié)果大致如下:(圖片取自書(shū)中
    單采樣點(diǎn)三角形渲染
  • 多重采樣所做的潭陪,就是不使用單個(gè)采樣點(diǎn)決定基元是否包含某個(gè)屏幕像素,而是多個(gè)采樣點(diǎn)最蕾。例如我們以常規(guī)方式放置四個(gè)子采樣(subsamples)來(lái)決定是否包含像素依溯。從下圖我們可以看出,左側(cè)單個(gè)采樣點(diǎn)像素未包含在三角形中瘟则,因此該像素不會(huì)運(yùn)行片元著色器輸出顏色黎炉;右側(cè)四個(gè)采樣點(diǎn)中有兩個(gè)包含在三角形中,因此像素運(yùn)行片元著色器產(chǎn)生顏色醋拧。(圖片取自書(shū)中
    單采樣點(diǎn)與多采樣點(diǎn)
  • 注意:采樣的數(shù)量可以是任何數(shù)字拜隧,更多的采樣點(diǎn)能更精確地決定部分包含的像素的渲染結(jié)果。
  • 在MSAA中趁仙,對(duì)于每個(gè)像素片元著色器只運(yùn)行一次,不管該像素中多少個(gè)子采樣點(diǎn)被基元包含垦页。片元著色器使用插值到像素中心的頂點(diǎn)數(shù)據(jù)運(yùn)行雀费,然后MSAA使用一個(gè)更大的深度/模板緩沖區(qū)來(lái)決定是否包含子采樣點(diǎn),最后被包含的子采樣點(diǎn)的數(shù)量決定了將多少三角形的顏色寫(xiě)入到幀緩沖區(qū)痊焊。例如上面的圖中盏袄,四個(gè)子采樣點(diǎn)中有兩個(gè)被三角形包含忿峻,那么像素最終的顏色就是一半三角形的顏色與一半幀緩沖區(qū)的顏色的混合。
  • 最終的結(jié)果就是使用更高分辨率的顏色緩沖區(qū)(和更高分辨率的深度/模板緩沖區(qū))來(lái)產(chǎn)生光滑的邊緣辕羽。(圖片取自書(shū)中
    多采樣點(diǎn)
  • 最后三角形邊緣的渲染結(jié)果大致如下逛尚,注意邊緣像素的顏色:(圖片取自書(shū)中
    多采樣點(diǎn)渲染
  • 注意:雖然片元著色器每個(gè)像素只運(yùn)行一次,但是顏色值刁愿、深度值和模板值則是按子采樣點(diǎn)數(shù)量存儲(chǔ)绰寞。

2. OpenGL中的MSAA

  • 如果我們想要使用OpenGL的MSAA,我們需要一個(gè)能存儲(chǔ)每個(gè)像素不止一個(gè)采樣值的緩沖區(qū)——一種能存儲(chǔ)指定數(shù)量采樣的緩沖區(qū)類型铣口,多重采樣緩沖區(qū)(multisample buffer)滤钱。
  • 大部分窗體系統(tǒng)都為我們提供了一個(gè)多重采樣緩沖區(qū)。在GLFW中脑题,我們只需在創(chuàng)建窗體之前調(diào)用glfwWindowHint函數(shù)指示GLFW我們需要N采樣的多重采樣緩沖區(qū)來(lái)代替常規(guī)緩沖區(qū)即可件缸。
glfwWindowHint(GLFW_SAMPLES, 4);
  • 在OpenGL中我們則只需調(diào)用glEnable函數(shù)啟動(dòng)多重采用即可(不過(guò)OpenGL一般默認(rèn)啟動(dòng)多重采樣)。
glEnable(GL_MULTISAMPLE);
  • 下面是單采樣和多采樣的綠色立方體渲染效果叔遂。


    單采樣點(diǎn)立方體

    多采樣點(diǎn)立方體

3. 離屏MSAA

  • 因?yàn)镚LFW內(nèi)置了多重采樣緩沖區(qū)的創(chuàng)建他炊,因此啟動(dòng)多重采樣很容易。但是如果我們想使用自己的幀緩沖區(qū)已艰,我們必須自己生成多重采樣緩沖區(qū)痊末。有兩種方式可以生成多重采樣緩沖區(qū)來(lái)作為幀緩沖區(qū)的附件:紋理附件和渲染緩沖區(qū)附件。與我們?cè)趲彌_區(qū)章節(jié)討論的常規(guī)附件相似旗芬。

3.1 多重采樣紋理附件

  • 要?jiǎng)?chuàng)建支持存儲(chǔ)多個(gè)采樣點(diǎn)的紋理我們使用glTexImage2DMultisample而不是glTexImage2D舌胶。
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, tex);
// samples: 采樣點(diǎn)數(shù)
// 最后一個(gè)參數(shù)GL_TRUE表示:對(duì)紋理像素采用相同的采用位置和相同的子采樣數(shù)量
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGB, width, height, GL_TRUE);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
  • 要將多重采樣紋理附加到幀緩沖區(qū),我們使用glFramebufferTexture2D函數(shù)疮丛。
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, tex, 0);

3.2 多重采樣渲染緩沖區(qū)對(duì)象

  • 與紋理相似幔嫂,創(chuàng)建多重采樣渲染緩沖區(qū)對(duì)象并不困難,我只需將glRenderbufferStorage函數(shù)更換為glRenderbufferStorageMultisample誊薄,并配置(當(dāng)前綁定)渲染緩沖區(qū)的內(nèi)存履恩。
glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, width, height);

3.3 渲染到多重采樣幀緩沖區(qū)

  • 因?yàn)槎嘀夭蓸訋彌_區(qū)比較特別,對(duì)于一些操作如著色器中的采樣呢蔫,我們不能直接使用切心。解析一個(gè)多重采樣的幀緩沖區(qū)一般使用glBlitFramebuffer函數(shù),該函數(shù)從一個(gè)幀緩沖區(qū)中的一個(gè)區(qū)域?qū)?shù)據(jù)拷貝到另外一個(gè)緩沖區(qū)中片吊,同時(shí)對(duì)多重采樣緩沖區(qū)進(jìn)行了解析绽昏。從幀緩沖區(qū)章節(jié)我們知道有GL_READ_FRAMEBUFFERGL_DRAW_FRAMEBUFFER兩個(gè)緩沖區(qū)目標(biāo)。glBlitFramebuffer函數(shù)能夠從這兩個(gè)目標(biāo)讀取數(shù)據(jù)并自動(dòng)確定哪一個(gè)是源哪一個(gè)是目標(biāo)幀緩沖區(qū)俏脊。因此我們可以通過(guò)將圖像塊傳輸?shù)?strong>默認(rèn)幀緩沖區(qū)來(lái)將多重采樣幀緩沖區(qū)數(shù)據(jù)輸出到屏幕全谤。
glBindFramebuffer(GL_READ_FRAMEBUFFER, multisampleFBO);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
  • 綜上所述,離屏MSAA的渲染循環(huán)中的大致過(guò)程如下:
// framebuffer:多重采樣的幀緩沖區(qū)
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
ClearScene();
DrawScene();
// 將多重采樣幀緩沖區(qū)輸出到默認(rèn)幀緩沖區(qū)(屏幕顯示的緩沖區(qū))
glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(0, 0, SCR_WIDTH, SCR_HEIGHT, 0, 0, SCR_WIDTH, SCR_HEIGHT, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
  • 渲染效果如下爷贫,與直接在窗體系統(tǒng)設(shè)置多重采樣相似:


    離屏MSAA渲染
  • 如果我們想對(duì)多重采樣幀緩沖區(qū)進(jìn)行后處理认然,因?yàn)槲覀儾荒苤苯邮褂卯?dāng)前片元著色器中的多重采樣紋理补憾,因此我們需要再創(chuàng)建一個(gè)非多重采樣的中間幀緩沖區(qū)。我們先將多重采樣幀緩沖區(qū)的數(shù)據(jù)拷貝到中間幀緩沖區(qū)卷员,然后對(duì)中間幀緩沖區(qū)的常規(guī)2D紋理進(jìn)行后處理盈匾,再將其顯示到屏幕上。大致過(guò)程如下:
CreateSceneAndSetData();
CreateMultisampleFramebuffer();
CreateScreenAndSetData();
CreateIntermediaFramebuffer();

SetScreenTexture();

while (!glfwWindowShouldClose(window))
{
    BindMultisampleFramebuffer();
    DrawScene();

    glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
    // 目標(biāo)設(shè)置為中間幀緩沖區(qū)
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, intermediateFBO);
    glBlitFramebuffer(0, 0, SCR_WIDTH, SCR_HEIGHT, 0, 0, SCR_WIDTH, SCR_HEIGHT, GL_COLOR_BUFFER_BIT, GL_NEAREST);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    DrawScreenTexture();

    glfwSwapBuffers(window);
    glfwPollEvents();
}
  • 一個(gè)灰度化的立方體效果毕骡。


    離屏MSAA后處理效果
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末削饵,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子挺峡,更是在濱河造成了極大的恐慌葵孤,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件橱赠,死亡現(xiàn)場(chǎng)離奇詭異尤仍,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)狭姨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)宰啦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人饼拍,你說(shuō)我怎么就攤上這事赡模。” “怎么了师抄?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵漓柑,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我叨吮,道長(zhǎng)辆布,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任茶鉴,我火速辦了婚禮锋玲,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘涵叮。我一直安慰自己惭蹂,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布割粮。 她就那樣靜靜地躺著盾碗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪舀瓢。 梳的紋絲不亂的頭發(fā)上置尔,一...
    開(kāi)封第一講書(shū)人閱讀 51,688評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼榜轿。 笑死,一個(gè)胖子當(dāng)著我的面吹牛朵锣,可吹牛的內(nèi)容都是我干的谬盐。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼诚些,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼飞傀!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起诬烹,我...
    開(kāi)封第一講書(shū)人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤砸烦,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后绞吁,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體幢痘,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年家破,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了颜说。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡汰聋,死狀恐怖门粪,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情烹困,我是刑警寧澤玄妈,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站髓梅,受9級(jí)特大地震影響拟蜻,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜女淑,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一瞭郑、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧鸭你,春花似錦屈张、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至愉老,卻和暖如春场绿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背嫉入。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工焰盗, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留璧尸,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓熬拒,卻偏偏與公主長(zhǎng)得像爷光,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子澎粟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容