1. 程式人生 > >轉:關於支援多重取樣的FBO和Texture

轉:關於支援多重取樣的FBO和Texture

該文轉自風過楓默的部落格,對於如何使用MSAA(Multisample Anti Aliasing)解釋的比較透徹,特轉載來供自己查閱,也方便大家,原文連結為 http://www.cnblogs.com/chandler00x/p/3888139.html?utm_source=tuicool&utm_medium=referral 

閒話不嘮,簡單粗暴版。

  簡單提一句MSAA(Multisample Anti Aliasing),依本人愚見,MSAA就是光柵化階段對一個畫素內部進行多次取樣(採4次就是4X,採8次就是8X多重取樣),然後根據按照一定規則(預設是取平均值)將同一個畫素內的多個取樣點融合成一個的過程(resolve 過程)。

  先講簡單的版本,從OpenGL的使用角度上講,多重取樣可以分為兩種,context-based 和 Fbo-based。

  Context-based Multisample需要顯式(明確地,explicitly)建立一個支援多重取樣的上下文(OpenGL Render Context)。使用時只需要呼叫glEnable(GL_MULTISAMPLE),那麼接下來要渲染的物體都會進行多重取樣。輕鬆加愉快! 前提是你使用GLUT、GLFW等庫,可以很簡單地通過呼叫一個函式來建立支援多重取樣渲染環境的視窗。但是!當你像我一樣,要基於win32 或者 mfc構建OpenGL 應用程式時,這個過程就相對複雜一點。此過程在之前的隨筆中有講到,要先建立視窗、建立臨時context、初始化glew庫,獲得相關函式指標、銷燬原視窗,建立新context等等操作,在此按下不表。

  Fbo-based Multisample不需要顯式地去建立一個支援多重取樣的上下文。採用這種方法給了我們更多的靈活性。Fbo-based Multisample也可以分為小兩種。第一種,渲染到RenderBuffer,然後呼叫glBlitFramebuffer到default framebuffer。採用第一種方法,多重取樣的resolve過程由glBlitFramebuffer完成了,所以我們不用擔心這個環節。第二種:渲染到Texture,然後在fragment shader中手動地對 sample 進行 resolve 操作。預設的resolve是取平均值的,現在我們可以在fragment shader中獲取各個sample的值,要怎麼resolve,決定權在你,這就是所謂的靈活性。

蘿莉囉嗦,全程程式碼版 

  第一種!基於OpenGL Context的多重取樣。實在沒啥好講的。重點完全在於如何建立支援多重取樣的Context。好麻煩的,但是我在之前的隨筆中有講到,以Nehe的程式碼為例(我還是把Nehe的原版程式碼也貼上吧,免得以後找不著)。注意,在建立支援多重取樣的渲染環境時,有一段程式碼是OpenGL環境設定的,如下:

複製程式碼
 1 int iAttributes[] = 
 2     {
 3         WGL_DRAW_TO_WINDOW_ARB,GL_TRUE,
 4         WGL_SUPPORT_OPENGL_ARB,GL_TRUE,
 5         WGL_ACCELERATION_ARB,WGL_FULL_ACCELERATION_ARB,
 6             WGL_COLOR_BITS_ARB,24,
 7             WGL_ALPHA_BITS_ARB,8,
 8             WGL_DEPTH_BITS_ARB,24,
 9             WGL_STENCIL_BITS_ARB,0,
10             WGL_DOUBLE_BUFFER_ARB,GL_TRUE,
11             WGL_SAMPLE_BUFFERS_ARB,GL_TRUE,  //!要將多重取樣使用的buffers設定為真。
12             WGL_SAMPLES_ARB,4,          //!在此設定取樣點的數量。
13             0,0
14     };
15 
16     //First We Check To See If we can get a pixel format for 4 Samples
17     valid = wglChoosePixelFormatARB(hDc,iAttributes,fAttributes,1,&pixelFormat,&numFormats);
複製程式碼

  注意設定取樣緩衝區為真,設定取樣點數量就ok了,別的沒啥好說的。渲染的時候呼叫glEnable(GL_MULTISAMPLE)就好了。

  第二種!這個值得說道下!

  先說下FBO渲染到RenderBuffer的多重取樣方式吧。 Talk is cheap, show me the code!

複製程式碼
 1    glGenRenderbuffers(1,&m_multiSampleColor);
 2     glBindRenderbuffer(GL_RENDERBUFFER,m_multiSampleColor);
 3     glRenderbufferStorageMultisample(GL_RENDERBUFFER,4,GL_RGBA8,m_width,m_height);  //與普通Renderbuffer不同的是,在分配空間時,我們呼叫glRenderBufferStorageMultisample(),第二個引數是取樣數。
 4 
 5     glGenFramebuffers(1,&m_multiSampleFBO);
 6     glBindFramebuffer(GL_FRAMEBUFFER,m_multiSampleFBO);
 7     
 8     glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_RENDERBUFFER,m_multiSampleColor);
 9 
10 
11     //glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D_MULTISAMPLE,m_texID,0);
12 
13     glGenRenderbuffers(1,&m_multiSampleDepth);
14     glBindRenderbuffer(GL_RENDERBUFFER,m_multiSampleDepth);
15     glRenderbufferStorageMultisample(GL_RENDERBUFFER,4,GL_DEPTH_COMPONENT,m_width,m_height);  //用作Depth Test的RenderBuffer也一樣,要呼叫glRenderBufferStorageMultisample()
16 
17     
18     glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_RENDERBUFFER,m_multiSampleDepth);
19 
20     GLenum drawBufs[] = {GL_COLOR_ATTACHMENT0};
21     glDrawBuffers(1, drawBufs);
22 
23     GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
24     if( result == GL_FRAMEBUFFER_COMPLETE) {
25         printf("Framebuffer complete!\n");
26     } else {
27         printf("Framebuffer incomplete!\n");
28     }
複製程式碼

  注意上面的程式碼紅色標註的部分,與普通Renderbuffer不同的是,用於多重取樣渲染的Renderbuffer需要呼叫glRenderbufferStorageMultisample來為Renderbuffer分配空間,第二個引數為取樣點個數。

  以上是Framebuffer的初始化部分。以下是渲染的部分:

複製程式碼
 1     glBindFramebuffer(GL_FRAMEBUFFER,m_multiSampleFBO);  //繫結你之前申請的FBO
 2     
 3     // Shader Programs,Setup Matrices, Light, Materials,  And Render Whatever You Want To Render Here!       //放開了畫吧,騷年!
 4 
 5     glBindFramebuffer(GL_READ_FRAMEBUFFER,m_multiSampleFBO);  //設定之前的FBO為將要讀取的Framebuffer
 6     glBindFramebuffer(GL_DRAW_FRAMEBUFFER,0);           //設定螢幕(default framebuffer)為將要寫入的Framebuffer
 7     glBlitFramebuffer(0,0,m_width,m_height,0,0,m_width,m_height,GL_COLOR_BUFFER_BIT,GL_NEAREST);  //傳送FBO的ColorBuffer到default framebuffer的ColorBuffer去,期間進行了Multisample的Resolve操作。
 8     glBlitFramebuffer(0,0,m_width,m_height,0,0,m_width,m_height,GL_DEPTH_BUFFER_BIT,GL_NEAREST);  //傳送FBO的DepthBuffer到default framebuffer的DepthBuffer去,期間進行了Multisample的Resolve操作。
 9 
10     glBindFramebuffer(GL_READ_FRAMEBUFFER,0);
11     glBindFramebuffer(GL_DRAW_FRAMEBUFFER,0);   
複製程式碼

  值得注意的是,在綁定了之前申請的FBO,渲染所有需要渲染的物體到其繫結的RenderBuffer之後,需要進行從FBO到default framebuffer的Blit操作,此期間Multisample的Resolve操作由OpenGL為你悄無聲息地完成了。

  下面來說道下,FBO渲染到Texture的多重取樣方式!

  首先先來看看FBO初始化部分的程式碼:

複製程式碼
 1     GLint iUnits;
 2     glGetIntegerv(GL_MAX_TEXTURE_UNITS,&iUnits);
 3     printf("Max Texutre Units Supported is %d.h\n",iUnits);
 4 
 5     glActiveTexture(GL_TEXTURE0);
 6     glGenTextures(1,&m_texID);
 7     glBindTexture(GL_TEXTURE_2D_MULTISAMPLE,m_texID);      //注意與普通Texture的不同,這裡繫結的Target是 GL_TEXTURE_2D_MULTISAMPLE,意圖已經很明顯了吧!
 8 
 9     glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE,4,GL_RGBA8,m_width,m_height,GL_TRUE);  //分配空間的函式也是呼叫的Multisample版本,Target依然是GL_TEXTURE_2D_MULTISAMPLE
10 
11     glGenRenderbuffers(1,&m_multiSampleDepth);
12     glBindRenderbuffer(GL_RENDERBUFFER,m_multiSampleDepth);
13     glRenderbufferStorageMultisample(GL_RENDERBUFFER,4,GL_DEPTH_COMPONENT,m_width,m_height);  //我們依然需要支援多重取樣的Depth Buffer,不然Framebuffer完整性檢查會通不過。
14 
15     glGenFramebuffers(1,&m_multiSampleFBO);
16     glBindFramebuffer(GL_FRAMEBUFFER,m_multiSampleFBO);
17     glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D_MULTISAMPLE,m_texID,0);  //注意Target依然是GL_TEXTURE_2D_MULTISAMPLE
18     glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_RENDERBUFFER,m_multiSampleDepth);
19 
20     GLenum drawBufs[] = {GL_COLOR_ATTACHMENT0};
21     glDrawBuffers(1, drawBufs);
22 
23     GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
24     if( result == GL_FRAMEBUFFER_COMPLETE) {
25         printf("Framebuffer complete!\n");
26     } else {
27         printf("Framebuffer incomplete!\n");
28     }
複製程式碼

  在上述程式碼的註釋中已經寫得很清楚,我們需要支援Multisample的Texture,相關的繫結Target以及記憶體空間分配函式都有各自的Multisample版本。

  接下來看看渲染部分的程式碼:(只挑重要的部分)

複製程式碼
        //Pass 1:
        glBindFramebuffer(GL_FRAMEBUFFER,m_multiSampleFBO);
        
        //Select Shader Programs, Setup Matrices, Lights, Materials.

        //Render Objects
    
        //Pass 2:
        glBindFramebuffer(GL_FRAMEBUFFER,0);

        //Select Shader Programs, Setup Shader Uniforms.
    
        //Render A Full Screen Quad!
複製程式碼

  上面的程式碼貌似啥內容都沒有哈,其實簡單的說,分為2個render pass。 第一個Pass,將物體渲染到多重取樣過的紋理中。第二個pass,將紋理resolve到defaul Framebuffer,即螢幕上。

  其實在關鍵在於第二個pass中的resolve過程。貼上程式碼。這是pass 2的Fragment shader。

複製程式碼
 1 #version 400
 2 
 3 in vec2 Coord;
 4 
 5 layout (location = 0) out vec4 FragColor;
 6 
 7 uniform sampler2DMS baseTex;    //注意,此處不再是普通的sampler2D,而是sampler2DMS,專職疑難多重取樣問題。
 8 
 9 uniform int nMultiSample;      //取樣個數,此處傳入為4
10 
11 
12 
13 void main(void)
14 {
15     ivec2 texSize = textureSize(baseTex);
16 
17     vec4 fTexCol = vec4(0.0);
18 
19     if( 0 == nMultiSample )
20     {
21         FragColor = texelFetch(baseTex,ivec2(Coord * texSize),0);
22     }
23     else
24     {
25         for( int i = 0 ; i < nMultiSample ; i++ )
26         {
27             fTexCol += texelFetch(baseTex, ivec2(Coord * texSize), i);  //獲取每個取樣點的顏色,然後求平均。如果想試其他的resolve方法,It's up to you!
28         }
29         FragColor = fTexCol / nMultiSample;
30     }
31 }
複製程式碼

  在Fragment shader中,通過一個sampler2DMS 獲取紋理中的4個取樣點,通過texelFetch內建函式獲取取樣點顏色,求平局值,作為這個畫素的最終值!

  終於寫完了!呼~

相關推薦

關於支援多重取樣FBOTexture

該文轉自風過楓默的部落格,對於如何使用MSAA(Multisample Anti Aliasing)解釋的比較透徹,特轉載來供自己查閱,也方便大家,原文連結為 http://www.cnblogs.com/chandler00x/p/3888139.html?utm_source=tuicool&ut

NGINX中的proxy_passrewrite

http狀態碼 gin cep itl def rem 參數 nta bre 章作者:luxianghao 文章來源:http://www.cnblogs.com/luxianghao/p/6807081.html 轉載請註明,謝謝合作。 免責聲明:文章內容僅代表個人觀點

JSP中out.write()out.print()的區別

out物件的型別是JspWriter。JspWriter繼承了java.io.Writer類。 1)print方法是子類JspWriter,write是Writer類中定義的方法; 2)過載的print方法可將各種型別的資料轉換成字串的形式輸出,而過載的write方法只能輸出字元、字

Spring歷史版本變遷如今的生態帝國

Spring歷史版本變遷和如今的生態帝國     前兩篇: 為什麼要有Spring?

機器學習支援向量機SVM人工神經網路ANN的比較

在統計學習理論中發展起來的支援向量機(Support Vector Machines, SVM)方法是一種新的通用學習方法,表現出理論和實踐上的優勢。SVM在非線性分類、函式逼近、模式識別等應用中有非常好的推廣能力,擺脫了長期以來形成的從生物仿生學的角度構建學習機器的束縛。

系統技術非業餘研究 » CPU密集型計算 erlangC 大比拼

原文地址:http://pseudelia.wordpress.com/2009/08/23/erlang-native-code-benchmark/ Normalerweise compiliert Erlang Bytecode (heißt das so in Erlang?). Das

用Java實現JVM(二)支援介面、類物件

1. 概述我的 JVM 已經能夠執行HelloWorld了,並且有了基本的 JVM 骨架,包括執行時資料結構的定義(棧、棧幀、運算元棧等),執行時的邏輯控制等。但它還沒有類和物件的概念,比如無法執行下面這更復雜的HelloWorld:public interface SpeakerInterface {

你知道的java你不知的的java

最近我們收到一封電子郵件,諮詢 “什麼是Java?”條目的資訊。在2006年,難道還有人不知道“什麼是Java”嗎?十年來,有大量介紹Java的書籍、網站和會議,難道不是所有人都知道“什麼是Java”嗎?顯然答案是否定的。畢竟,情況已經改變。每個涉及applet和實時(Jus

Direct3D基礎——預備知識多重取樣、畫素格式、記憶體池、交換鏈頁面置換、深度快取、頂點運算、裝置效能

多重取樣 用畫素矩陣表示影象的時候往往會出現塊狀效應,多重取樣便是一項用於平滑塊狀影象的技術。 圖片來自:DirectX9.03D遊戲開發程式設計基礎 左邊那條是一條鋸齒線,右邊是一條經過取樣的反走樣線,看上去要平滑的多。 D3DMULTISAMPLE_TYPE列舉型別包含

【Java並發編程】之二十並發新特性—Lock鎖條件變量(含代碼)

ets exc n) 否則 max 長時間 info trace space 簡單使用Lock鎖 Java 5中引入了新的鎖機制——Java.util.concurrent.locks中的顯式的互斥鎖:Lock接口,它提供了比synchronized更加廣泛的鎖

【Java並發編程】之二十一並發新特性—阻塞隊列阻塞棧(含代碼)

err 退出 link rac gb2312 com void throws pbo 轉載請註明出處:http://blog.csdn.net/ns_code/article/details/17511147 阻塞隊列 阻塞隊列是Java 5並發新特性中的內容

【實用教程】阿裏雲服務器的配置使用

-a 文件 4.4 創建 site 租用服務器 網頁 html F12 【實用教程】阿裏雲服務器的配置和使用 隨著網絡應用的日常化,網絡資源的使用已經不是專業人士或機構的專利。通過簡單的學習,每個人都可以在無需硬件的情況下擁有一個甚至多個服務器,並配置屬於自己的網頁

MySQLOracle的一些區別

interval art 年月日 tool 數學運算 ont 簡單 序列號 最大的 有很多應用項目, 剛起步的時候用MYSQL數據庫基本上能實現各種功能需求,隨著應用用戶的增多,數據量的增加,MYSQL漸漸地出現不堪重負的情況:連接很慢甚至宕機,於是就有把數據從MYSQL遷

VMware中CentOS配置靜態IP進行網絡訪問(NAT方式橋接模式)

name nat模式 定義 終端 star static state alt 相關 傳送門:http://blog.csdn.net/zhangatle/article/details/77417310 其實這個博主的博客最是適合新手學習,踩過的坑讓我再踩一踩,印象深刻

[] [Java] 知乎下巴第5集使用HttpClient工具包寬度爬蟲

fan param 出隊 page connect ise dex ide xtra 原文地址:http://blog.csdn.net/pleasecallmewhy/article/details/18010015 下載地址:https://code.csdn.net

25個Java機器學習工具

重點 推薦系統 mine 很多 .sh 分類器 ssi 包括 eve 轉自:http://www.cnblogs.com/data2value/p/5419864.html 本列表總結了25個Java機器學習工具&庫: 1. Weka集成了數據挖掘工作的機器學習算法

HTMLWeb窗體的區別

ont .net 加載 平臺 最快 font -s ext 加載速度 總結:Html就是靜態頁面,可以用來寫錯誤界面等不需要和後臺交互的,簡單的界面;web窗體用來和服務器交互,實現動態的,比較復雜的功能。 一、Html和web窗體的區別: 1、 HTML頁

】編寫高質量代碼改善C#程序的157個建議——建議28理解延遲求值主動求值之間的區別

ons ati rgs 理解 問題 效率 sele 而不是 reac 建議28:理解延遲求值和主動求值之間的區別 要理解延遲求值(lazy evaluation)和主動求值(eager evaluation),先看個例子: List<in

quojs 及 11個處理觸摸事件多點觸摸的JS庫

eal detail true asc tps www ast box asp QuoJs官方文檔http://www.360doc.com/content/15/0504/18/11984479_468037372.shtml ==== 11個處理觸摸事件和多點觸

理解 IntelliJ IDEA 的項目配置Web部署

例如 tps alt 開發 path -c archive 可能 tab 1、項目配置的理解 IDEA 中最重要的各種設置項,就是這個 Project Structre 了,關乎你的項目運行,缺胳膊少腿都不行。最近公司正好也是用之前自己比較熟悉的IDEA而不是Eclipse