Opengl 如何将gl_FragCoord转换为片段着色器中的世界空间点?
我的理解是,如果有视图投影矩阵、屏幕宽度和屏幕高度的倒数,可以将gl_FragCoord转换为片段着色器中的世界坐标点。首先,通过分别除以宽度和高度,将Opengl 如何将gl_FragCoord转换为片段着色器中的世界空间点?,opengl,glsl,Opengl,Glsl,我的理解是,如果有视图投影矩阵、屏幕宽度和屏幕高度的倒数,可以将gl_FragCoord转换为片段着色器中的世界坐标点。首先,通过分别除以宽度和高度,将gl_FragCoord.x和gl_FragCoord.y从屏幕空间转换为标准化设备坐标,然后将其缩放和偏移到范围[-1,1]。接下来,通过逆视图投影矩阵进行变换,以获得仅当除以w分量时才能使用的世界空间点 下面是我的片段着色器代码,它不起作用。注inverse_proj实际上设置为逆视图投影矩阵: #version 450 uniform m
gl_FragCoord.x
和gl_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个组件)。第一步是撤消视口变换,这需要访问给定给gldeptrange
的参数
这就给出了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
是一个统一体,包含由指定的四个参数,其顺序与给定给该函数的顺序相同。我解决了代码中的问题。首先,正如Nicol所指出的,glFragCoord.z
(深度)需要从屏幕坐标进行移动。另外,我在原始代码中编写了1/ndc.w*clip
而不是clip/clip.w
,这是一个错误
但是,正如BDL所指出的,将世界位置作为一个变量传递给片段着色器会更有效。但是,下面的代码是完全通过片段着色器实现所需结果的一种简单方法(例如,对于屏幕空间程序,没有每个片段的世界位置,您需要每个片段的视图向量)
通过一个不同于顶点着色器的变量传递世界位置会更容易(也更有效)。嗨,尼科尔,请你解释一下什么是
视口
变量以及它是如何定义的?@travnik:Done。
#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;
// ...
}