# Isometric perspective for Graphics3D

Is it possible to render Graphics3D in an isometric projection? I know that the ViewPoint option can be used for orthogonal projection by specifying, e.g. ViewPoint -> {0, Infinity, 0}. This doesn't take multiple infinities though, so I can't do ViewPoint -> {Infinity, -Infinity, Infinity}, for instance.

I realise that I could achieve this by rotating the entire scene about two axes and using an orthogonal projection:

Graphics3D[
Rotate[
Rotate[
Cuboid[{-.5, -.5, -.5}],
Pi/4,
{0, 0, 1}
],
ArcTan[1/Sqrt],
{0, 1, 0}
],
ViewPoint -> {-Infinity, 0, 0}
]


However, this is rather cumbersome and it's harder to figure out the correct rotations for the viewpoint I'm interested in. I'd rather just specify the octant from which to view scene isometrically. Is there actually a "proper" way to achieve this?

• I did an isometric projection here: mathematica.stackexchange.com/questions/28000/isometric-3d-plot/…. – Michael E2 Jun 22 '15 at 13:16
• @MichaelE2 Oh okay, I only read the question body and didn't see what it had to do with isometric plotting (should have read the comments as well). But I guess your approach is similar to mine, except that using two vectors for the rotation is obviously simpler than using two angles. – Martin Ender Jun 22 '15 at 13:58

As of V11.2 we can use a combination of ViewProjection and ViewPoint:

Graphics3D[Cuboid[], ViewProjection -> "Orthographic", ViewPoint -> {1, 1, 1}] Various vantages:

v = Tuples[{Tuples[{-1, 1}, 3], IdentityMatrix}];

Graphics3D[Cuboid[{-.5, -.5, -.5}, {1., 2., 4}], ViewProjection -> "Orthographic",
ViewPoint -> #1, ViewVertical -> #2] & @@@ v [Edit notice: Updated to allow the setting of the vertical direction of the plot and to fix an error.]

Here is a slight generalization of my answer to Isometric 3d Plot. To get an isometric view, we need to construct a ViewMatrix that will rotate a vector of the form {±1, ±1, ±1} to {0, 0, 1} and project orthogonally onto the first two coordinates.

ClearAll[isometricView];
isometricView[
g_Graphics3D,                                 (* needed only for PlotRange *)
v_ /; Equal @@ Abs[N@v] && 1. + v[] != 1., (* view point {±1, ±1, ±1} *)
vert_: {0, 0, 1}] :=                          (* like ViewVertical; default: z-axis *)
{TransformationMatrix[
RescalingTransform[
EuclideanDistance @@
Transpose[Chartingget3DPlotRange@ g] {{-1/2, 1/2}, {-1/2, 1/2}, {-1/2, 1/2}}].
RotationTransform[{-v, {0, 0, 1}}].
RotationTransform[{vert - Projection[vert, v], {0, 0, 1} - Projection[{0, 0, 1}, v]}].
RotationTransform[Mod[ArcTan @@ Most[v], Pi], v].
TranslationTransform[-Mean /@ (Chartingget3DPlotRange@ g)]],
{{0, 1, 0, 0}, {1, 0, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}}};

foo = Graphics3D[Cuboid[{-.5, -.5, -.5}, {1., 2., 4}]];
Show[foo, ViewMatrix -> isometricView[foo, {1, 1, 1}, {0, 0, 1}],
ImagePadding -> 20, Axes -> True, AxesLabel -> {x, y, z}]
Show[foo, ViewMatrix -> isometricView[foo, {-1, 1, 1}, {1, 1, 0}],
ImagePadding -> 20, Axes -> True, AxesLabel -> {x, y, z}]  All combinations of viewpoints and vertical axes: Notes:

Getting an accurate plot range that includes the padding is important to computing the correct view matrix. There are alternatives to the undocumented internal function Chartingget3DPlotRange. Alexey Popkov has a method here: How to get the real PlotRange using AbsoluteOptions? I used PlotRange /. AbsolutOptions[g, PlotRange] and multiplied by 1.02 (I don't recall why not something like 1.04) to approximate the padding in my answer to Isometric 3d Plot.

My go-to resource for understanding ViewMatrix has been especially Heike's answer to Extract values for ViewMatrix from a Graphics3D.

This update is in response to Yves' comment. Working with the axes made me realize that the coordinate system is flipped (from "right-handed" to "left-handed). Hence I changed the projection from IdentityMatrix to one that flips the x & y coordinates.

It might be a good idea to Deploy the graphics to prevent rotation by the mouse. When the graphics are rotated, the front end resets the ViewMatrix in a rather ugly way.

• Very nice - is it possible to align the z-axis vertically? – Yves Klett Jun 22 '15 at 14:57
• @YvesKlett That was a bit harder than I thought it would be, mainly because I had misunderstood something. – Michael E2 Jun 22 '15 at 17:43
• Awesome! This will come in handy! – Yves Klett Jun 22 '15 at 17:45

You can use the following post-process function to apply a general parallel projection:

parallelProjection[g_Graphics3D, axes_, pad_: 0.15] :=
Module[{pr3, pr2, ar, t},
pr3 = {-pad, pad} (#2 - #) & @@@ # + # &@Chartingget3DPlotRange@g;
pr2 = MinMax /@ Transpose[Tuples@pr3.axes];
ar = Divide @@ Subtract @@@ pr2;
t = AffineTransform@Append[Transpose@axes, {0, 0, -1}];
t = RescalingTransform@Append[pr2, pr3[]].t;
Show[g, AspectRatio -> 1/ar,
ViewMatrix -> {TransformationMatrix[t], IdentityMatrix}]];


Here axes defines the projection of x,y,z axes to 2d plane and pad makes a room to display axes labels.

Isometric projection:

g = Graphics3D[Cuboid[], Axes -> True, AxesLabel -> {X, Y, Z}];
parallelProjection[g, {{-Sqrt/2, -1/2}, {Sqrt/2, -1/2}, {0, 1}}] Cabinet projection:

α = π/4;
parallelProjection[g, {{1, 0}, {0, 1}, -{Cos[α]/2, Sin[α]/2}}] Just in case you aren't looking for a completely correct solution, but instead, just a cheap workaround.

I was looking for a ViewPoint->{Infinity,Infinity, Infinity} kind of solution. Replacing Infinity with a number big enough (in my case 500) I could get the results I was looking for.