日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

深入理解多重采样(Multisampling)

發(fā)布時(shí)間:2023/12/15 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入理解多重采样(Multisampling) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

轉(zhuǎn)載請標(biāo)明出處:http://blog.csdn.net/yunchao_he/article/details/78354528

Multi-sampling或者說Multi-sample Anti-Alias (簡稱MSAA)是一種抗鋸齒的技術(shù),它通過在一個(gè)像素上進(jìn)行多次采樣多次計(jì)算并最終匯總(Resolve to single-sample),可使繪制的圖像邊緣更加平滑。通過這種方式繪制出來的圖片質(zhì)量更高,顯得更真實(shí)。但同時(shí),它對(duì)繪制的性能也會(huì)產(chǎn)生負(fù)面影響。所以,是否使用這項(xiàng)技術(shù),需要開發(fā)者在圖片質(zhì)量(Quality)和性能(Performance)之間進(jìn)行權(quán)衡。那么,MSAA到底對(duì)整個(gè)繪制流水線(Rendering Pipeline)產(chǎn)生了什么影響?本文將進(jìn)行深入分析,從而幫助自己及讀者在相關(guān)問題上有更深的理解,從而做出正確合理的決策:比如在開發(fā)過程中是否使用MSAA。

MSAA簡介

首先簡單講一下什么是MSAA。MSAA就是把每個(gè)pixel(或者說fragment)細(xì)分為多個(gè)sub-pixel,比如分為4個(gè)、8個(gè)、16個(gè)甚至32個(gè)sub-pixel,分別對(duì)應(yīng)MSAA4, MSAA8, MSAA16, MSAA32。我們知道,圖形學(xué)里,每個(gè)piexl占據(jù)屏幕上的一小塊矩形網(wǎng)格。比如對(duì)于1920*1280的顯示器,就有1920*1280個(gè)小的矩形網(wǎng)格,每個(gè)網(wǎng)格都是一個(gè)pixel。而MSAA則把每個(gè)小的矩形網(wǎng)格再進(jìn)行細(xì)分。比如MSAA4/MSAA8分別把每個(gè)piexl再分為4個(gè)或者8個(gè)sub-pixel,其中每一個(gè)sub-pixel稱為一個(gè)sample。而正常pipeline里的所有per-pixel(per-fragment)的操作,打開MSAA后,理論上都可以per-sample來處理。這樣,每個(gè)pixel里的多個(gè)sample,?都可以獨(dú)立進(jìn)行插值、獨(dú)立執(zhí)行fragment shader,計(jì)算出獨(dú)立的顏色值、深度值。然后求出同一個(gè)pixel的所有sample的算術(shù)平均值(也就是resolve to single sample),就得出這個(gè)pixel的最終顏色。通過這種方式,圖形邊緣的繪制會(huì)更精細(xì)更平滑。當(dāng)然,對(duì)于1920*1280的網(wǎng)格,MSAA4相當(dāng)于在處理1920*1280*4個(gè)網(wǎng)格,計(jì)算量(以及顯存里某些變量的存儲(chǔ)空間)也是成倍增加。

MSAA分析

MSAA在Rendering Pipeline的過程中,可能的影響有以下幾方面。

1)光柵化階段(Rasterization)

光柵化階段一個(gè)重要的工作就是插值計(jì)算(Interpolation),所以多重采樣作用到這個(gè)階段主要是多重插值。?

這個(gè)階段的multisampling可以分為幾種,一種是重量級(jí)的多重插值,一種是定制化的多重插值,還有一種是輕量級(jí)的多重插值。當(dāng)然,這只是我個(gè)人的簡單分類,具體區(qū)別詳見下文。

先講重量級(jí)、重負(fù)載的多重插值。我們知道,在Rasterization階段,需要對(duì)fragment shader階段的所有inputs進(jìn)行插值計(jì)算。可能的插值計(jì)算變量包括但不限于顏色,法線,紋理坐標(biāo)等等。比如上圖手繪的圖片里,對(duì)三角形的繪制,開發(fā)者通常只設(shè)置頂點(diǎn)信息。這里以顏色為例,三個(gè)頂點(diǎn)A/B/C的顏色分別為藍(lán)色、黑色、紅色。三角形覆蓋的區(qū)域(網(wǎng)格區(qū)),都是GPU在Rasterization階段根據(jù)各個(gè)像素所在位置,進(jìn)行插值計(jì)算,得出各個(gè)pixel/fragment的顏色值。這個(gè)顏色值顯然是三個(gè)頂點(diǎn)顏色值的混合。理論上,凡是需要per-pixel插值的變量,也可以進(jìn)行per-sample插值,也就是多重插值。注意,這里的“多重”,其實(shí)是站在每個(gè)pixel(或者說fragment)的角度。因?yàn)橥粋€(gè)pixel有多個(gè)sample,每個(gè)sample都是對(duì)這個(gè)pixel進(jìn)行了細(xì)分,是它的sub-pixel(可理解為多個(gè)"子網(wǎng)格")。根據(jù)具體硬件的布局實(shí)現(xiàn),同一個(gè)pixel內(nèi)的多個(gè)sample之間,位置有差異,從而可計(jì)算出per-sample的更精細(xì)的值。這樣就相當(dāng)于對(duì)這個(gè)pixel進(jìn)行了多次插值計(jì)算。實(shí)際上對(duì)于每個(gè)sample,?當(dāng)然還是只進(jìn)行一次插值計(jì)算。

如果對(duì)所有需要插值的變量,比如fragment shader的所有inputs,都進(jìn)行這種多重插值,這就是重量級(jí)的多重插值。

比如對(duì)于顏色,如果是繪制一個(gè)很大的矩形,比如1920*1280的矩形, 對(duì)顏色變量進(jìn)行插值計(jì)算時(shí)則需要1920*1280次計(jì)算,也需要在顯存(video memory)里占用這么多的存儲(chǔ)空間。這是光柵化階段不可避免的計(jì)算消耗和存儲(chǔ)消耗。如果打開4倍的MSAA(MSAA4),則需要1980*1280*4次計(jì)算,同時(shí)也需要相應(yīng)規(guī)模的顯存空間。所以計(jì)算消耗和存儲(chǔ)消耗一下子擴(kuò)大了4倍。當(dāng)然,對(duì)于其它需要進(jìn)行插值的變量也是如此。所以,如果對(duì)所有需要插值的變量都做多重插值,顯然消耗很大。但GL確實(shí)可以這么做,調(diào)用
?

glMinSampleShading(1.0);

?

就可以對(duì)所有變量都進(jìn)行多重插值。注意,進(jìn)行多重插值,不僅計(jì)算量顯著增加,顯存消耗量也會(huì)顯著增加。

第二種是定制化的多重插值。可以在vertex shader的某個(gè)或者某些outputs以及fragment shader里相應(yīng)的inputs變量前加'sample'關(guān)鍵字。這樣,插值計(jì)算時(shí)只會(huì)對(duì)你指定的變量進(jìn)行多重插值。比如以下的一段簡單的fragment shader代碼,對(duì)fragment shader里的部分input變量添加了'sample'關(guān)鍵字(這里是color),指定對(duì)它(們)進(jìn)行多重插值,而其它變量則沒有多重插值:

#version 450 coresample in vec4 color; in vec4 normal;out vec4 fColor;void main() {// do something }

這兩種多重插值,實(shí)際上都需要和per-sample shading相結(jié)合,才有意義。也即是說,需要fragment shader的執(zhí)行是per sample,而不是per pixel。關(guān)于這一點(diǎn),詳見后面的片段著色階段如何enable多重采樣。

最后一種,是輕量級(jí)的多重插值。它對(duì)需要插值的變量本身不進(jìn)行多重插值。只針對(duì)color變量,附加coverage計(jì)算。而這個(gè)計(jì)算是per-sample的的。也就是說,對(duì)于MSAA4,它會(huì)對(duì)每個(gè)pixel申請4個(gè)bits的gl_coverage變量。記錄rasterization過程中這個(gè)sample有沒有被覆蓋。如果某個(gè)sample被覆蓋,則在gl_coverage里相應(yīng)的bit位設(shè)置為1。如果某個(gè)sample沒有被覆蓋,則相應(yīng)的bit位設(shè)置為0。這樣,可以根據(jù)coverage來調(diào)整最終顏色。比如處于圖像邊緣的像素,如果4個(gè)sample里有1個(gè)sample被覆蓋,而可以使用1/4來調(diào)和這個(gè)像素的顏色。從而達(dá)到MSAA的效果。但本身并不需要針對(duì)每個(gè)color進(jìn)行4次插值計(jì)算,也不需要4倍的顯存空間存儲(chǔ)color的值。

當(dāng)然,對(duì)于depth/stencil的值,又有一些區(qū)別。通常情況下,如果draw framebuffer里有depth/stencil?的多重采樣緩沖區(qū),則會(huì)對(duì)depth/stencil的值做多重插值,并且在per-fragment operation階段,會(huì)進(jìn)行per-sample的depth/stencil test.?

如果申請的render target是支持多重采樣的,則會(huì)自動(dòng)enable輕量級(jí)的插值計(jì)算。這包括兩種情況,第一種情況是繪制到離屏的fbo里,這時(shí)需要使用multisample renderbuffer或者multisample texture作為color buffer,必要的話,可以使用multisample renderbuffer或者multisample texture作為depth_stencil buffer,然后進(jìn)行離屏渲染,繪制到這個(gè)fbo里。而且,繪制完成后,需要開發(fā)者主動(dòng)blitting到single-sample的framebuffer去顯示。Chromium里WebGL的實(shí)現(xiàn),會(huì)默認(rèn)打開anti-alias,用的正是這種方式。相應(yīng)的示例代碼如下:

?

// 創(chuàng)建multisample texture glGenTextures( 1, &tex ); glBindTexture( GL_TEXTURE_2D_MULTISAMPLE, tex ); glTexStorage2DMultisample( GL_TEXTURE_2D_MULTISAMPLE, num_samples, GL_RGBA8, width, height, false );// 把multisample texture 作為fbo的color bufferglGenFramebuffers( 1, &fbo );glBindFramebuffer( GL_FRAMEBUFFER, fbo );glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, tex, 0 );rendering(); // 離屏渲染,繪制到fbo里。開發(fā)者需要根據(jù)自己的業(yè)務(wù)邏輯,自行實(shí)現(xiàn)// blitting glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); glDrawBuffer(GL_BACK); glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);

另一種情況是直接繪制到窗口的默認(rèn)緩存(default framebuffer),?這需要在窗口創(chuàng)建的時(shí)候聲明為Multisample的窗口, glut可以幫助你完成這個(gè)操作,而不需要對(duì)各種窗口系統(tǒng)進(jìn)行處理。其代碼如下(這段代碼將創(chuàng)建一個(gè)RGBA顏色格式的multisample default framebuffer,?而且是雙緩沖):
?

glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_MULTISAMPLE);

這種情況下,系統(tǒng)也會(huì)自動(dòng)幫你resolve到single sample的buffer并顯示,不需要開發(fā)者做更多操作。實(shí)際上,如果創(chuàng)建窗口默認(rèn)緩存(default framebuffer)時(shí)就enable了MSAA,窗口系統(tǒng)會(huì)申請一個(gè)msaa的color buffer,?同時(shí)也會(huì)申請single-sample?的color buffer。但default framebuffer的depth/stencil buffer,?則只有一個(gè)msaa的depth/stencil buffer,?沒有single-sample的depth/stencil buffer.?


2)采樣階段

綁定多重采樣的texture,?然后使用texelFetch之類的采樣函數(shù),則可從multisample texture里進(jìn)行逐sample的紋理采樣(per-sample texture fetching)。當(dāng)然,per-sample texture fetching可以結(jié)合gl_sampleID來進(jìn)行,也就是同一個(gè)pixel里的每個(gè)sample,有自己的sampleID,然后通過gl_sampleID為每個(gè)sample獲取不同的值。以下是一個(gè)簡單的fragment shader的例子,將插值得到的color和multisample里的多重采樣值,進(jìn)行融混。

#version 450uniform sample2DMS tex; in ivec2 texCoord; in color;out fColor;void main() {fColor = 0.5 * color + 0.5 * texelFetch(tex, texCoord, gl_SampleID); }

當(dāng)然,per-sample texture fetching也是在per-sample shading的時(shí)候才有意義。

另外需要指出的是,開發(fā)者無法初始化一個(gè)multisample texture的數(shù)據(jù)。也即是不存在類似于TexImage2D這樣的接口,去上傳初始化multisample的原始圖片。所以,multisample texture里進(jìn)行采樣,像素內(nèi)容必定是用戶自主render出來的。

3)片段著色階段

片段著色階段進(jìn)行多重采樣,就是指fragment shader的執(zhí)行不是per pixel/fragment,?而是per sample。也是說,對(duì)于1920*1280的render target,?普通情況下,需要調(diào)用1920*1280次fragment shader,?如果使用了MSAA4,則需要調(diào)用1920*1280*4次fragment shader!

所以,如果fragment shader很復(fù)雜,4倍的計(jì)算量將會(huì)嚴(yán)重影響性能。

當(dāng)然,per-sample shading并不會(huì)自動(dòng)打開,需要開發(fā)者主動(dòng)調(diào)用上文提到的glMinSampleShading(1.0)。當(dāng)然,MinSampleShading里的參數(shù)可以選擇其它數(shù)據(jù),比如0.5。則對(duì)MSAA4,它會(huì)選擇4個(gè)sample里的2個(gè)sample進(jìn)行per-sample shading,計(jì)算量為2倍。另外,前面已經(jīng)講到,per-samper shading還會(huì)針對(duì)需要插值的變量,進(jìn)行per-sample interpolation。這樣,同一個(gè)pixel/fragment內(nèi)的每個(gè)sample的插值的結(jié)果都會(huì)不一樣。從而使計(jì)算結(jié)果更精細(xì)。當(dāng)然代價(jià)也很大,既成倍增加插值計(jì)算量,也成倍增加顯存的存儲(chǔ)空間。同樣地,也可以在fragment shader里進(jìn)行per-sample texture fetching,?為同一個(gè)pixel/fragment里的不用sample獲取不同的紋理采樣值。

4)Blitting

blitting通常是把multisample framebuffer里的像素內(nèi)容,resolve到single-sample framebuffer里。如果繪制的時(shí)候使用了multisample fbo進(jìn)行離屏渲染,則需要開發(fā)者自行調(diào)用blitFramebuffer。上文也有使用blitFramebuffer從離屏的msaa fbo渲染到single-sample framebuffer的例子。

小結(jié)

最后,大家可以發(fā)現(xiàn),MSAA對(duì)Rasterization之前的階段都沒有直接影響。比如CPU的操作(主要是clident driver的validation等)不會(huì)受到影響,比如也不增加從CPU上傳到GPU的數(shù)據(jù)(比如頂點(diǎn)數(shù)據(jù),紋理數(shù)據(jù)),也不會(huì)增加vertex shader、tessellation shader、geometry shader的執(zhí)行次數(shù)。這些階段,都不會(huì)受MSAA的直接影響。如果這些階段是繪制程序的性能瓶頸,即使開啟MSAA,性能的損失可能也不會(huì)明顯。

而MSAA對(duì)性能的影響主要體現(xiàn)在所有per pixel/fragment的操作,比如rasterization階段的插值計(jì)算以及存儲(chǔ)開銷, fragment shader的執(zhí)行等。不同類型的MSAA操作,會(huì)對(duì)這些階段帶來顯著影響。如果性能瓶頸在這些階段,使用MSAA后,很可能導(dǎo)致性能顯著下降。

一般來講,使用輕量級(jí)的multisampling技術(shù)(也就是創(chuàng)建multisample的framebuffer),就可以達(dá)到較好的渲染質(zhì)量,性能損失也不太大。但是,如果需要處理alpha-tested transparency問題,輕量級(jí)的multisampling技術(shù)則根本不起作用。當(dāng)你使用一張較大的規(guī)則圖片去表達(dá)不規(guī)則的貼圖,多余部分則需要通過alpha值(比如alpha值為0)來剔除,這時(shí)就需要使用alpha-tested transparency技術(shù)。比如一棵樹的圖片,可能是規(guī)則長方形,但樹木本身并不規(guī)整,原始圖片里樹木本身之外的像素,texture mapping時(shí)需要根據(jù)alpha值剔除,以免遮擋場景里的其它物體。這時(shí)候如果需要使用multisampling技術(shù),則輕量級(jí)的MSAA會(huì)出問題。關(guān)于alpha-tested transparency問題,詳見參考文獻(xiàn)[7]。所以重量級(jí)的多重采樣,也有其應(yīng)用場景和價(jià)值。

參考文檔:


[1] OpenGL, OpenGL ES specification,?主要是OpenGL 4.5/4.6, OpenGL ES 3.1/3.2?的specification.

[2] OpenGL Shading Language和OpenGL ES Shading Language,?主要是GLSL 450/460以及GLSL ES 310/320

[3] OpenGL Programming Guide 8th edition

[4] ARB_sample_shading:https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_sample_shading.txt (The Q&A part is also interesting)?

[5] OES_sample_shading:https://www.khronos.org/registry/OpenGL/extensions/OES/OES_sample_shading.txt

[6] Multisampling:https://www.khronos.org/opengl/wiki/Multisampling

[7]Transparency and alpha-tested transparency:https://www.khronos.org/opengl/wiki/Transparency_Sorting
————————————————
?
原文鏈接:https://blog.csdn.net/yunchao_he/article/details/78354528

總結(jié)

以上是生活随笔為你收集整理的深入理解多重采样(Multisampling)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。