簡體   English   中英

如何在片段着色器中將gl_FragCoord轉換為世界空間點?

[英]How do I convert gl_FragCoord to a world space point in a fragment shader?

我的理解是,如果您具有視圖投影矩陣,屏幕寬度和屏幕高度的倒數,則可以將gl_FragCoord轉換為片段着色器中世界坐標的點。 首先,將屏幕空間的gl_FragCoord.xgl_FragCoord.y轉換為標准化的設備坐標,方法是分別除以寬度和高度,然后將其縮放並偏移到[-1,1]范圍內。 接下來,通過逆視圖投影矩陣進行變換,以得到僅當您除以w分量時才可以使用的世界空間點。

以下是我無法使用的片段着色器代碼。 注意, 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;

    // ...
}

首先,將gl_FragCoord.x和gl_FragCoord.y從屏幕空間轉換為規范化的設備坐標

同時忽略了NDC空間是三維空間 (窗口空間)這一事實。 您還忘記了從剪輯空間到NDC空間的轉換涉及到一個划分,您並未撤銷。 好吧,您確實嘗試過撤消它,但是在通過反向剪輯變換進行了變換之后。

取消頂點后處理轉換將使用gl_FragCoord所有四個組件(盡管您只需3個組件gl_FragCoord )。 第一步是撤消視口轉換,這需要訪問給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;

其中, viewport是一個統一形式,包含由glViewport函數指定的四個參數,其順序與給該函數的順序相同。

我發現了我的代碼存在的問題。 首先,正如Nicol所指出的,需要將glFragCoord.z (深度)從屏幕坐標上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;

    // ...
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM