18
$\begingroup$

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[2]], 
    {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?

$\endgroup$
2
  • $\begingroup$ I did an isometric projection here: mathematica.stackexchange.com/questions/28000/isometric-3d-plot/…. $\endgroup$
    – Michael E2
    Commented Jun 22, 2015 at 13:16
  • $\begingroup$ @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. $\endgroup$ Commented Jun 22, 2015 at 13:58

4 Answers 4

7
$\begingroup$

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

$\endgroup$
18
$\begingroup$

[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.

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

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

$\endgroup$
2
$\begingroup$

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.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.