Writing in the depth buffer ?

Hello,

Is it possible to write in the depth buffer ? With DrawPixel ?

My goal is to update only objects selected by the user and the rest of the scene is display only one time, saved on buffers (color and depth components).

This is possible because the camera doesn’t move. Whould please to share with me to smart idea to program such scenario ?

Thank !

stencil buffer?

[edit] forget about that. my typing was faster than my thinking.

Use GL_DEPTH_COMPONENT as format parameter in glDrawPixels and disable color write to fill the depth buffer with the saved values.

Then do the same with GL_RGBA and disable depth write do load the saved color image.

The disabling is important, because per default glDrawPixels will always override depth and color, no matter what the internal format says.

Be sure to test the performance of this. This will only be faster than re-drawing the scene if your saved image contains really complex geometry (e.g. pre-rendered high resolution data). For most scenes, just redrawing them would be faster.

“The disabling is important, because per default glDrawPixels will always override depth and color, no matter what the internal format says.”

More precisely glDrawPixels is using the informations from the glRasterPos to generate color or depth informations.
If the type is color, it will not override depth, it will correctly depth test. It’s not enough to disable depth writes if you don’t want any depth testing against what you rendered before, you need to disable depth test which makes depth mask irrelevant.

I still have the same problem… It doesn’t work and its becomes very slow (6 FPS instead of 400 FPS) Just when I comment the first DrawPixels…

glDepthMask(GL_TRUE);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glDrawPixels(g_WindowWidth, g_WindowHeight, GL_DEPTH_COMPONENT, GL_FLOAT, g_DepthBuffer);

glDepthMask(GL_FALSE);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDrawPixels(g_WindowWidth, g_WindowHeight, GL_RGBA, GL_UNSIGNED_BYTE, g_ColorBuffer);

What do you mean, it doesn’t work? What’s the error?

Did you disable the depth test before this code, as Relic suggested?

Have you made sure that the glDrawPixels is the problem? Perhaps the data itself is corrupt.

The speed drop is expected, although I didn’t think it would be that big. An alternative for the color is drawing a fullscreen textured quad. For the depth you’ll have to write a shader that replaces z from a texture.

As I said, the scene would have to be really complex for this to be faster than just redrawing it each frame.

Almost of all my sample code, if it helps:

#include “sample.h”
#ifdef WIN32
#include “windows.h”
#endif
#include <GL/gl.h>
#include <glm/glmext.h>

typedef unsigned char uint8;

using namespace glm;

int g_WindowWidth = 0;
int g_WindowHeight = 0;

float* g_DepthBuffer = NULL;
uint8* g_ColorBuffer = NULL;

namespace
{
// GL_QUADS
glm::vec3 SolidPosition[] =
{
glm::vec3(-1,-1,-1),
glm::vec3(-1, 1,-1),
glm::vec3( 1, 1,-1),
glm::vec3( 1,-1,-1),

	glm::vec3(-1,-1, 1),
	glm::vec3( 1,-1, 1),
	glm::vec3( 1, 1, 1),
	glm::vec3(-1, 1, 1),

	glm::vec3(-1,-1,-1),
	glm::vec3( 1,-1,-1),
	glm::vec3( 1,-1, 1),
	glm::vec3(-1,-1, 1),

	glm::vec3(-1, 1,-1),
	glm::vec3(-1, 1, 1),
	glm::vec3( 1, 1, 1),
	glm::vec3( 1, 1,-1),

	glm::vec3( 1,-1,-1),
	glm::vec3( 1, 1,-1),
	glm::vec3( 1, 1, 1),
	glm::vec3( 1,-1, 1),

	glm::vec3(-1,-1,-1),
	glm::vec3(-1,-1, 1),
	glm::vec3(-1, 1, 1),
	glm::vec3(-1, 1,-1)
};

glm::vec3 SolidNormal[] =
{
	glm::vec3( 0, 0, 1),
	glm::vec3( 0, 0, 1),
	glm::vec3( 0, 0, 1),
	glm::vec3( 0, 0, 1),

	glm::vec3( 0, 0,-1),
	glm::vec3( 0, 0,-1),
	glm::vec3( 0, 0,-1),
	glm::vec3( 0, 0,-1),

	glm::vec3( 0, 1, 0),
	glm::vec3( 0, 1, 0),
	glm::vec3( 0, 1, 0),
	glm::vec3( 0, 1, 0),

	glm::vec3( 0,-1, 0),
	glm::vec3( 0,-1, 0),
	glm::vec3( 0,-1, 0),
	glm::vec3( 0,-1, 0),

	glm::vec3(-1, 0, 0),
	glm::vec3(-1, 0, 0),
	glm::vec3(-1, 0, 0),
	glm::vec3(-1, 0, 0),

	glm::vec3( 1, 0, 0),
	glm::vec3( 1, 0, 0),
	glm::vec3( 1, 0, 0),
	glm::vec3( 1, 0, 0)
};

}

void Begin(int Width, int Height)
{
g_WindowWidth = Width;
g_WindowHeight = Height;

if(g_DepthBuffer == NULL)
	g_DepthBuffer = new float[Width * Height * 1];
if(g_ColorBuffer == NULL)
	g_ColorBuffer = new uint8[Width * Height * 4];

glEnable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Set projection matrix
glMatrixMode(GL_PROJECTION);
//glLoadMatrixf(perspectiveGTX(45.0f, 640.0f / 480.0f, 0.1f, 100.0f));
glLoadIdentity();

// Set modelview matrix
mat4 Projection = perspectiveGTX(45.0f, 640.0f / 480.0f, 0.1f, 100.0f);
mat4 View = translateGTX(0.0f, 0.0f,-8.0f);

// First object
mat4 Model1 = rotateGTX(45.f, 0.0f, 0.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(Projection * View * Model1);
glNormalPointer(GL_FLOAT, 0, &SolidNormal[0]);
glVertexPointer(3, GL_FLOAT, 0, &SolidPosition[0]);

glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);

glColor3f(1.0f, 0.5f, 0.0f);
glDrawArrays(GL_QUADS, 0, 24);

glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glFinish();
glReadPixels(0, 0, g_WindowWidth, g_WindowHeight, GL_DEPTH_COMPONENT, GL_FLOAT, g_DepthBuffer);

glReadPixels(0, 0, g_WindowWidth, g_WindowHeight, GL_RGBA, GL_UNSIGNED_BYTE, g_ColorBuffer);
glFinish();

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

}

void End()
{
delete[] g_DepthBuffer;
g_DepthBuffer = NULL;

delete[] g_ColorBuffer;
g_ColorBuffer = NULL;

}

void Render(float CurrentTime)
{
glClear(GL_DEPTH_BUFFER_BIT);
// Set modelview matrix
mat4 Projection = perspectiveGTX(45.0f, 640.0f / 480.0f, 0.1f, 100.0f);
mat4 View = translateGTX(0.0f, 0.0f,-8.0f);

glEnable(GL_DEPTH_TEST);

/*
// First object
//mat4 Model1 = glm::mat4(1.0f);//rotateGTX(CurrentTime * 1.f, 0.0f, 1.0f, 1.0f);
mat4 Model1 = rotateGTX(45.f, 0.0f, 0.0f, 1.0f);

glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);

glMatrixMode(GL_PROJECTION);
glLoadMatrixf(Projection);

glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(View * Model1);

glNormalPointer(GL_FLOAT, 0, &SolidNormal[0]);
glVertexPointer(3, GL_FLOAT, 0, &SolidPosition[0]);

glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);

glColor3f(1.0f, 0.5f, 0.0f);
glDrawArrays(GL_QUADS, 0, 24);

glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);

*/

glDisable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);

mat4 Ortho = glm::ortho2DGTX(0.f, 320.f, 0.f, 240.f);
glMatrixMode(GL_PROJECTION);
//glLoadIdentity();
glLoadMatrixf(Ortho);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

glRasterPos2i(0, 0);
glDepthMask(GL_TRUE);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
//glDrawPixels(g_WindowWidth, g_WindowHeight, GL_DEPTH_COMPONENT, GL_FLOAT, g_DepthBuffer);

glDepthMask(GL_FALSE);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDrawPixels(g_WindowWidth, g_WindowHeight, GL_RGBA, GL_UNSIGNED_BYTE, g_ColorBuffer);

glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);

// Second object
mat4 Model2 = rotateGTX(rotateGTX(translateGTX(0.0f, 0.0f, 0.0f), CurrentTime * 10.f, 0.0f, 0.0f, 1.0f), CurrentTime * 20.f, 1.0f, 1.0f, 0.0f);

glMatrixMode(GL_PROJECTION);
glLoadMatrixf(Projection);

glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(View * Model2);

glNormalPointer(GL_FLOAT, 0, &SolidNormal[0]);
glVertexPointer(3, GL_FLOAT, 0, &SolidPosition[0]);

glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);

glColor3f(1.0f, 0.0f, 1.0f);
glDrawArrays(GL_QUADS, 0, 24);

glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);

glFinish();

// Error
int Error = glGetError();
if(Error)
	printf("OpenGL Error: %d

", Error);
}

Yes, this should be used for complex scene with large meshes.

I mean, the saved scene is always recover be the selected object… As the depth buffer have been cleared.

The most obvious problem is reading and writing the depth buffer as GL_FLOAT and the color as GL_RGBA.

Internally depth is packed 32-bit data, containing 24-bit depth and 8-bit stencil.
The format which matches this best is GL_UNSIGNED_INT. This just requires shift and mask operations to recover the 24-bit depth at the right location.
Use 24-bit depth buffers and GL_UNSIGNED_INT for your gl*Pixels.
Data of fixed type buffers is always shifted to the most significant bits in the user data. (You don’t need to care here.)

Second, GL_RGBA is not the native color format for 8-bit channel color formats on NVIDIA HW, You should use GL_BGRA for the color in your case. (This is different for floating point buffers.)

Read this:
http://developer.nvidia.com/object/fast_texture_transfers.html
and this:
http://developer.nvidia.com/object/gpu_programming_guide.html

BUT, if you just want to save and restore pixel data without ever accessing it, there is an extension for exactly that: WGL_ARB_buffer_region here
http://www.opengl.org/registry/specs/ARB/wgl_buffer_region.txt

Mind the OpenGL pixel ownership test (read the OpenGL 2.1 spec Chapter 4.1.1 “Pixel Ownership Test”) on all these pixel read operations.

You could also render everything into FBOs as backing store, which won’t have pixel ownership problems, and update using the EXT_framebuffer_blit extension.

Never use glFinish unless you must, and there is no reason for it in your code.