OpenGL:从GLSL中的窗口空间坐标计算眼睛空间坐标?

时间:2011-04-14 20:30:34

标签: opengl glsl

如何从窗口空间(帧缓冲区中的像素)坐标+ GLSL中的像素深度值计算眼睛空间坐标(GLSL中的gluUnproject可以这么说)?

5 个答案:

答案 0 :(得分:3)

看起来与GLSL convert gl_FragCoord.z into eye-space z重复。

编辑(完整答案):

// input: x_coord, y_coord, samplerDepth
vec2 xy = vec2(x_coord,y_coord); //in [0,1] range
vec4 v_screen = vec4(xy, texture(samplerDepth,xy), 1.0 );
vec4 v_homo = inverse(gl_ProjectionMatrix) * 2.0*(v_screen-vec4(0.5));
vec3 v_eye = v_homo.xyz / v_homo.w; //transfer from homogeneous coordinates

答案 1 :(得分:2)

假设您坚持使用固定的管道式模型,视图和投影,您可以完全实现gluUnProject man page中给出的公式。

GLSL中没有内置矩阵反转,所以理想情况下你就是在CPU上。因此,您需要提供组合的modelViewProjection矩阵的逆的一致性。 gl_FragCoord位于窗口坐标中,因此您还需要提供视图尺寸。

所以,你最终可能会得到类似的东西(即席编码):

vec4 unProjectedPosition = invertedModelViewProjection * vec4( 
               2.0 * (gl_FragCoord.x - view[0]) / view[2] - 1.0, 
               2.0 * (gl_FragCoord.y - view[1]) / view[3] - 1.0,
               2.0 * gl_FragCoord.z - 1.0,
               1.0);

如果您已经实现了自己的旧矩阵堆栈的模拟,那么您可能很好地反转矩阵。否则,它可能比您预期的more daunting topic更好,您可能最好使用MESA的open source implementation(参见invert_matrix,该文件中的第三个函数),只是因为它经过了很好的测试,如果没有别的。

答案 2 :(得分:0)

嗯,一个关于opengl.org的人指出,投影产生的剪辑空间坐标除以clipPos.w来计算规范化的设备坐标。当将片段从ndc上的步骤反转到剪辑空间坐标时,您需要重建那个w(恰好是相应的视图空间(相机)坐标中的-z),并将ndc坐标与该值相乘以计算正确的剪辑空间坐标(可以通过将其与反投影矩阵相乘来转换为视图空间坐标)。

以下代码假定您正在后期处理中处理帧缓冲区。在渲染几何体时处理它时,可以使用gl_FragCoord.z而不是texture2D(sceneDepth,ndcPos.xy).r。

以下是代码:

uniform sampler2D sceneDepth;
uniform mat4 projectionInverse;
uniform vec2 clipPlanes; // zNear, zFar
uniform vec2 windowSize; // window width, height

#define ZNEAR clipPlanes.x
#define ZFAR clipPlanes.y

#define A (ZNEAR + ZFAR)
#define B (ZNEAR - ZFAR)
#define C (2.0 * ZNEAR * ZFAR)
#define D (ndcPos.z * B)
#define ZEYE -(C / (A + D))

void main() 
{
vec3 ndcPos;
ndcPos.xy = gl_FragCoord.xy / windowSize;
ndcPos.z = texture2D (sceneDepth, ndcPos.xy).r; // or gl_FragCoord.z
ndcPos -= 0.5;
ndcPos *= 2.0;
vec4 clipPos;
clipPos.w = -ZEYE;
clipPos.xyz = ndcPos * clipPos.w;
vec4 eyePos = projectionInverse * clipPos;
}

基本上这是gluUnproject的GLSL版本。

答案 3 :(得分:0)

我刚才意识到在片段着色器中进行这些计算是不必要的。您可以通过在CPU上执行此操作并将其与MVP反转相乘来保存一些操作(假设glDepthRange(0, 1),可随意编辑):

glm::vec4 vp(left, right, width, height);
glm::mat4 viewportMat = glm::translate(
    vec3(-2.0 * vp.x / vp.z - 1.0, -2.0 * vp.y / vp.w - 1.0, -1.0))
  * glm::scale(glm::vec3(2.0 / vp.z, 2.0 / vp.w, 2.0));
glm::mat4 mvpInv = inverse(mvp);
glm::mat4 vmvpInv = mvpInv * viewportMat;
shader->uniform("vmvpInv", vmvpInv);

在着色器中:

vec4 eyePos = vmvpInv * vec4(gl_FragCoord.xyz, 1);
vec3 pos = eyePos.xyz / eyePos.w;

答案 4 :(得分:0)

我认为所有可用的答案都是从一个方面触及问题,khronos.org有一个Wiki页面,其中列出了几个不同的案例,并用着色器代码进行了解释,因此值得在此处发布。 Compute eye space from window space