2011-07-20 257 views
3

我正在OpenGL中進行陰影映射 - 因此我創建了一個幀緩衝區對象,在此處我從光源視圖渲染場景的深度。OpenGL - 幀緩衝區深度紋理與顏色深度紋理有所不同

glBindRenderbuffer(GL_RENDERBUFFER, color_buffer); 
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, width, height); 
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, color_buffer); 

glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer); 
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height); 
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_buffer); 

glGenTextures(1, &color_texture); 
glBindTexture(GL_TEXTURE_2D, color_texture); 
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color_texture, 0); 

glGenTextures(1, &depth_texture); 
glBindTexture(GL_TEXTURE_2D, depth_texture); 
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_texture, 0); 

然後,這就像正常情況一樣,從光線的角度呈現場景,完全如您所料。唯一的補充是我使用自定義着色器將場景的深度也渲染到「color_texture」。

varying vec4 screen_position; 

void main() 
{ 
    screen_position = gl_ModelViewProjectionMatrix * gl_Vertex; 
    gl_Position = screen_position; 
} 

-------------- 

varying vec4 screen_position; 

void main() 
{ 
    float depth = screen_position.z/screen_position.w; 
    gl_FragColor = vec4(depth, depth, depth, 1.0); 
} 

我可以使用全屏四元組將這兩個紋理「color_texture」和「depth_texture」寫入屏幕。這兩個確實是深度圖,看起來是正確的。現在這個奇怪的位。

實際上渲染對象上的陰影取樣時,「color_texture」深度可以正常工作,但當切換到「depth_texture」採樣時,深度因某個比例和某個常數而不同。

當我爲這個採樣深度添加了一些模糊因子數字時,我可以使它起作用,但這確實很困難,而且感覺很糟糕。

我真的不知道什麼是錯的,從技術上說,兩個紋理採樣時應該是相同的。由於RGB的準確性,我無法繼續使用「color_texture」。我真的需要切換,但我不能爲我的生活找出爲什麼深度紋理給出不同的價值。

我已經編程過幾次陰影映射,它不是一個新的概念。

任何人都可以對此有所瞭解嗎?

回答

6

您的着色器存在一些問題。首先,screen_position不是屏幕位置;這是剪輯空間頂點位置。屏幕空間將與您的顯示器相關,因此如果您移動窗口,則會發生變化。你永遠不會獲得任何屏幕空間位置; OpenGL只下到窗口空間(相對於窗口的位置)。

其次,這樣的:

float depth = screen_position.z/screen_position.w; 

不計算深度。它計算歸一化設備座標(NDC)空間Z位置,範圍從[-1,1]。深度是一個窗口空間值,它是在NDC空間值通過視口轉換(由glViewport和glDepthRange指定)轉換之後發生的。該變換將深度置於[0,1]範圍內。

最重要的是第三,你手動完成這一切;讓GLSL爲你做:

void main() 
{ 
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; 
} 

-------------- 

void main() 
{ 
    gl_FragColor = vec4(gl_FragCoord.zzz, 1.0); 
} 

看到了嗎?好多了。

現在:

當涉及到實際渲染上採樣「color_texture」深度工作正常,但是當我切換到取樣「depth_texture」,深度是由一些規模和一些不同的物體陰影不變。

當然是了。這是因爲您認爲深度是NDC Z值。 OpenGL將實際的窗口空間Z值寫入深度。所以你需要使用窗口空間。 OpenGL很好,可以提供一些uniforms to your fragment shader來使這更容易。您可以使用這些制服將NDC空間Z值轉換爲窗口空間Z值。

+0

感謝您的好評!你能否解釋NDC Z值與窗口深度的區別?投影矩陣中已經提供了前端和近端剪切平面,所以深度範圍肯定不會有差別? 它是簡單地將[-1,1]映射到[0,1]還是它爲浮點精度做了一些縮放或者什麼?我明白如何使用glViewport將x和y座標縮放到窗口空間中。也許我缺少深度的東西。 無論哪種方式非常感謝,我相信我現在可以開始工作。 –

+0

@Daniel:深度範圍定義了Z位置從NDC空間到窗口空間的映射。所以如果你使用'glDepthRange(0.0,0.5)',那麼你只能得到範圍[0,0.5]的深度值。因此,在進行陰影映射比較時,您必須尊重深度範圍。 –