2014-10-02 128 views
5

我一直試圖按照this教程的指示實現屏幕空間環境遮擋。當我遇到他們時,我一直在處理與我的實施有關的問題,但是這一個讓我目前陷入了困境。OpenGL:將視空間座標投影到NDC,看起來在[-1,1]範圍外的結果

我對該方法的理解如下。環境閉塞因子由取自與給定片段的法線對齊的半球內的樣品確定。爲了確定樣本是否對環境遮擋因素有貢獻,我必須根據視圖空間深度紋理(包含在本文圖像的左下角)檢查樣本的視圖空間深度。因此,我知道從深度紋理中獲取哪個座標,我必須將樣本的座標從視圖空間轉換爲標準化的設備座標(範圍[-1,1]),然後範圍[0 ,1],所以深度紋理有效地「映射」到視口。

下面的圖像是我的環境遮擋在我的場景上。我知道我對環境遮擋本身(我認爲半球面向不正確)有一個相當明顯的問題,我將及時處理,但是目前令我好奇的是什麼讓遮擋物的外觀被「縮小」 ',這表明我從視野樣本座標移動到紋理座標的操作是不正確的。

enter image description here

因爲我缺乏一個穩定的着色器的調試器,我可以做調試僅限於我可以呈現在屏幕上。下一個圖像用下面的代碼創建的,與國家數據中心的歸一化裝置座標對於給定的樣品:

if (ndcs.x > 1.0f || ndcs.y > 1.0f || ndcs.x < -1.0f || ndcs.y < -1.0f) 
{ 
    gl_FragColor = vec4(1.0f, 0.0f, 0.0f, 1.0f); 
} 
else 
{ 
    gl_FragColor = vec4(vec3(1.0f), 1.0f); 
} 

enter image description here

我期望圖像是完全白色(或者說,我正在使用這個着色器),但是它似乎表明我創建的NDC不在[-1,1]範圍內,我相信這肯定是不正確的。這不是在屏幕的相同區域或者,你可以在下圖中看到的相機是非常接近的表面:

enter image description here

我從來沒有使用此過程之前獲得國家數據中心,所以我我確定我的邏輯在某個地方肯定是錯的。我已經下載了本教程提供的演示代碼,並且我看不到代碼的不同之處。我也在網上進行了搜索(包括在這個網站上),我似乎無法找到任何症狀與我自己完全相同的人。

下面是從我着色器的相關代碼:

韋爾着色器:

v_eye_space_position = u_mvpMatrix * a_position; 
v_world_space_normal = normalize(u_rotationMatrix * a_normal); 
v_eye_space_normal = normalize(u_mvpMatrix * a_normal); 
gl_Position = v_eye_space_position; 

破片着色器:

// --- SSAO Testing --- 
// Convert from the noise texture back to [-1,1] range 
// We want the noise texture to tile across the screen. 
vec3 kernel_rotation = (texture2D(s_noise, gl_FragCoord.xy * u_noise_scale) * 2.0f - 1.0f).xyz; 
vec3 eye_space_tangent = normalize(kernel_rotation - v_eye_space_normal.xyz * dot(kernel_rotation, v_eye_space_normal.xyz)); 
vec3 eye_space_bitangent = cross(v_eye_space_normal.xyz, eye_space_tangent); 
mat3 tbn = mat3(eye_space_tangent, eye_space_bitangent, v_eye_space_normal); 

float ambient_occlusion = 0.0f; 
const float hemisphere_radius = 0.05f; 

for (int i=0; i<16; i++) 
{ 
    vec3 kernel_sample = tbn * u_ssao_kernel[i]; 
    kernel_sample = kernel_sample * hemisphere_radius + v_eye_space_position.xyz; 

    // Project the sample position into screen space. 
    vec4 offset = vec4(kernel_sample, 1.0f); 
    offset = u_projection_matrix * offset; 
    offset.xy /= offset.w; 
    vec4 ndcs = offset; 
    offset.xy = 1.0f - (offset.xy * 0.5f + 0.5f); 

    // Find the depth at this sample point. 
    float sample_depth = texture2D(s_camera_depth, offset.xy).z; 

    // Check if the sample point is occluded. 
    float range_check = 0.0f; 

    float linear_eye_space_position = (v_eye_space_position.z - u_near_plane)/(u_far_plane - u_near_plane); 

    // Range check. 
    if (abs(linear_eye_space_position - sample_depth) < hemisphere_radius) 
    { 
    range_check = 1.0f; 
    } 

    float linear_kernel_sample_depth = (kernel_sample.z - u_near_plane)/(u_far_plane - u_near_plane); 
    if (sample_depth <= linear_kernel_sample_depth) 
    { 
    ambient_occlusion += 1.0f * range_check; 
    } 
} 

// Average and invert the ambient occlusion. 
ambient_occlusion = 1.0f - (ambient_occlusion/16.0f); 

我已經看了隔離每一個元素,我不能看到他們的問題。

  • 我susbstituted片段了自己的看法空間位置到 投影(而不是樣品的看法空間位置),我也得到 相同的結果。
  • 投影矩陣是我 使用轉換模型的頂點的投影矩陣(我已經構造了MVP 矩陣在我的頂點着色器,以確保投影矩陣是 達到機智的着色器程序,它是)。
  • 投影操作本身 - 這不是我以前做過的事情,但我已經在線閱讀 文章,以及投影問題的人 的問題,我看不出我做錯了什麼。

因此,我只能得出這樣的結論:我對透視投影的理解有一定的基礎性,這是有缺陷的,但我無法弄清楚是什麼。如果你們中的任何一個人都可以對這個問題或我進一步檢查的途徑有所瞭解,我會非常感激。如果有任何有用的信息我已經省略或我可以澄清的任何內容,請讓我知道。

回答

2

從你的頂點着色器:

v_eye_space_position = u_mvpMatrix * a_position; 
[...] 

pMatrix * a_normal); gl_Position = v_eye_space_position;

從這一點,我們可以看到,v_eye_space_position頂點的視角空間位置,但夾空間的位置,這也需要被分配到gl_Position。你的矩陣制服的neame也表明這是ModelView-Matrix。

在你的片段着色器中,你基本上是通過投影矩陣再次(因爲你似乎認爲它是在眼睛空間中)而產生的結果。

所以正確的代碼是:現在

v_eye_space_position = u_mvMatrix * a_position; 
[...] 
gl_Position = u_projection_matrix * v_eye_space_position; 

,您可以在投影再次在片段着色器適用於v_eye_space_position。但我的問題是:爲什麼再這樣做?如果你想在屏幕空間工作,gl_FragCoord已經在窗口空間。只需通過反轉視口(和深度範圍)變換,就可以從窗口空間到NDC獲得多重添加。

+0

非常感謝你的幫助。實施你的建議後,結果是我的預期。我很迷惑我怎麼把自己弄糊塗成這樣一個簡單的錯誤。獲得的經驗:總是檢查'簡單'的東西(特別是座標空間)。非常感謝 - 你已經爲我解除了巨大的壓力。祝你今天愉快! :) – 2014-10-03 07:37:24