Некоторое время я пытался найти способ прочитать значение глубины для определенной координаты мыши (x, y). Все хорошо работает на win10 с opengl 4.x, но не для opengl es 3.x
Мои подходы:
последующего метода было бы достаточно, но, к сожалению, слишком неточно, также на 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);
Причины:
Может быть, кто-то может мне помочь и решить узел, потому что я не могу найти другого объяснения?
Вот некоторые измеренные значения:
zc 0.984314
zd 0.985363
zc 0.552941
zd 0.554653
zc 1 -> extremly critical
zd 0.999181
Поскольку 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);
Я до сих пор не знаю с уверенностью, является ли 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.
Похоже, что значение в буфере глубины не совсем совпадает с 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.