我的理解是,如果你有视图投影矩阵的反转,屏幕宽度和屏幕高度,你可以将gl_FragCoord转换为片段着色器中世界坐标的一个点.首先,在转换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;
// ...
}
Run Code Online (Sandbox Code Playgroud)
首先,将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功能,以相同的顺序作为给予该功能.