2013-05-20 55 views
4

我想和GLSL啓動延遲着色項目,Java的&的OpenGLLWJGL中的延遲着色如何工作?

1.如何做一個延遲渲染管線工程,它使每幅圖像的場景? 例如,當我想要創建高光模糊和陰影紋理時,是否需要爲每個這些紋理渲染場景。

我見過一些代碼片段,沒有多個渲染循環。

2.什麼是幾何緩衝區,它有什麼作用?它是否可以像場景數據的存儲一樣,我可以在不再次渲染的情況下繪製到紋理上?

+3

不是這裏要問的問題的類型,但是,您可以在這裏找到一些實際實現的信息:(http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter09.html) – dinony

+0

延遲渲染具有*與LWJGL無關。這完全是關於OpenGL和你如何使用它。 –

回答

13

要添加更多的特性,因此你可能會開始的東西。您需要具有多個附件的FBO以及讓着色器寫入多個FBO附件的方法。 Google glDrawBuffers。您的FBO附件也需要紋理,以便將信息傳遞給着色器。 FBO附件的尺寸應與您渲染的屏幕尺寸相同。有很多方法可以解決這個問題。這是一個例子。

需要兩個宗教組織

幾何緩衝區

1. Diffuse (GL_RGBA) 
2. Normal Buffer (GL_RGB16F) 
3. Position Buffer (GL_RGB32F) 
3. Depth Buffer 

注意3)是一個巨大的浪費,因爲我們可以利用深度緩存和重建的位置的投影。這是很多便宜。起始位置緩衝區至少是一個好的開始。一次攻擊一個問題。

2)正常緩衝區也可以被壓縮更多。

光累積緩衝器

1. Light Buffer (GL_RGBA) 
2. Depth Buffer 

深度在這個FBO 緩衝器附着應該是相同的附件如在幾何緩衝器。在這個例子中,我們可能不會使用這個深度緩衝區信息,但您遲早會需要它。它將始終包含第一階段的深度信息。

我們該如何渲染這些東西?

我們從非常簡單的着色器渲染場景開始。這些的目的主要是填充幾何緩衝區。我們只需使用填充幾何緩衝區的非常簡單的着色器繪製所有幾何圖形。爲了簡單起見,我使用了120個着色器並且沒有紋理映射(儘管這些都是超級微不足道的)。

頂點着色器:

#version 120 

varying vec3 normal; 
varying vec4 position; 

void main(void) 
{ 
    normal = normalize(gl_NormalMatrix * gl_Normal); 
    position = gl_ModelViewMatrix * gl_Vertex; 
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; 
} 

片段着色器:

#version 120 

uniform vec4 objectColor; // Color of the object you are drawing 
varying vec3 normal; 
varying vec4 position; 

void main(void) 
{ 
    // Use glDrawBuffers to configure multiple render targets 
    gl_FragData[0] = objectColor; // Diffuse 
    gl_FragData[1] = vec4(normalize(normals.xyz), 0.0); // normals 
    gl_FragData[2] = vec4(position.xyz, 0.0); // Position 
} 

現在我們已經例如繪製的20個對象,以不同顏色的出幾何緩衝區。如果我們看看漫反射緩衝區,這是一個非常沉悶的圖像與純色(或無光照的普通紋理),但我們仍然有每個片段的視圖位置,正常和深度。這將是在進行照明時的下一個階段的寶貴信息。

輕積累

現在我們切換到我們的光積累緩衝器,現在是時候做一些光明魔法。對於我們要用添加劑混合啓用的我們的光累積緩衝區中的每一條光線。只要您覆蓋受光線影響的所有碎片,您如何做到這一點對於結果並不重要。您最初可以通過繪製全屏四邊形來完成此操作,但這非常昂貴。我們只會介紹點光源,但這足以涵蓋簡單的照明原理(簡單的點光源極其微不足道)。一種簡單的方法是在由光半徑縮放的光位置繪製立方體或低聚球體(光量)。這使得渲染大量小燈光的方式更有效率......但現在不用擔心表現。全屏四合一會很好的解決問題。

現在,簡單的原則是:

  • 每個片段已存儲的x,y,z位置,我們簡單地用質地得到獲取
  • 我們傳遞的光
  • 位置我們通過在光
  • 我們可以知道,如果該片段可以通過光的影響半徑簡單地通過測量值中的位置緩衝區
  • 的距離光源的位置從那裏它很ST昂達爾光計算

片段着色器: (此着色器適用於任何東西。輕量,全屏四邊形..等等) 的#Version 120

uniform sampler2D diffuseBuffer; 
uniform sampler2D positionBuffer; 
uniform sampler2D normalBuffer; 

uniform float lightRadius; // Radius of our point light 
uniform vec3 lightPos; // Position of our point light 
uniform vec4 lightColor; // Color of our light 
uniform vec2 screensize; // screen resolution 

void main() 
{ 
    // VU for the current fragment 
    vec2 uv = vec2(gl_FragCoord.x/screensize.x, gl_FragCoord.y/screensize.y); 
    // Read data from our gbuffer (sent in as textures) 
    vec4 diffuse_g = texture2D(diffuseBuffer, uv); 
    vec4 position_g = texture2D(positionBuffer, uv); 
    vec4 gnormal_g = texture2D(normalBuffer, uv); 

    // Distance from the light center and the current pixel 
    float distance = length(lightPos - position_g.xyz); 

    // If the fragment is NOT affecter by the light we discard it! 
    // PS : Don't kill me for using discard. This is for simplicity. 
    if(distance > lightRadius) discard; 

    // Calculate the intensity value this light will affect the fragment (Standard light stuff!) 
    ... Use lightPos and position_g to calculate the light normal .. 
    ... Do standard dot product of light normal and normal_g ... 
    ... Just standard light stuff ... 

    // Super simple attenuation placeholder 
    float attenuation = 1.0 - (distance/lightRadius); 

    gl_FragColor = diffuse_g * lightColor * attenuation * <multiplier from light calculation>; 
} 

我們重複這一過程,每個光。光線渲染順序無關緊要,因爲結果總是與添加劑混合相同。您也可以通過僅累積光強來簡化操作。從理論上講,您應該已經在燈光蓄積緩衝區中獲得了最終點亮的結果,但您可能需要進行其他調整。

結合

您可能需要調整一些東西。周圍?色彩校正?多霧路段?其他後期處理的東西。您可以將光線累積緩衝區和漫射緩衝區進行一些調整。我們已經在燈光舞臺上這樣做了,但是如果您只保存了燈光強度,那麼您必須在這裏做一個簡單的diffuse * light組合。

通常只是一個全屏幕四邊形,將最終結果呈現在屏幕上。

更多的東西

  • 正如前面提到的,我們想擺脫的位置緩衝區。在投影中使用深度緩衝區來重建位置。
  • 你不需要需要使用光量。有些人喜歡簡單地渲染足夠大的四邊形以覆蓋屏幕上的區域。
  • 上面的示例不包括像如何爲每個對象定義唯一材質的問題。那裏有很多gbuffer格式的資源和變體。有些人喜歡在alpha通道中保存材質索引(在漫反射緩衝區中),然後在紋理中查找一行以獲取材質屬性。
  • 方向燈等光源類型影響整個場景可以很容易地通過渲染全屏幕的四成亮累積緩衝處理
  • 聚光燈也是不錯的,也很容易實現
  • 我們可能希望更多的光屬性
  • 我們可能想要某種方式來衡量漫射和光緩衝區如何組合以支持環境和發射
  • 有許多方法可以以更緊湊的方式存儲法線。例如,您可以使用球座標來刪除一個值。那裏有大量關於延期照明和gbuffer格式的文章。看看人們使用的格式可以給你一些想法。只要確保你的gbuffer不會太胖。
  • 使用線性化的深度值和您的投影來重建視圖位置並不難。您需要使用投影常量構造一個矢量。將其與您的深度值(0到1之間)相乘以獲得視圖位置。那裏有幾篇文章。這只是兩行代碼。

在這篇文章中可能有很多選擇,但希望它顯示了一般原則。沒有一個着色器被編譯。這只是由3.3記憶轉換爲1.2。

有幾種方法來光積累。您可能想要減少使用1000個立方體和錐體對VBO進行批處理繪製的繪製調用次數。隨着更多現代GL版本的使用,您還可以使用幾何着色器來計算可覆蓋每個燈光區域的四邊形。可能最好的方法是使用計算着色器,但這需要GL 4.3。這樣做的好處是你可以遍歷所有的燈光信息並做一次寫入。還有一些僞計算方法是將屏幕劃分爲粗糙網格併爲每個單元分配一個光源列表。這隻能使用片段着色器完成,但需要在CPU上構建燈光列表,並通過UBO將數據發送到着色器。

計算着色器方法是迄今爲止最簡單的一種。它消除了舊方法中的許多複雜性,以便跟蹤和組織一切。簡單地迭代燈光並對幀緩衝區進行單個寫入。

0

延遲渲染的基本思想是將網格的幾何變換爲目標幀緩衝區上的位置,併爲目標幀緩衝區的像素賦予它們的最終顏色。

第一步是以某種方式渲染幾何圖形,即幀緩衝區的每個像素都會接收有關原始幾何圖元的信息,即在任一世界或眼睛空間(眼睛空間是首選),變換切線空間,切線,副法線)以及其他屬性,具體取決於後面的要求。這是「幾何緩衝區」(回答你的問題)。

使用幾何緩衝區,預計算幾何→像素映射可以重複使用幾個相似的處理步驟。例如,如果要渲染50個光源,則必須僅處理幾何圖形50次(這等於渲染100個三角形,這是兒童玩現代GPU),其中每次迭代使用其他參數(光線位置,方向,影子緩衝區等)。這與普通的多通道渲染相反,每次迭代都需要重新處理整個幾何圖形。

當然可以被用於每遍呈現不同類型的陰影處理(輝光,模糊,虛化,光暈等)

然後,對於每一次迭代傳遞結果合併在一起成爲一個合成圖像。

+2

注意:您不應將NBT轉換存儲在幾何緩衝區中。您應該存儲從凹凸貼圖中獲取的* normal *(如果您正在做凹凸貼圖),或者從頂點着色器中插入。您還應該在光照過程中計算片段着色器中的位置,而不是從紋理中讀取它。 –

1

1)延遲着色包括將場景的幾何體以及基本上其他所有內容分離爲單獨的過程。

例如,當我想創建高光模糊和陰影紋理時,是否需要爲這些紋理中的每一個渲染場景。

對於陰影紋理,可能(如果您使用陰影映射,這是無法避免的)。但是,對於其他所有內容:

不,這就是爲什麼延遲着色可能非常有用。在延期管道中,您可以渲染一次幾何圖形,併爲每個像素保存顏色,法線和三維位置(幾何緩衝區)。這可以通過幾種不同的方式來實現,但最常見的是將幀緩衝區對象(FBOs)用於多個渲染目標(MRT)。當使用FBO進行延遲着色時,除了綁定FBO,在片段着色器中使用多個輸出(每個渲染目標都使用一個輸出)之外,您可以按照與正常渲染相同的方式渲染幾何,並且不計算任何光照。您可以在OpenGL網站或通過快速谷歌搜索閱讀關於FBO和MRT的更多信息。然後點亮你的場景,你會用着色器讀取這些數據,並用它來計算光照,就像你通常那樣。這樣做的最簡單方法(但不是最好的方法)是爲場景渲染全屏四邊形和樣本顏色,常規和位置紋理。

2)幾何緩衝區是將在場景中進行照明和其他陰影所需的所有數據。它在幾何傳遞過程中(唯一需要渲染幾何的時間)創建,通常是一組紋理。渲染幾何圖形時,每個紋理均用作渲染目標(請參閱上文關於FBO和MRT)。您通常有一個顏色紋理,一個用於法線,另一個用於3d位置。如有必要,它還可以包含更多數據(如照明參數)。這爲您提供了在光照過程中每個像素點亮所需的所有數據。

僞代碼看起來是這樣的:

for all geometry { 
     render to FBO 
    } 
    for all lights { 
     read FBO and do lighting 
    } 
    //... here you can read the FBO and use it for anything!