Почему в opengl отклоняется gl_FragCoord.z ​​от буфера глубины?

Некоторое время я пытался найти способ прочитать значение глубины для определенной координаты мыши (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

2

Решение

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

Если это поддерживается версией OpenGL ES, которую вы используете, вы можете изменить формат буфера рендеринга (например, g. 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);
2

Другие решения

Я до сих пор не знаю с уверенностью, является ли 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

Похоже, что значение в буфере глубины не совсем совпадает с 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
По вопросам рекламы [email protected]