2016-08-14 214 views
1

我的理解是,如果您具有視圖投影矩陣,屏幕寬度和屏幕高度的反轉,則可以將gl_FragCoord轉換爲片段着色器中世界座標中的點。首先,將gl_FragCoord.xgl_FragCoord.y從屏幕空間轉換爲標準化的設備座標,方法是分別除以寬度和高度,然後縮放並將它們偏移到[-1,1]範圍內。接下來,通過逆視投影矩陣進行變換,得到一個世界空間點,只有在用w分量除以後才能使用該點。如何將gl_FragCoord轉換爲片段着色器中的世界空間點?

下面是片段着色器代碼我有不工作。注意inverse_proj實際上被設爲逆視圖投影矩陣:

#version 450 

uniform mat4 inverse_proj; 
uniform float screen_width; 
uniform float screen_height; 

out vec4 fragment; 

void main() 
{ 
    // Convert screen coordinates to normalized device coordinates (NDC) 
    vec4 ndc = vec4(
     (gl_FragCoord.x/screen_width - 0.5) * 2, 
     (gl_FragCoord.y/screen_height - 0.5) * 2, 
     0, 
     1); 

    // Convert NDC throuch inverse clip coordinates to view coordinates 
    vec4 clip = inverse_proj * ndc; 
    vec3 view = (1/ndc.w * clip).xyz; 

    // ... 
} 
+0

通過從頂點着色器變化的世界位置變得更容易(更高效)。 – BDL

回答

4

首先,你從屏幕空間歸一化裝置轉換gl_FragCoord.x和gl_FragCoord.y座標

,同時忽略了一個事實該NDC空間是三維(如窗口空間)。你也忘了從剪輯空間到NDC空間的轉換涉及到一個你沒有撤消的分割。那麼,你確實有點嘗試撤消它,但在通過逆剪輯變換進行變換之後。

撤銷vertex post-processing transformations使用gl_FragCoord的所有四個組件(儘管您只需3個組件即可完成)。第一步是撤消視口變換,這需要訪問給出的參數glDepthRange

這給你NDC座標。那麼你必須撤消視角鴻溝。 gl_FragCoord.w的值爲1/clipW。 clipW是該操作中的除數。所以你除以gl_FragCoord.w回到剪輯空間。

從那裏,你可以乘以投影矩陣的逆。雖然如果你想要世界空間,你反轉的投影矩陣必須是世界到投影,而不僅僅是純粹的投影(通常是相機到投影)。

在代碼:

vec4 ndcPos; 
ndcPos.xy = ((2.0 * gl_FragCoord.xy) - (2.0 * viewport.xy))/(viewport.zw) - 1; 
ndcPos.z = (2.0 * gl_FragCoord.z - gl_DepthRange.near - gl_DepthRange.far)/
    (gl_DepthRange.far - gl_DepthRange.near); 
ndcPos.w = 1.0; 

vec4 clipPos = ndcPos/gl_FragCoord.w; 
vec4 eyePos = invPersMatrix * clipPos; 
0

我想通了問題,我的代碼。首先,正如Nicol指出的那樣,glFragCoord.z(深度)需要從屏幕座標轉移。此外,我寫了1/ndc.w * clip而不是clip/clip.w的原始代碼存在錯誤。

然而,正如BDL所指出的那樣,將世界位置作爲變化傳遞給片段着色器會更有效率。但是,以下代碼是完全通過片段着色器實現所需結果的簡短方法(例如,對於每個片段沒有世界位置的屏幕空間程序,並且您希望每個片段具有視圖向量)。

#version 450 

uniform mat4 inverse_view_proj; 
uniform float screen_width; 
uniform float screen_height; 

out vec4 fragment; 

void main() 
{ 
    // Convert screen coordinates to normalized device coordinates (NDC) 
    vec4 ndc = vec4(
     (gl_FragCoord.x/screen_width - 0.5) * 2.0, 
     (gl_FragCoord.y/screen_height - 0.5) * 2.0, 
     (gl_FragCoord.z - 0.5) * 2.0, 
     1.0); 

    // Convert NDC throuch inverse clip coordinates to view coordinates 
    vec4 clip = inverse_view_proj * ndc; 
    vec3 vertex = (clip/clip.w).xyz; 

    // ... 
} 
相關問題