How to save a depth buffer to image file (as greyscale)?

Post your questions, suggestions and experiences regarding to Image manipulation, 3d modeling and level editing for the Irrlicht engine here.
Post Reply
drhenry
Posts: 16
Joined: Fri Mar 26, 2010 8:03 am

How to save a depth buffer to image file (as greyscale)?

Post by drhenry »

Hi everybody,
I'm new to Irrlicht and like to know, how you can save a depth buffer texture as a greyscale image file.

The depth buffer was created by

Code: Select all

DepthRTT = driver->addRenderTargetTexture(ScreenRTTSize, "depthRTT", ECF_R32F);
The following code only saves a red colored image, because of format (where "texture" is the depth texture):

Code: Select all

void* imageData = texture->lock(true);
IImage* im = driver->createImageFromData(texture->getColorFormat(), texture->getSize(), imageData);
driver->writeImageToFile(im, filename);
im->drop();
texture->unlock();
terier
Posts: 34
Joined: Sun Oct 05, 2008 4:46 pm

Post by terier »

Grayscale depth buffer is pretty much useless, because it can only store 8 bit values. Your buffer should store the z values in the red channel and their exponential part in the green channel (you could also make use of the blue channel, but it's not necessary), so that it can be decyphered like this:

Code: Select all

z = color.r + (color.g) / 256.0
Found something like this in XEffects documentation :D ...
BlindSide
Admin
Posts: 2821
Joined: Thu Dec 08, 2005 9:09 am
Location: NZ!

Post by BlindSide »

Hey, you can change the format to ECF_A8R8G8B8

and then alter the last line of the shader to:

Code: Select all

gl_FragColor = vec4(depth);
(OGL)

and

Code: Select all

return float4(depth);
(D3D)

But yeah, you won't get very nice precision like this. If you plan to use it externally maybe its best to encode it like terier said, and then when you load it decode it like he said. But be careful you don't store the exponential part in the green channel, that's for VSM. In the green channel just store fract(depth / 255.0) * 255.0.
ShadowMapping for Irrlicht!: Get it here
Need help? Come on the IRC!: #irrlicht on irc://irc.freenode.net
terier
Posts: 34
Joined: Sun Oct 05, 2008 4:46 pm

Post by terier »

BlindSide wrote:But be careful you don't store the exponential part in the green channel, that's for VSM. In the green channel just store fract(depth / 255.0) * 255.0.
Sorry, my bad. I meant to say fractional part, not exponential :oops:
drhenry
Posts: 16
Joined: Fri Mar 26, 2010 8:03 am

Post by drhenry »

I don't want to use the depth map externally. I'd like to save it so that I can have a look at it later on (for some kind of debugging).

Ok, if I create the depth texture as ECF_G32R32F, I'll have to decode depth in the shader via

Code: Select all

vec4 texDepth = texture2D(DepthMapSampler, coords);
float depth = (texDepth.r + (texDepth.g / 255.0));
right?
BTW: does anyone know, where the ENCODING of the depth happens in the XEffects project? Or does Irrlicht do this internally when an object is rendered to a depth render target of format ECF_G32R32F?

However, I still don't know, how I can save this texture to a file on HD...?

In combination with a depth texture of format ECF_R32F, I already tried the following code, which stores only a completely black image:

Code: Select all

	u32 col = 0;
	unsigned int texWidth = texture->getSize().Width;
	unsigned int texHeight = texture->getSize().Height;
	IImage* im = driver->createImage(ECF_R8G8B8, texture->getSize());
	float* imageData = (float*)texture->lock(true);
	if (imageData)
	{
		for (unsigned int y=0; y < texHeight; y++)
		{
			for (unsigned int x=0; x < texWidth; x++)
			{
				col = clamp<u32>(255.0 * imageData[y * texWidth + x], 0, 255);
				im->setPixel(x, y, SColor(255, col, col, col));
			}
		}
		driver->writeImageToFile(im, filename);
		texture->unlock();
		im->drop();
	}
	else
		std::cout << "ERROR: could not lock texture data" << std::endl;
BlindSide
Admin
Posts: 2821
Joined: Thu Dec 08, 2005 9:09 am
Location: NZ!

Post by BlindSide »

Just use ECF_A8R8G8B8 if you want to view it.
ShadowMapping for Irrlicht!: Get it here
Need help? Come on the IRC!: #irrlicht on irc://irc.freenode.net
drhenry
Posts: 16
Joined: Fri Mar 26, 2010 8:03 am

Post by drhenry »

Thanks. Ok, as you already mentioned, because of the low depth precision of 8 bit you can't even distinguish the objects from each other in the resulting image file.
Is there any way to get such a nice grey scale image like in http://en.9jcg.com/comm_pages/blog_content-art-168.htm?
BlindSide
Admin
Posts: 2821
Joined: Thu Dec 08, 2005 9:09 am
Location: NZ!

Post by BlindSide »

Umm. That image is 8 bits. You're monitor has 32 bit color display, which is 8 bits per channel (RGBA). Hence if you want to LOOK at it, it has to be 8 bits which is low precision for actual useful calculations.

If you can't distinguish them then there's another reason for that, perhaps you should reduce your far value.
ShadowMapping for Irrlicht!: Get it here
Need help? Come on the IRC!: #irrlicht on irc://irc.freenode.net
stefbuet
Competition winner
Posts: 495
Joined: Sun Dec 09, 2007 4:13 pm
Location: france

Post by stefbuet »

The depth map is from 0 to 1 where 1 is the camera far value.
If you're looking at close objects as the previous webpage screenshot, then you won't see a lot of things because it will be much dark and the color range will be too small to disctinct different objects. If you want your depth map for debug purpose only you can try to multiply the depth value like this or reduce camera far value:

depth*=10.0; //+ or -
gl_FragColor=vec4(depth, depth, depth, 1.0);
Post Reply