I have the following C++ OpenGL code which renders the RGB values of pixels in a scene:
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, _windowWidth, _windowHeight);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
float aspectRatio = float(_windowWidth) / float(_windowHeight);
gluPerspective(60.0f, aspectRatio, 0.1f, 1000.0f);
glMatrixMode(GL_MODELVIEW);
_camera.Update();
glLoadMatrixf(_camera.Matrix()[0]);
_scene.Render();
glutSwapBuffers();
However, I would like to instead render the depth buffer of the scene, i.e. so that each pixels value is the z-distance in front of the camera.
That is, I am currently getting the top image but I want the bottom image (image from here):
How should I go about this? I don't think I'm using shaders (am I?) – and the advice given here seems to suggest this might only be possible with shaders.
There is also this code, although this too looks like it is using shaders. How difficult would it be to modify my code to use shaders?
You can slurp the depthbuffer to host memory via glReadPixels()
and GL_DEPTH_COMPONENT
and re-upload the buffer as a GL_LUMINANCE
texture:
#include <GL/glew.h>
#include <GL/glut.h>
#include <vector>
using namespace std;
void display()
{
int w = glutGet( GLUT_WINDOW_WIDTH );
int h = glutGet( GLUT_WINDOW_HEIGHT );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
double ar = w / static_cast< double >( h );
const float zNear = 0.1;
const float zFar = 10.0;
gluPerspective( 60, ar, zNear, zFar );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glTranslatef( 0, 0, -4 );
static float angle = 0;
angle += 3;
glPushMatrix();
glRotatef( angle, 0.1, 0.5, 0.3 );
glColor3ub( 255, 0, 0 );
glutSolidTeapot( 1 );
glPopMatrix();
vector< GLfloat > depth( w * h, 0 );
glReadPixels( 0, 0, w, h, GL_DEPTH_COMPONENT, GL_FLOAT, &depth[0] );
// linearize depth
// http://www.geeks3d.com/20091216/geexlab-how-to-visualize-the-depth-buffer-in-glsl/
for( size_t i = 0; i < depth.size(); ++i )
{
depth[i] = ( 2.0 * zNear ) / ( zFar + zNear - depth[i] * ( zFar - zNear ) );
}
static GLuint tex = 0;
if( tex > 0 )
glDeleteTextures( 1, &tex );
glGenTextures(1, &tex);
glBindTexture( GL_TEXTURE_2D, tex);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexImage2D( GL_TEXTURE_2D, 0, GL_LUMINANCE, w, h, 0, GL_LUMINANCE, GL_FLOAT, &depth[0] );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glOrtho( 0, w, 0, h, -1, 1 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glEnable( GL_TEXTURE_2D );
glColor3ub( 255, 255, 255 );
glScalef( 0.3, 0.3, 1 );
glBegin( GL_QUADS );
glTexCoord2i( 0, 0 );
glVertex2i( 0, 0 );
glTexCoord2i( 1, 0 );
glVertex2i( w, 0 );
glTexCoord2i( 1, 1 );
glVertex2i( w, h);
glTexCoord2i( 0, 1 );
glVertex2i( 0, h );
glEnd();
glDisable( GL_TEXTURE_2D );
glutSwapBuffers();
}
void timer( int value )
{
glutPostRedisplay();
glutTimerFunc( 16, timer, 0 );
}
int main( int argc, char **argv )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE );
glutInitWindowSize( 600, 600 );
glutCreateWindow( "GLUT" );
glewInit();
glutDisplayFunc( display );
glutTimerFunc( 0, timer, 0 );
glEnable( GL_DEPTH_TEST );
glutMainLoop();
return 0;
}
Round-tripping to the CPU isn't terribly fast (especially with the host-side linearization). You can use PBOs to make it a GPU-to-GPU transfer but you'll lose the linearization.
You can use Framebuffer Object (fbo) to render the depth values into texture. Then in a second rendering pass draw a quad over the whole viewport and apply depth texture on it.
Or you can write a fragment shader that will output fragments colors according to their depth, this can render in single pass.
See here some examples. You can find more searching for 'fbo'.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With