Access Z-buffer and save it as file

Hi all,
i’m new user of Blender.
I need to access Z-buffer because I need to use the deistances from the objects in the scene to the camera. Now, I can only get a image in grey-scale that gives me the object’s depth but I would like save the value of each pixel in a matrix or array and save it in a file .txt
I wonder if there is a script that does that. Otherwise, how can I write a script which does it?

Thanks for your help!!!

Hi, I want to do the same thing. I think a possible way is render an EXR image and then extract the Z channel… If anybody know any other solutions, please help us!

If I’m not mistaken you can save the z-buffer to an image, using the nodes editor. After that it’s a simple matter of reading the values and writing them to a text file.

Alternatively you could use the z-buffer of the 3d-view. Here’s some code to do that:

import Blender
from Blender import *
from Blender.BGL import *

windows = Window.GetScreenInfo()
for w in windows:
    if w['type'] == Window.Types.VIEW3D:
        xmin, ymin, xmax, ymax = w['vertices']
        width = xmax-xmin
        height = ymax-ymin

zbuf = Buffer(GL_FLOAT, [width*height])
glReadPixels(xmin, ymin, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, zbuf)

strbuf = []
for i in range(height):
    strbuf.append(str(zbuf[i*width:i*width+width]))
strbuf.reverse()

file = open("C:/test.txt", "w")
for i in strbuf:
    file.write(i[1:-1]+'
')
file.close()

Some remarks:
This doesn’t work in wireframe and bounding box mode (viewport shading methods).
It’s best to have only one 3d-view when running the script.
It could be that the z-depth of the grid is also output, so you might want to disable it.

Many thanks for your answer! But i need to have a correlation between the image render (variable image size) and the z depth pixel to pixel, and I’m afraid that with glReadPixels isn’t possible. The EXR image format seems perfect for me, with an EXR viewer I can read the Z channel value referred to the pixel under the cursor. But I haven’t found nothing for saving z-values on text file. However thanks!

ok, I’m not real comfortable with python (I mostly code in c…I could have coded a seq plugin to do the same thing in 1/4 the time it took me to learn enough python to do this) but this will give you a txt file with an array filled with the distance from the camera to each pixel in blender units.

  • you need a node window, UV/Image window (set to viewer node) and a text window all open at the same time
  • render
  • in the node editor, link the renderlayer z socket to a viewer image socket and make that viewer node active so that it shows in the image editor- you will see a white screen…don’t worry about it :wink:
  • load the following code into the text window and run it.
import Blender
from Blender import *

img = Image.GetCurrent()
if img:
    maxz = 50  #set just past the max depth of your scene
    xs,ys = img.getSize()
    file = open("put your path/filename here", "w")
    file.write("zbuffer_array["+str(xs*ys)+"] = {")
    for y in range(ys):
        for x in range(xs):
            r,g,b,a = img.getPixelHDR(x,y)
            if  r> maxz:
                r = maxz
            file.write("%.3f, " %r) #change number if you want more or less precision
    file.write("}
")
    file.close()
    print("done")

notes:

  • maxz gives you a better value to deal with if a pixel is the blender background… ie: 50.000 instead of 99999997952.000 (it can also make the txt file much smaller if alot of background is present- 50% with default cube)
  • if you want values 0.0->1.0 instead of actual blender units, run the z socket through a normalize node (or Map value node) before the viewer node.
  • This produces a huge text file! default cube at 720*480 is 2.6megs with 345600 array elements

Is there a way to have the z-buffer with anti-aliased edges instead of the jagged edges?

It has to be aliased or else z-combine doesn’t work… it’s the “standard”

I guess if you need it smooth you just need to render it twice up an then downsample… of use your nodes with FSA

For those wanting a non python way just use openexr…

or if you want another format :
compositing nodes and link the “z” output to the output node (or a file output node…)

if you don’t want in as a float you could link the z to a “normalise” node and then to the output…

Thanks for your explanation Michael W, but I’m not sure to fully understand.
Following your tips I’m trying to save the Open Exr after having “normalized” it, but I still see the jagged edges. Btw, now that you told me this has to be aliased, I see I’ve to look for a workaround…

Many thanks to all! The paprmh’s code is great. Now I’m trying to do a tool more automatic, in where the 3 preliminary steps are done by a python script. So:

  1. Is possible render in image window (setting context displayMode=0) -first step done-OK
    2)OK
    3)Without using node editor, I see that U/V image window has a button ‘Draws zbuf values mapped to camera clip…’. The result is exactly as connect Z socket to an output viewer, so it’s possible use the script for all blend file. But, unfortunately, I’havn’t found an API for set this button in a script. Any advice?

Hello. Sorry for digging up an old thread.
I’m trying to do the same thing - access Z data dircetly from script. Does enyone know how to port the gpaprmh’s code to new python API for Blender 2.64?
I have the particular problem with this part:

img = Image.GetCurrent()

EDIT:
After a few tries I have a more general question - is there a way to access render layers/passes data from python script?
I know where to find render settings and render the scene but where should I look for the result?

EDIT2:
Or maybe is there another way to save Z-Buffer data to a file (16-bit image or text)? Saving to a 8-bit grayscale PNG works great but I need a higher bit depth.