4
$\begingroup$

I'm trying to render an object from different views using blender. While I worked out how this can be achieved by the means of a python script, I'm stuck on my next task: I also want to dump the depthmap for every rendered image. What I've found so far is this link, so I assume that I need to somehow disable render passes to get my desired result? How would I do that through the python interface? Or is there an easier way?

Edit: I found another reference how to do this in the GUI: http://www.cs.tut.fi/kurssit/SGN-5406/vrlab2012/blender-manual.pdf. How could I automate this with a python script?

$\endgroup$
2
  • $\begingroup$ Cycles or Blender Internal? If possible please provide a test scene. Also might be a good idea to split up your question... $\endgroup$
    – p2or
    Dec 5, 2015 at 17:46
  • $\begingroup$ Blender internal would be enough for my purposes. The scene is very simple, only a single mesh (loaded from an .obj file) placed in origin. Just an example of how to do it with the default cube woud be enough for me :) $\endgroup$
    – panmari
    Dec 5, 2015 at 18:18

3 Answers 3

8
$\begingroup$

From various sources I found out how to assemble a render graph to put out the depth map (scaled to the range [0, 255]):

# Set up rendering of depth map:
bpy.context.scene.use_nodes = True
tree = bpy.context.scene.node_tree
links = tree.links

# clear default nodes
for n in tree.nodes:
    tree.nodes.remove(n)

# create input render layer node
rl = tree.nodes.new('CompositorNodeRLayers')

map = tree.nodes.new(type="CompositorNodeMapValue")
# Size is chosen kind of arbitrarily, try out until you're satisfied with resulting depth map.
map.size = [0.08]
map.use_min = True
map.min = [0]
map.use_max = True
map.max = [255]
links.new(rl.outputs[2], map.inputs[0])

invert = tree.nodes.new(type="CompositorNodeInvert")
links.new(map.outputs[0], invert.inputs[1])

# The viewer can come in handy for inspecting the results in the GUI
depthViewer = tree.nodes.new(type="CompositorNodeViewer")
links.new(invert.outputs[0], depthViewer.inputs[0])
# Use alpha from input.
links.new(rl.outputs[1], depthViewer.inputs[1])

The output can then be saved to a file using a File Output node:

# create a file output node and set the path
fileOutput = tree.nodes.new(type="CompositorNodeOutputFile")
fileOutput.base_path = "/my_path/"
links.new(invert.outputs[0], fileOutput.inputs[0])

Whenever a render is triggered, the depth map will be dumped into the base_path specified.

$\endgroup$
3
  • 2
    $\begingroup$ Great! Just an idea: you could also create an output node to save the file. $\endgroup$
    – p2or
    Dec 7, 2015 at 16:47
  • $\begingroup$ Thanks for the hint! A file output node would indeed be better for my purposes. $\endgroup$
    – panmari
    Dec 7, 2015 at 16:53
  • $\begingroup$ Just wondering if the z value represents the distance between a surface point and the sensor? $\endgroup$
    – shinxg
    Dec 7, 2020 at 8:34
1
$\begingroup$

I struggled with CompositorNodeMapValue, setting the size/min/max to values that got a good reading. Using the CompositorNodeMapRange was more helpful.

You can set the values intuitively, this video is good intro.

For setting these same parameters from that video in the api, you would set

map.inputs[1].default_value = (min value you will be getting)

map.inputs[2].default_value = (max value you will be getting)

map.inputs[3].default_value = (min value you will map to)

map.inputs[4].default_value = (max value you will map to)

The last two values are typically 0 and 1, but if you want your depth map to be lighter if the object is closer to the camera, they will be 1 and 0 respectively.

$\endgroup$
1
$\begingroup$

Some of the suggested tips have been useful, but for blender 3.4.1 with Eevee renderer I had to do extra steps, which I add for reference (the main thing is enabling the Z pass):

# Useful scene variables
scn = bpy.context.scene
cam = scn.camera
output_path = scn.render.filepath
tree = bpy.context.scene.node_tree
links = tree.links

bpy.context.scene.render.use_compositing = True
bpy.context.scene.use_nodes = True
bpy.context.scene.view_layers[0].use_pass_z = True

for n in tree.nodes:
  tree.nodes.remove(n)
rl = tree.nodes.new('CompositorNodeRLayers')

vl = tree.nodes.new('CompositorNodeViewer')
vl.use_alpha = True
links.new(rl.outputs[0], vl.inputs[0])  # link Image to Viewer Image RGB
links.new(rl.outputs['Depth'], vl.inputs[1])  # link Render Z to Viewer Image Alpha

Then render and store as a numpy array:

bpy.ops.render.render()

pixels = np.array(bpy.data.images['Viewer Node'].pixels)
resolution = int(np.sqrt(len(pixels)/4))
#reshaping into image array 4 channel (rgbz)
image_with_depth = pixels.reshape(resolution,resolution,4)
$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .