Isometric perspective for Graphics3D

[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]] != 1., (* view point {±1, ±1, ±1} *)
    vert_: {0, 0, 1}] :=                          (* like ViewVertical; default: z-axis *)
 {TransformationMatrix[
   RescalingTransform[
     EuclideanDistance @@ 
       Transpose[Charting`get3DPlotRange@ 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 /@ (Charting`get3DPlotRange@ 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}]

Mathematica graphics Mathematica graphics

All combinations of viewpoints and vertical axes:

Mathematica graphics

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 Charting`get3DPlotRange. 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[4] 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.


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 - #) & @@@ # + # &@Charting`get3DPlotRange@g;
   pr2 = MinMax /@ Transpose[[email protected]];
   ar = Divide @@ Subtract @@@ pr2;
   t = AffineTransform@Append[Transpose@axes, {0, 0, -1}];
   t = RescalingTransform@Append[pr2, pr3[[3]]].t;
   Show[g, AspectRatio -> 1/ar, 
    ViewMatrix -> {TransformationMatrix[t], IdentityMatrix[4]}]];

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[3]/2, -1/2}, {Sqrt[3]/2, -1/2}, {0, 1}}]

enter image description here

Cabinet projection:

α = π/4;
parallelProjection[g, {{1, 0}, {0, 1}, -{Cos[α]/2, Sin[α]/2}}]

enter image description here


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[3]}];

Graphics3D[Cuboid[{-.5, -.5, -.5}, {1., 2., 4}], ViewProjection -> "Orthographic", 
  ViewPoint -> #1, ViewVertical -> #2] & @@@ v

enter image description here