Почему в opengl отклоняется gl_FragCoord.z ​​от буфера глубины? - PullRequest
0 голосов
/ 26 апреля 2018

Я некоторое время пытался найти способ прочитать значение глубины для определенной координаты мыши (x, y). Все отлично работает на win10 с opengl 4.x, но не для opengl es 3.x

Мои подходы:

  1. glReadPixels () не работает на openGL для буфера глубины
  2. приведение лучей не подходит, потому что я работаю с большой моделью местности
  3. последующий метод будет достаточным, но, к сожалению, слишком неточным, также на win10, но почему?

    #version 420
    uniform vec2 screenXy;
    uniform vec2 screenSize;
    
    out vec4 fragColor;
    
    void main(void) {
    
    if((int(gl_FragCoord.x) == int(screenXy.x)) && ((int(screenSize.y) - int(gl_FragCoord.y)) == int(screenXy.y))) {
        fragColor.r = gl_FragCoord.z;
        } else {
            fragColor = vec4(1, 1, 1, 1.0);
        }
    }
    

Я передаю координаты xy мыши в fragementshader (screenXy). Если выбранный пиксель находится в строке, я записываю значение глубины в буфер цвета. Это работает, но значение gl_FragCoord.z ​​и значение из буфера глубины не совсем совпадают (я знаю, что это значение из буфера глубины является правильным). Хотя gl_FragCoord.z ​​и значение буфера глубины - это float, и я думаю, что 32-битный.

GLfloat zd; // from depth buffer
GLfloat zc[4]; // from color buffer
m_func->glReadPixels(xy.x(), m_pFbo->height() - xy.y(), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &zd);
m_func->glReadPixels(xy.x(), m_pFbo->height() - xy.y(), 1, 1, GL_RGBA, GL_FLOAT, zc);

Причины:

  1. отклонение происходит за счет внутреннего преобразования типа, но где?
  2. потому что GL_DEPTH_TEST выполняется после фрагмента шейдера gl_FragCoord.z ​​не ближайший (к камере), но который сохраняется в буфере глубины. Поэтому не имеет смысла сохранять gl_FragCoord.z ​​в отдельном Frambuffer, потому что это неверное значение.

Может быть, кто-то может мне помочь и решить узел, потому что я не могу найти другого объяснения?

Вот некоторые измеренные значения:

zc  0.984314
zd  0.985363

zc  0.552941
zd  0.554653

zc  1 -> extremly critical
zd  0.999181

Ответы [ 3 ]

0 голосов
/ 27 апреля 2018

Я до сих пор не знаю точно, является ли gl_FragCoord.z ​​таким же, как в буфере глубины после теста глубины. Со счетчиком вы можете сделать запрос

if(gl_FragCoord.z_last > gl_FragCoord.z)
    fragColor.z = gl_FragCoord.z;

так в основном то, что делает тест глубины. но как хранить gl_FragCoord.z_last как статический? Есть ли способ без потерь прочитать значение глубины в openGL 3.x? Согласно solidpixel, существует только плавающий кадровый буфер из opengl 3.2.

0 голосов
/ 27 апреля 2018

Кажется, что значение в буфере глубины не совпадает с gl_FragCoord.z. Я думаю, что следующий пример демонстрирует это.

#version 420

uniform vec4 color;
uniform vec2 screenXy;
uniform vec2 screenSize;

in vec2 vBC;

out vec4 fragColor;

void main(void) {

fragColor.r = gl_FragCoord.z;

}

C ++

GLfloat zd;
GLubyte zc[4];
m_func->glReadPixels(xy.x(), m_pFbo->height() - xy.y(), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &zd);
m_func->glReadPixels(xy.x(), m_pFbo->height() - xy.y(), 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, zc);

Данные: zc0 = 255 (из gl_FragCoord.z); zd = 0,996561 (из буфера глубины)

Но это должно быть 254, потому что 0.996561 * 255 = 254.123055.

0 голосов
/ 26 апреля 2018

Поскольку 0,984314 * 255,0 - это ровно 251,0, я предполагаю, что внутренний формат цветовой плоскости - GL_RGBA8. Это означает, что для каждого цветового канала имеется 1 байт, и zc может иметь только 256 различных значений, от 0,0 до 1,0 с шагом 1/256.

Если это поддерживается версией OpenGL ES, которую вы используете, то вы можете изменить формат хранилища буфера рендеринга (например, GL_R32F - только канал красного цвета, но 32-битная плавающая точка).

Или вы можете закодировать глубину для 4 каналов цветовой плоскости 4 * 8 бит:

vec4 PackDepth( in float depth )
{
    depth *= (256.0*256.0*256.0 - 1.0) / (256.0*256.0*256.0);
    vec4 encode = fract( depth * vec4(1.0, 256.0, 256.0*256.0, 256.0*256.0*256.0) );
    return vec4( encode.xyz - encode.yzw / 256.0, encode.w ) + 1.0/512.0;
}

....

fragColor = PackDepth(gl_FragCoord.z);

И вы можете расшифровать его после прочтения значения:

GLfloat zc[4]; // from color buffer
m_func->glReadPixels(xy.x(), m_pFbo->height() - xy.y(), 1, 1, GL_RGBA, GL_FLOAT, zc);

float depth = zc[0] + zc[1]/256.0 + zc[2]/(256.0*256.0) + zc[3]/(256.0*256.0*256.0);
depth = depth * (255.0f/256.0f) * (256.0*256.0*256.0) / (256.0*256.0*256.0 - 1.0);
...