【问题标题】:OpenGL: Compute eye space coord from window space coord in GLSL?OpenGL:从 GLSL 中的窗口空间坐标计算眼睛空间坐标?
【发布时间】:2011-08-05 20:56:12
【问题描述】:

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

【问题讨论】:

    标签: opengl glsl


    【解决方案1】:

    看起来与 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
    

    【讨论】:

    • 我已阅读您对该问题的回复。首先,我不只是想重建 z。然后您的回复包含看似完全不相关的内容,即您在一个代码行中使用了一些变量,而这些变量从未在以下代码行中被引用。当我读到那篇文章时,我问自己在发布该回复时您一直在吸烟。 (j/k) ;-)
    • @karx11erx:答案并没有你说的那么糟糕,但我在这里放了一个固定版本供你参考。
    • 啊酷。谢谢。我觉得还是不太对。您从深度缓冲区中获取 v_screen,然后在下一行中使用 read_depth。我认为它们是相同的。问题是,我没有原始的投影矩阵。我想要做的是在渲染整个帧之后在后期处理中应用阴影贴图。所以我有一个带有颜色和深度缓冲区以及阴影贴图的 FBO。但它并不完全有效。详情见这里:opengl.org/discussion_boards/…
    • 啊,我看到你在这里编辑了你的代码。我指的是您链接到的另一个问题。
    【解决方案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),因为它已经过良好测试。

    【讨论】:

    • 这与 glGetIntegerv 为 GL_VIEWPORT 返回的值相同。您还应该按照下面的 kvark 精神修改我的答案: invert 出现在我似乎熟悉的更新版本的 GLSL 规范中。不过,您可能不想每个片段都这样做,因为它会非常昂贵。
    • 谢谢。所以查看 [0 .. 3] = 左、右、下、上?我有一个矩阵求逆函数,没问题。实际上我已经在使用它了(有关详细信息,请参阅我对 kvark 评论的回复)。
    • 是的,这听起来是对的——因此您将 x 和 y 转换为 [-1, 1] 范围内的数字以覆盖整个轴。我实际上是在转录链接的手册页的内容,以便提供完整的详细信息,很抱歉在我的回答中留下了“查看”的含义有点模糊。
    【解决方案3】:

    好吧,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;
    }
    

    基本上这是一个 GLSL 版本的 gluUnproject。

    【讨论】:

      【解决方案4】:

      我刚刚意识到没有必要在片段着色器中进行这些计算。您可以通过在 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;
      

      【讨论】:

        【解决方案5】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-12-28
          • 2020-08-15
          • 2013-08-10
          • 2011-06-22
          • 2011-12-27
          • 2019-10-19
          • 1970-01-01
          相关资源
          最近更新 更多