如何在片段着色器中将gl_FragCoord转换为世界空间点? [英] How do I convert gl_FragCoord to a world space point in a fragment shader?

查看:221
本文介绍了如何在片段着色器中将gl_FragCoord转换为世界空间点?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的理解是,如果您具有视图投影矩阵,屏幕宽度和屏幕高度的逆值,则可以在片段着色器中将gl_FragCoord转换为世界坐标中的一个点.首先,将屏幕空间中的gl_FragCoord.xgl_FragCoord.y分别通过除以宽度和高度,然后将它们缩放并偏移到[-1,1]范围内,将其转换为规范化的设备坐标.接下来,通过逆视图投影矩阵进行变换,以获取仅当您除以w分量时才可以使用的世界空间点.

My understanding is that you can convert gl_FragCoord to a point in world coordinates in the fragment shader if you have the inverse of the view projection matrix, the screen width, and the screen height. First, you convert gl_FragCoord.x and gl_FragCoord.y from screen space to normalized device coordinates by dividing by the width and height respectively, then scaling and offsetting them into the range [-1, 1]. Next you transform by the inverse view projection matrix to get a world space point that you can use only if you divide by the w component.

下面是我无法使用的片段着色器代码.注意inverse_proj实际上设置为逆视图投影矩阵:

Below is the fragment shader code I have that isn't working. Note inverse_proj is actually set to the inverse view projection matrix:

#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从屏幕空间转换为规范化的设备坐标

First, you convert gl_FragCoord.x and gl_FragCoord.y from screen space to normalized device coordinates

同时忽略NDC空间是三维(窗口空间)这一事实.您还忘记了从片段空间到NDC空间的转换涉及到一个划分,您并未撤销.好吧,您确实尝试过撤消它,但是在通过反向剪辑变换进行了变换之后.

While simultaneously ignoring the fact that NDC space is three-dimensional (as is window space). You also forgot that the transformation from clip-space to NDC space involved a division, which you did not undo. Well, you did kinda try to undo it, but after transforming by the inverse clip transformation.

撤消顶点后处理转换使用gl_FragCoord的所有四个组件(尽管您只需支付3就可以了).第一步是撤消视口变换,这需要访问赋予glDepthRange的参数.

Undoing the vertex post-processing transformations use all four components of gl_FragCoord (though you could make due with just 3). The first step is undoing the viewport transform, which requires getting access to the parameters given to glDepthRange.

这将为您提供NDC坐标.然后,您必须撤消透视图鸿沟. gl_FragCoord.w的值为1/clipW. clipW是该操作的除数.因此,您用gl_FragCoord.w除以返回剪辑空间.

That gives you the NDC coordinate. Then you have to undo the perspective divide. gl_FragCoord.w is given the value 1/clipW. And clipW was the divisor in that operation. So you divide by gl_FragCoord.w to get back into clip space.

从那里,您可以乘以投影矩阵的倒数.尽管如果您想要世界空间,则您要反转的投影矩阵必须是一个到投影的世界,而不仅仅是纯粹的投影(通常是从摄影机到投影).

From there, you can multiply by the inverse of the projection matrix. Though if you want world-space, the projection matrix you invert must be a world-to-projection, rather than just pure projection (which is normally camera-to-projection).

代码内:

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函数,以与该功能相同的顺序.

Where viewport is a uniform containing the four parameters specified by the glViewport function, in the same order as given to that function.

这篇关于如何在片段着色器中将gl_FragCoord转换为世界空间点?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆