glReadPixels获得的深度缓冲区始终为1 [英] depth buffer got by glReadPixels is always 1
问题描述
我正在使用glReadPixels来获取选择像素的深度值,但是我总是得到1,我该如何解决呢?这是代码:
I'm using glReadPixels to get depth value of select pixel, but i always get 1, how can i solve it? here is the code:
glEnable(GL_DEPTH_TEST);
..
glReadPixels(x, viewport[3] - y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, z);
我想念什么吗?我的渲染部分如下所示.我使用不同的着色器绘制场景的不同部分,那么如何正确地从缓冲区读取深度值呢?
Do I miss anything? And my rendering part is shown below. I use different shaders to draw different part of scene, so how should i make it correct to read depth value from buffer?
void onDisplay(void)
{
// Clear the window and the depth buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// calculate the view matrix.
GLFrame eyeFrame;
eyeFrame.MoveUp(gb_eye_height);
eyeFrame.RotateWorld(gb_eye_theta * 3.1415926 / 180.0, 1.0, 0.0, 0.0);
eyeFrame.RotateWorld(gb_eye_phi * 3.1415926 / 180.0, 0.0, 1.0, 0.0);
eyeFrame.MoveForward(-gb_eye_radius);
eyeFrame.GetCameraMatrix(gb_hit_modelview);
gb_modelViewMatrix.PushMatrix(gb_hit_modelview);
// draw coordinate system
if(gb_bCoord)
{
DrawCoordinateAxis();
}
if(gb_bTexture)
{
GLfloat vEyeLight[] = { -100.0f, 100.0f, 150.0f };
GLfloat vAmbientColor[] = { 0.2f, 0.2f, 0.2f, 1.0f };
GLfloat vDiffuseColor[] = { 1.0f, 1.0f, 1.0f, 1.0f};
glUseProgram(normalMapShader);
glUniform4fv(locAmbient, 1, vAmbientColor);
glUniform4fv(locDiffuse, 1, vDiffuseColor);
glUniform3fv(locLight, 1, vEyeLight);
glUniform1i(locColorMap, 0);
glUniform1i(locNormalMap, 1);
gb_treeskl.Display(SetGeneralColor, SetSelectedColor, 0);
}
else
{
if(!gb_bOnlyVoxel)
{
if(gb_bPoints)
{
//GLfloat vPointColor[] = { 1.0, 1.0, 0.0, 0.6 };
GLfloat vPointColor[] = { 0.2, 0.0, 0.0, 0.9 };
gb_shaderManager.UseStockShader(GLT_SHADER_FLAT, gb_transformPipeline.GetModelViewProjectionMatrix(), vPointColor);
gb_treeskl.Display(NULL, NULL, 1);
}
if(gb_bSkeleton)
{
GLfloat vEyeLight[] = { -100.0f, 100.0f, 150.0f };
glUseProgram(adsPhongShader);
glUniform3fv(locLight, 1, vEyeLight);
gb_treeskl.Display(SetGeneralColor, SetSelectedColor, 0);
}
}
if(gb_bVoxel)
{
GLfloat vEyeLight[] = { -100.0f, 100.0f, 150.0f };
glUseProgram(adsPhongShader);
glUniform3fv(locLight, 1, vEyeLight);
SetVoxelColor();
glPolygonMode(GL_FRONT, GL_LINE);
glLineWidth(1.0f);
gb_treeskl.DisplayVoxel();
glPolygonMode(GL_FRONT, GL_FILL);
}
}
//glUniformMatrix4fv(locMVP, 1, GL_FALSE, gb_transformPipeline.GetModelViewProjectionMatrix());
//glUniformMatrix4fv(locMV, 1, GL_FALSE, gb_transformPipeline.GetModelViewMatrix());
//glUniformMatrix3fv(locNM, 1, GL_FALSE, gb_transformPipeline.GetNormalMatrix());
//gb_sphereBatch.Draw();
gb_modelViewMatrix.PopMatrix();
glutSwapBuffers();
}
推荐答案
我认为您没看错,唯一的问题是您没有将缓冲区的深度线性化回<znear...zfar>
范围,因此整个~1
值屏幕是由于深度的对数依赖性(几乎所有值都非常接近1).
I think you are reading correctly the only problem is that you are not linearize the depth from buffer back to <znear...zfar>
range hence the ~1
value for whole screen due to logarithmic dependence of depth (almost all the values are very close to 1).
我正在这样做:
double glReadDepth(double x,double y,double *per=NULL) // x,y [pixels], per[16]
{
GLfloat _z=0.0; double m[16],z,zFar,zNear;
if (per==NULL){ per=m; glGetDoublev(GL_PROJECTION_MATRIX,per); } // use actual perspective matrix if not passed
zFar =0.5*per[14]*(1.0-((per[10]-1.0)/(per[10]+1.0))); // compute zFar from perspective matrix
zNear=zFar*(per[10]+1.0)/(per[10]-1.0); // compute zNear from perspective matrix
glReadPixels(x,y,1,1,GL_DEPTH_COMPONENT,GL_FLOAT,&_z); // read depth value
z=_z; // logarithmic
z=(2.0*z)-1.0; // logarithmic NDC
z=(2.0*zNear*zFar)/(zFar+zNear-(z*(zFar-zNear))); // linear <zNear,zFar>
return -z;
}
不要忘了x,y
以像素为单位,(0,0)
以左下角为单位!!!! 返回的深度在<zNear,zFar>
范围内.该函数假定您正在使用像这样的透视变换:
Do not forget that x,y
is in pixels and (0,0)
is bottom left corner !!! The returned depth is in range <zNear,zFar>
. The function is assuming you are using perspective transform like this:
void glPerspective(double fovy,double aspect,double zNear,double zFar)
{
double per[16],f;
for (int i=0;i<16;i++) per[i]=0.0;
// original gluProjection
// f=divide(1.0,tan(0.5*fovy*deg))
// per[ 0]=f/aspect;
// per[ 5]=f;
// corrected gluProjection
f=divide(1.0,tan(0.5*fovy*deg*aspect));
per[ 0]=f;
per[ 5]=f*aspect;
// z range
per[10]=divide(zFar+zNear,zNear-zFar);
per[11]=-1.0;
per[14]=divide(2.0*zFar*zNear,zNear-zFar);
glLoadMatrixd(per);
}
请注意,只有在没有线性深度缓冲区的情况下,接近相机对象的深度精度才是好的.有关更多信息,请参见:
Beware the depth accuracy will be good only for close to camera object without linear depth buffer. For more info see:
如果问题仍然存在,则可能还有另一个原因.您是否有像素格式的深度缓冲区?在Windows中,您可以像这样检查:
If the problem persist there might be also another reason for this. Do you have Depth buffer in your pixel format? In windows You can check like this:
缺少深度缓冲区可以解释为什么值始终为1
(与~0.997
不同)的原因.在这种情况下,您需要更改窗口的初始化,为深度缓冲区(16/24/32
)启用一些位.参见:
Missing depth buffer could explain why the value is always 1
(not like ~0.997
). In such case you need to change the init of your window enabling some bits for depth buffer (16/24/32
). See:
有关使用此技术的更多详细信息(以C ++示例为例),请参见:
For more detailed info about using this technique (with C++ example) see:
这篇关于glReadPixels获得的深度缓冲区始终为1的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!