2013-07-15 36 views
1

我一直在OpenGL中使用SSAO。我決定從OpenGL中的this教程中爲我的延遲渲染器實現SSAO。不幸的是我一直無法讓它工作得很好。取決於相機的位置,SSAO變暗的區域變化很大。我知道當相機移動時,SSAO的輸出可能會有一些變化,但這比我在其他SSAO實現中觀察到的要大得多。SSAO用相機角度顯着改變

這裏是片段着色器代碼

void main() { 

    vec3 origin = positionFromDepth(texture2D(gDepth, samplePosition)); 
    vec3 normal = texture2D(gNormal, samplePosition).xyz; //multiplying this 
//by 2 and subtracting 1 doesn't seem to help 
    vec2 random = getRandom(samplePosition); 

    float radius = uRadius/origin.z; 
    float occlusion = 0.0; 
    int iterations = samples/4; 

    for (int i = 0; i<iterations; i++) { 
     vec2 coord1 = reflect(kernel[i], random)*radius; 
     vec2 coord2 = vec2(coord1.x*0.707 - coord1.y*0.707, coord1.x*0.707 + coord1.y*0.707); 
     occlusion += occlude(samplePosition, coord1 * 0.25, origin, normal); 
     occlusion += occlude(samplePosition, coord2 * 0.50, origin, normal); 
     occlusion += occlude(samplePosition, coord1 * 0.75, origin, normal); 
     occlusion += occlude(samplePosition, coord2, origin, normal); 
    } 

    color = vec4(origin, 1); 

} 

positionFromDepth()功能:

vec3 positionFromDepth(float depth) { 
    float near = frustrumData.x; 
    float far = frustrumData.y; 
    float right = frustrumData.z; 
    float top = frustrumData.w; 
    vec2 ndc;   
    vec3 eye;    
    eye.z = near * far/((depth * (far - near)) - far); 
    ndc.x = ((gl_FragCoord.x/buffersize.x) - 0.5) * 2.0; 
    ndc.y = ((gl_FragCoord.y/buffersize.y) - 0.5) * 2.0; 
    eye.x = (-ndc.x * eye.z) * right/near; 
    eye.y = (-ndc.y * eye.z) * top/near; 
    return eye; 
} 

而且occlude()功能:

float occlude(vec2 uv, vec2 offsetUV, vec3 origin, vec3 normal) { 
    vec3 diff = positionFromDepth(texture2D(gDepth,(uv+offsetUV)))-origin; 
    vec3 vec = normalize(diff); 
    float dist = length(diff)/scale; 
    return max(0.0,dot(normal,vec)-bias)*(1.0/(1.0+dist))*intensity; 
} 

我有一種感覺問題可能是在positionFromDepth()函數,除了我用th e相同的代碼,用於完美渲染的渲染器的光照階段(我認爲)。我已經完成了這個代碼一千次,並沒有發現任何突出的錯誤。我已經嘗試了各種值bias,radius,intenistyscale,但這似乎不是問題。我很擔心無論我法線或立場是錯誤的,所以這裏是其中的一些屏幕截圖:

重建的位置: enter image description here 和正常緩衝: enter image description here

我將包括遮擋的圖像緩衝區,但這個問題大多隻在相機移動時才顯而易見,圖像無法顯示。

有沒有人有任何想法這裏有什麼問題?

+0

嗨!我遇到了執行相同教程的相同問題。你能告訴我,你是否管理過這個,你做了什麼? – TomatoMato

回答

3

奇怪的是,乘以2並減去1對您的法線貼圖沒有幫助。這通常是爲了克服與以無符號/歸一化紋理格式存儲法線相關的問題。除非正常的G緩衝區是有符號/非正常化的格式,否則當您第一次寫入時可能需要使用* 0.5 + 0.5並且在採樣紋理時使用* 2.0 - 1.0來打開和解壓法線。

在任何情況下,有多種SSAO方法,許多甚至不使用曲面法線。因此,關於存儲法線的矢量空間的討論經常被忽略。

我強烈懷疑你的法線是在視野空間而不是世界空間。如果你用頂點着色器中的「普通矩陣」乘以法線,就像許多教程要做的那樣,那麼你的法線就會在視圖空間中。

事實證明,視圖空間法線實際上並沒有那麼有用,現今使用世界空間法線可以更好地處理後期處理效果。大多數現代的延遲着色引擎(例如虛幻引擎4,CryEngine 3等)將常規G緩衝區存儲在世界空間中,然後將其轉換爲像素着色器中的視圖空間(如果需要)。


順便說,我已經包括一些代碼,我使用以重構從傳統的深度緩衝器中的對象空間中的位置。您似乎正在使用視圖空間位置/法線。你可能想嘗試在對象/世界空間的一切。

 
flat in mat4 inv_mv_mat; 
    in vec2 uv; 

... 

float linearZ (float z) 
{ 
#ifdef INVERT_NEAR_FAR 
    const float f = 2.5; 
    const float n = 25000.0; 
#else 
    const float f = 25000.0; 
    const float n = 2.5; 
#endif 

    return n/(f - z * (f - n)) * f; 
} 

vec4 
reconstruct_pos (in float depth) 
{ 
    depth = linearZ (depth); 

    vec4 pos = vec4 (uv * depth, -depth, 1.0); 
    vec4 ret = (inv_mv_mat * pos); 

    return ret/ret.w; 
} 

這需要一些額外的設置在延遲着色照明通的頂點着色器階段,它看起來像這樣:

 
#version 150 core 

in  vec4 vtx_pos; 
in  vec2 vtx_st; 

uniform mat4 modelview_mat; // Matrix used when the G-Buffer was built 
uniform mat4 camera_matrix; // Matrix used to stretch the G-Buffer over the viewport 

uniform float buffer_res_x; 
uniform float buffer_res_y; 

    out vec2 tex_st; 
flat out mat4 inv_mv_mat; 
    out vec2 uv; 


// Hard-Coded 45 degree FOV 
//const float fovy = 0.78539818525314331; // NV pukes on the line below! 
//const float fovy = radians (45.0); 
//const float tan_half_fovy = tan (fovy * 0.5); 

const float tan_half_fovy = 0.41421356797218323; 

     float aspect  = buffer_res_x/buffer_res_y; 
     vec2 inv_focal_len = vec2 (tan_half_fovy * aspect, 
            tan_half_fovy); 

const vec2 uv_scale  = vec2 (2.0, 2.0); 
const vec2 uv_translate = vec2 (1.0, 1.0); 


void main (void) 
{ 
    inv_mv_mat = inverse (modelview_mat); 
    tex_st  = vtx_st; 
    gl_Position = camera_matrix * vtx_pos; 
    uv   = (vtx_st * uv_scale - uv_translate) * inv_focal_len; 
} 
+0

感謝您的回答!看着你的'reconstruct_pos'函數幫了很大忙。它看起來像我的問題是使用gl_Fragcoord而不是像素使用uv。 (使用gl_Fragcoord意味着每個樣本都有相同的x和y,這是錯誤的。)但是我仍然對法線的打包和解包感到困惑。爲什麼有必要? – Spaceman1701

+0

您需要打包和解壓法線,因爲「​​正常」紋理不能存儲範圍在0.0-1.0以外的值。有紋理格式允許這樣做,但通常您的G-Buffer和法線貼圖本身都存儲在簡單的無符號標準化紋理(有時稱爲unorm)中。法線,特別是如果它們在世界空間中,可能具有負值的組件,因此將它們存儲爲這些紋理格式需要重新縮放和偏置(例如* 2 - 1) –

+0

這很有道理,但爲什麼我會將法線存儲在世界空間然後?在視圖空間中,法線不可能是負數,這意味着我不必打包它們,我的精度就會提高。我不明白爲什麼世界空間法線會更好。 – Spaceman1701