2014-04-16 80 views
6

在片段着色器中採樣全屏紋理的最佳方式是什麼,例如延遲渲染器中的g緩衝區或後處理着色器中的場景紋理?採樣全屏紋理的最佳方法

在我使用以下兩種方式的時刻:

  • 傳遞屏幕尺寸着色器作爲一個統一的,並從gl_FragCoord計算(U,V):

    vec2 texCoord = gl_FragCoord.xy/vScreenSize; 
    vec3 c = texture(tex, texCoord).rgb; 
    

    不由於需要劃分並且爲屏幕尺寸提供着色器是麻煩的,因此似乎是理想的。

  • gl_FragCoord.xy轉換成ivec並使用texelFetch

    vec3 c = texelFetch(tex, ivec2(gl_FragCoord.xy), 0).rgb; 
    

    此外,因爲需要從floatint轉換不理想。

那麼,有沒有更好的辦法?我真的只是想在我的像素着色器繪製的確切點上對緩衝區進行採樣。


//編輯:


好,用插值紋理座標是來自頂點着色器,我設法弄清楚下面的代碼的建議:

頂點着色器:

#version 150 

uniform mat4 im_ModelViewProjectionMatrix; 

in vec3 iv_Vertex; 
noperspective out vec2 vVertCoord; 

void main(void) 
{ 
    gl_Position = im_ModelViewProjectionMatrix * vec4(iv_Vertex, 1.0); 
    vVertCoord = (gl_Position.xy/gl_Position.w) * (0.5) + vec2(0.5); 
} 

我基本上是從剪輯空間計算標準化設備座標(NDC)然後將NDC(範圍從[-1,1])映射到區間[0,1]。這適用於全屏四邊形(即使沒有透視分割,因爲座標非常簡單)。我需要在我的延遲渲染器中繪製爲光幾何圖形的任意幾何圖形具有一些問題。在頂點着色器I輸出vVertCoord爲紅色= x和綠色= Y顏色:

#version 150 

noperspective in vec2 vVertCoord; 
out vec4 colorOut; 

void main(void) 
{ 
    colorOut = vec4(vVertCoord.x, vVertCoord.y, 0, 1); 
} 

這是結果,當我點光球裏,一切都看起來很好(黑線呈現上目的):

All fine

但是,如果我靠攏光幾何這是結果:

Not ok

左上角的紅色補丁在那裏做什麼?您不希望在禁用調試顏色的情況下查看實際顏色的結果,因爲它看起來像是lsd行程,當您移動相機時,一切都會變形。這與精度有關嗎?請注意,當我在像素着色器中使用gl_FragCoord時,一切正常。

+0

是否有任何特別的原因,爲什麼你的紋理座標是基於gl_FragCoord而不是一個正常的插值屬性?在第一個例子中,這已經不再需要這個部門了。附:而不是vScreenSize,你可以有屏幕尺寸的倒數(把分割變成一個乘法) –

+0

你可能不想要後者,這將消除做任何紋理過濾的可能性。雖然您可能認爲自己並不關心這一點,但在延遲着色引擎中,以不同的分辨率(特別是低端硬件,通常具有相當的填充率限制)進行G-Buffer生成和着色可能很有用。 –

回答

2

如果您只是從頂點着色器傳入插值頂點座標,則不必做任何特殊的數學運算。

例如,如果你繪製覆蓋你的屏幕一個簡單的單位正方形,你可以只和會再收到全屏質感,你可能只是做這樣的事情:

vertex shader pseudocode: 
layout(position = 0) in vec3 in_vertex; 
out vec3 out_vertex; 
void main() 
{ 
    //Do your matrix multiplications to your in_vertex to get its final position... 
    out_vertex = in_vertex; 
} 

你的頂點着色器然後將in_vertex正確地插入範圍x:0 ... 1,y:0 ... 1(只要你繪製一個單位正方形)並將它傳遞給你的片段着色器。然後,您的片段着色器將使用它像這樣:

fragment shader pseudocode: 
in vec3 out_vertex; 
uniform sampler2D tex; 
void main() 
{ 
    gl_fragcolor = texture(tex,vec2(out_vertex.x,out_vertex.y)); 
} 

不需要其它數學運算,只要你要小心,out_vertex將永遠只能是在範圍0 ... 1。爲了擴展這個例子有點,想象這裏是我們方:

(0,1)+-----------+(1,1) | | | | | | | | | | (0,0)+-----------+(0,1)

,我們想品嚐的正中央這一點:

(0,1)+-----------+(1,1) | | | | | * | | | | | (0,0)+-----------+(0,1)

我們的頂點着色器會自動插即從其他4個位置開始,並將以下vec3傳遞給片段着色器:

out_vertex = vec3(0.5,0.5,0); 

然後可以用它來成功地採樣紋理

+0

我相信你仍然需要在你的頂點着色器中設置'gl_Position'。如果你繪製一個單位正方形,就像@redsoxfantom建議的那樣,你可以使用'gl_Position = vec4(2.0 * out_vertex,0.0) - 1.0;'。你不需要任何矩陣乘法。讓我知道你是否需要更多的解釋和細節。評論中很難涵蓋它,但我可以將它作爲答案發布。 –

+0

好的答案,儘管我最終得到了一個不同的代碼,因爲我並不總是畫全屏四邊形,而且是光線幾何圖形,在這種情況下,頂點座標沒有多大用處。 – Marius