如何将gl_FragCoord转换为片段着色器中的世界空间点?

Bry*_*man 1 opengl glsl

我的理解是,如果你有视图投影矩阵的反转,屏幕宽度和屏幕高度,你可以将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;

    // ...
}
Run Code Online (Sandbox Code Playgroud)

Nic*_*las 5

首先,将gl_FragCoord.x和gl_FragCoord.y从屏幕空间转换为规范化设备坐标

同时忽略了NDC空间是三维的事实(就像窗口空间一样).您还忘记了从剪辑空间到NDC空间的转换涉及一个除法,您没有撤消.好吧,你有点尝试撤消它,但是在通过反向剪辑转换进行转换之后.

撤消顶点后处理转换使用了所有四个组件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;
Run Code Online (Sandbox Code Playgroud)

其中viewport是包含由指定的四个参数的均匀glViewport功能,以相同的顺序作为给予该功能.

  • @travnik:完成。 (2认同)