Преобразовать буфер глубины OpenGL в z-расстояние мирового пространства от камеры? - PullRequest
0 голосов
/ 17 ноября 2011

Я использую 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) и значение буфера глубины с расстоянием до каждой точки на экране вworld-space:

z = (p_33) / (p_34 + глубина)

(примечание: матрица проекции / глаз настроены, глядя в направлении Z +)

Это приводит к почти нормальным z-значениям, но существует значительный предел погрешности между расстоянием до известных точек в сцене и значением, возвращаемым этим уравнением.

Есть идеи, что я мог бы сделать неправильно?

1 Ответ

3 голосов
/ 17 ноября 2011

Вот мои расчеты, мой результат отличается от вашего:

Определение:

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
...