java - 将 OpenGL 深度缓冲区转换为距相机的世界空间 z 距离?

标签 java opengl jogl depth

我正在使用 Java OpenGL(JOGL 2.x,从 Git 源构建)。我正在将场景渲染到带有颜色和深度附件的帧缓冲区对象。我想将 [0,1] 深度缓冲区值转换为世界空间距离。我的深度附件定义如下:

    private void setupDepthFBOs(GL2 gl,
                            int width,
                            int height, 
                            int[] frameBufferIds,
                            int[] colorBufferIds,
                            int[] depthBufferIds) {        
    // based on
    // http://www.java2s.com/Code/Java/Advanced-Graphics/BloomOpenGL.htm
    //  generate a framebuffer object
    gl.glGenFramebuffers(1, frameBufferIds, 0);
    // bind the framebuffer
    gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, frameBufferIds[0]);

    // generate a texture in memory
    gl.glGenTextures(1, colorBufferIds,0);
    gl.glBindTexture(GL2.GL_TEXTURE_2D, colorBufferIds[0]);
    // this will be an RGBA texture (4 bpp) with width, height..
    gl.glTexImage2D(GL2.GL_TEXTURE_2D,      // target texture type
            0,          // mipmap LOD level
            GL2.GL_RGBA8,           // internal pixel format
            width,          // width of generated image
            height,         // height of generated image
            0,          // border of image
            GL2.GL_RGBA,        // external pixel format 
            GL2.GL_UNSIGNED_BYTE,   // datatype for each value
            null);  // buffer to store the texture in memory

    // set some texture parameters?
    gl.glTexParameteri(GL.GL_TEXTURE_2D, 
                       GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);

    // use the texture we just created in the framebuffer we just created
    gl.glFramebufferTexture2D(
            GL2.GL_FRAMEBUFFER,         // target texture type
            GL.GL_COLOR_ATTACHMENT0,    // attachment point
            GL.GL_TEXTURE_2D,           // texture target type
            colorBufferIds[0],          // on-gpu id for texture 
            0);                         // mipmap lod level

    gl.glGenTextures(1,depthBufferIds,0);
    gl.glBindTexture(GL.GL_TEXTURE_2D,depthBufferIds[0]);
    gl.glTexImage2D(GL2.GL_TEXTURE_2D,          // target texture type
            0,                          // mipmap LOD level
            GL2.GL_DEPTH_COMPONENT24,   // internal pixel format
                    //GL2.GL_DEPTH_COMPONENT
            width,                      // width of generated image
            height,                     // height of generated image
            0,                          // border of image
            GL2.GL_DEPTH_COMPONENT,     // external pixel format 
            GL2.GL_UNSIGNED_INT,        // datatype for each value
            null);  // buffer to store the texture in memory


    gl.glTexParameteri(GL.GL_TEXTURE_2D,
                       GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST);
    gl.glTexParameteri(GL.GL_TEXTURE_2D,
                       GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST);
    gl.glTexParameteri(GL.GL_TEXTURE_2D, 
                       GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE);
    gl.glTexParameteri(GL.GL_TEXTURE_2D, 
                       GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE);

    gl.glFramebufferTexture2D(GL.GL_FRAMEBUFFER,
                              GL.GL_DEPTH_ATTACHMENT,
                              GL.GL_TEXTURE_2D,
                              depthBufferIds[0],0);


    gl.glBindTexture(GL.GL_TEXTURE_2D, 0);

    int status = gl.glCheckFramebufferStatus(GL2.GL_FRAMEBUFFER);


    if (status == GL2.GL_FRAMEBUFFER_COMPLETE) {
        gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0);
    } else {
        throw new IllegalStateException("Frame Buffer Object not created. Status was: " + status);
    }

}

这成功创建了一个深度缓冲区,我可以将其作为纹理读取并渲染到屏幕上,或者用作着色器的输入(我预期的最终用例)。

前几天晚上在 IRC 上进行了一些讨论后,我得出了以下公式,将投影矩阵(此处表示为 p)和深度缓冲区值与世界空间中屏幕上每个点的距离相关联:

z = (p_33)/(p_34 + 深度)

(注意:我的投影矩阵/眼睛设置为朝 Z+ 方向看)

这会产生几乎正常的 z 值,但到场景中已知点的距离与该方程返回的值之间存在很大的误差范围。

你知道我在这里可能做错了什么吗?

最佳答案

这是我的计算,我的结果与你的不同:

定义:

depth = out_z / out_w
out_z = in_z * p_33 + in_w * p_43
out_w = in_z * p_34 + in_w * p_44

已知:

in_w = 1, p_43 = -1, p_44 = 0

工作:

depth = (in_z * p_33 - 1) / (in_z * p_34)
depth = p_33 / p_34 - 1 / (in_z * p_34)
p_33 / p_34 - depth = 1 / (in_z * p_34)
1 / (p_33 / p_34 - depth) = in_z * p_34
1 / (p_33 / p_34 - depth) = in_z * p_34
1 / (p_33 - depth * p_34) = in_z

关于java - 将 OpenGL 深度缓冲区转换为距相机的世界空间 z 距离?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8158347/

相关文章:

java - 将BaseGameUtils添加到libgdx项目时出现问题

java - 正在解析 .obj 文件 : How to do materials/textures?

Java JOGL : How can create an image using both GL and Graphics?

c++ - OpenGL 在我的电脑上性能低下

java - JOGL 中顶点缓冲区对象的问题

java - 硬币找零 - 寻找最大数量

java - JExcel : Losing Cell Precison On Cells Having Formula ROUNDUP in MS Excel

java - 如何在 Java 中使用 Selenium WebDriver 单击列表中的链接

java - 使用OpenGL和3D建模软件之间的区别

c++ - openGL视频显示