# Depth from Graphics3D

Consider this simple 3D rendering with some geometric primitives:

Graphics3D[{Cylinder[{{-1, -1, 0}, {-1, -1, 1}}, .42], Cuboid[],
Polygon[{{-2, -2, 0}, {2, -2, 0}, {2, 2, 0}, {-2, 2, 0}}],
Sphere[{.3, -.6, .5}, .5]}, Boxed -> False]


How can I get the depth of each pixel of the rendering, i.e. the distance of the corresponding point to the camera?

Edit: The required depth image would be something like the OpenGL z-buffer. Vertices alone are not enough - I need the depth of every pixel in the rendered image.

• I have two applications: One where there are half a million (full image) and one with around 1000 (test points). Jul 25, 2013 at 10:42
• Pixels or vertices? Jul 25, 2013 at 11:09
• You might interested in this question. See, mathematica.stackexchange.com/questions/24211/… Jul 25, 2013 at 11:22
• @cormullion: Pixel! Jul 25, 2013 at 12:21

We can set the Method option for Graphics3D:

dmap = Graphics3D[{Cylinder[{{-1, -1, 0}, {-1, -1, 1}}, .42], Cuboid[],
Polygon[{{-2, -2, 0}, {2, -2, 0}, {2, 2, 0}, {-2, 2, 0}}],
Sphere[{.3, -.6, .5}, .5]}, Boxed -> False,
Method -> {"OneLayer" -> {"Depth", 1}}]


To get the distance values rescaled from 0 to 1, we can rasterize:

raster = ColorConvert[Rasterize[dmap], "Grayscale"];


We can view the depth map from different view points:

ListPlot3D[ImageData[raster], Axes -> False, Boxed -> False,
ViewPoint -> {0, 0, -10}, ViewVertical -> {0, -1, 0}, Mesh -> None,
SphericalRegion -> True]


• +1 I guess this is the winning answer. Where did you find out about Method -> {"OneLayer" -> {"Depth", 1}} ? Also what other options are available? Aug 14, 2021 at 17:22
• ^ nevermind - found it here - a direct example: wolfram.com/xid/0wgrojc-tlmeyj Aug 14, 2021 at 17:31
• Right, the Method option has been documented in the Graphics3D ref page since 11.3 I believe. Aug 14, 2021 at 17:32

It would certainly be helpful if you could specify your input data. As an example I'll use the scene you proposed above.

Let's first extract the vertices of the 3D scene. One way to achieve this is to export the scene as an .obj and then reimport the vertex data only. Let's neglect the fact that the vertices aren't uniformly distributed over the surfaces.

scene = Graphics3D[{Cylinder[{{-1, -1, 0}, {-1, -1, 1}}, .42], Cuboid[],
Polygon[{{-2, -2, 0}, {2, -2, 0}, {2, 2, 0}, {-2, 2, 0}}], Sphere[{.3, -.6, .5}, .5]},
Boxed -> False, ViewPoint -> {5, 5, 5}]

Export["scene.obj", scene];
impScene = Import["scene.obj", "VertexData"];


The camera location is at position $(5,5,5)$ as defined by ViewPoint above:

cameraLoc = {5, 5, 5};


These are all the lines connecting the camera to the vertices:

Graphics3D[Line[{cameraLoc, #}] & /@ impScene]


The distance from the camera to each of the vertices is easily obtained by:

dist = EuclideanDistance[cameraLoc, #] & /@ impScene;

• Thanks for the answer, but I need the depth of every pixel not only of vertices. Much like the OpenGL z-Buffer. Jul 25, 2013 at 12:00

One (very slow) method I've used is to sweep through the depth by increasing the ViewRange gradually, and rasterizing those scenes in black & white. You can then sum the resulting images to produce something that looks like a depth map.

drange = Range[12.0, 18, 0.05];
dimensions = {512, 512};

objects = {Cylinder[{{-1, -1, 0}, {-1, -1, 1}}, .42], Cuboid[],
Polygon[{{-2, -2, 0}, {2, -2, 0}, {2, 2, 0}, {-2, 2, 0}}],
Sphere[{.3, -.6, .5}, .5]};

Graphics3D[{FaceForm[Black], EdgeForm[Black], objects},
Boxed -> False, ViewRange -> {0, r}],
RasterSize -> dimensions], "Grayscale"], {r, drange}];



This is of course inadequate for your purposes due to poor performance and low depth resolution.

Another option is to set the VertexColors of the mesh to a GrayLevel corresponding to the distance from the camera. This is faster, but it's not accurate as it interpolates the depth. Also there are some artifacts near polygon edges.

camera = {1.3, -2.4, 2.};
scene = Graphics3D[{Cylinder[{{-1, -1, 0}, {-1, -1, 1}}, .42],
Cuboid[],
Polygon[{{-2, -2, 0}, {2, -2, 0}, {2, 2, 0}, {-2, 2, 0}}],
Sphere[{.3, -.6, .5}, .5]}, Boxed -> False, ViewPoint -> camera];
(* get the whole scene as one big mesh *)
polys = TriangulateMesh[ImportString[ExportString[scene, "OBJ"]]];

coords = MeshCoordinates[polys];
cells = MeshCells[polys, 2];

(* get all polygon vertices distances to camera, normalize, and set a GrayLevel *)
distances = GrayLevel /@ Rescale[EuclideanDistance[camera, #] & /@ coords];

(* render the scene with the VertexColors *)
Rasterize[
Graphics3D[{EdgeForm[None], Lighting -> {{"Ambient", White}},
GraphicsComplex[coords, cells, VertexColors -> distances]},
Boxed -> False]] // ColorNegate