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

Я использую 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-значения, но существует значительная погрешность между расстоянием до известных точек сцены и значением, возвращаемым этим уравнением.

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


person Alterscape    schedule 16.11.2011    source источник
comment
Пожалуйста, покажите, как вы настраиваете проекционную матрицу с фактическими значениями. Кроме того, вы уверены, что вам нужно расстояние z в пространстве мира, а не расстояние z в пространстве глаз? Последнее обычно имеет больше смысла для того, что вы делаете.   -  person bernie    schedule 17.11.2011


Ответы (1)


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

Определено:

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
person Hannesh    schedule 16.11.2011