Geometry shader總結


什么是Geometry Shader

GS存在於vertext shader和固定功能vertex post-processing stage之間,它是可選的不是必要的。
GS的輸入是單個primitive,輸出可能是0個或多個primitive. 

GS的作用

GS的主要作用就是從已有的primitive中生成新的primitive,它可以“無中生有”的生成新的頂點

OpenGL官網上提到兩種用法:

  Layered rendering: 對一個primitive,不改變rendertarget渲染出多個圖片
  Transform Feedback: 用來執行GPU的計算任務(pre-compute shader)

Real-time rendering書中提到了幾種效果可以用GS來實現:

  creating various sized particles from point data

      extruding fins along silhouettes for fur rendering

      finding object edges for shadow algorithms

下圖是個例子,給GS輸入一個三角形,GS輸出4個三角形

Layered Rendering

上面說到了,GS的一大用處體現在layerd rendering,即多層渲染。

試想一下,對於多層紋理而言,每一層的紋理坐標實際上是相同的。層號如何指定呢?固然可以在建立VBO時給紋理坐標第三個維度值,但是這並不會讓OpenGL畫到你想畫的層上:Fragment的過程就是將頂點像素化的過程,而這個過程是二維的……最后拿到的二維圖像必然沒有深度,層數無從談起。

但是Geometry卻有個關鍵的內建輸出變量:out int gl_Layer,正是它能夠指定繪制的層數。我們不妨先將我寫出來的geometry shader的內容貼出來,注意顯卡至少要支持到OpenGL 4.0,#version這句至少是400:

 1 #version 450
 2 layout (triangles, invocations = 2) in; //輸入三角形,2次調用
 3 layout (triangle_strip, max_vertices = 3) out;  //輸出三角形
 4 in vec2 gTexCoord[];    //從Vertex傳過來的紋理坐標
 5 out vec2 fTexCoord;     //傳到Fragment去的紋理坐標
 6 out int gl_Layer;   //層數的標記
 7 void main()
 8 {
 9     for(int k=0; k<gl_in.length(); k++)   //針對三角形每個頂點
10     {
11         gl_Layer = gl_InvocationID;    //用調用編號標記層號
12         fTexCoord = gTexCoord[k];    //紋理坐標傳遞
13         gl_Position = gl_in[k].gl_Position;    //頂點坐標傳遞
14         EmitVertex();    //開始傳遞頂點信息,對每個頂點調用一次
15     }
16     EndPrimitive();    //結束一個primitive,一個primitive調用一次
17 }

 需要注意的是,triangles意味着你在OpenGL的繪制指令必須是GL_TRIANGLEGL_TRIANGLE_STRIP或者GL_TRIANGLE_FAN。其他的對應關系可以在Wiki查到。三角形有3個頂點,這一組3個頂點將同時進入Geometry中,因此在Geometry中能拿到一個gl_in[]的內建數組,這個數組的大小應該跟繪制時一組頂點的數量一致,三角形就是3。而在這里我不需要增加頂點,因此輸出也還是3個頂點。同時紋理坐標也理所當然地變成了數組。因此需要一個循環來對三角形的每個頂點進行操作。

這里頂點坐標和紋理坐標都不必改,因此直接傳遞過去了。重點在於gl_Layer這一句。gl_Layer這個內建變量用於指示當前繪制的層號,這個值將影響像素化后像素繪制到哪一層上。OpenGL要求一組頂點(這里是一個三角形)內部的gl_Layer必須一致。這里賦值之后順便把它傳到Fragment里作為標志。
關鍵的一步在於第二行的invocations = 2gl_InvocationID這個內建變量。invocations=n指示Geometry對每組頂點做n次運算,用gl_InvocationID來標記每次運算的序號。我們可以將這個序號送到gl_Layer來作為層號的值!這樣geometry就會將這一組頂點重復發送兩次,而這兩次是發送到不同層上的,從而實現不同層的繪制!

接下來只要在Fragment里拿到這個gl_Layer,根據需要分層作處理就可以了。

用Transform feedback創建粒子系統

粒子系統是為了模仿一些自然現象(比如煙,灰塵,煙火,雨等)所使用的技術的一個通用名字。在這些現象中,共同的地方就是它們是由大量的小粒子所組成,這些小的粒子以某種方式在一起移動,這樣就構成了一種自然現象。

DirectX10 介紹了一個新的特性叫 Stream Output,這個對於粒子系統的實現是非常有用的。OpenGL 在 3.0
版本之后也加入了這個特性——Transform Feedback,其實現思路是在 GS(如果沒有使用 GS 則是
VS)處理之后,我們可以將變換之后的圖元存放到一個特殊的緩存——Transform Feedback Buffer
中。此外,我們可以決定圖元是否將繼續按照以前的流程進行光柵化。在下一幀渲染的時候,上一幀中輸出的頂點信息可以在這一幀中作為頂點緩存使用,在這樣的一個循環過程中,我們可以不借助於應用程序來實現對粒子信息的更新。下面這幅圖片介紹了 Transform Feedback Buffer 在管線中所處的位置。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM