There is no "built in" support for 3D coordinates in "plain" Metapost or in the "metafun" format, but you can program it to do more or less anything.
If you want a simple isometric projection, then you could adapt the approach that I showed last week in this answer. What I did there was to create a macro
p(x, y, z) that projects from three dimensions to two dimensions isometrically. But the downsides are (a) you have to remember to type
p(x,y,z) all the time instead of just using a triple
(x, y, z), and (b) isometric projections don't look very realistic.
If you want something more sophisticated then take a look at these:
But beware that drawing nicely in 3D is very hard, and there are no simple ways to reconcile 3D ideas with some of the core MP concepts. For example:
- what happens to the notion of a closed path? is a cube closed?
- how should you render the thickness of each line? Should lines be thicker if they are nearer the "observer's eye"?
- exactly how can we compute a Bezier spline in 3D?
and so on.
A worked example
For what it's worth, here is a version of your code using my
ipscale := 42;
ahangle := 30;
drawarrow p(0,0,0) -- p(3,0,0); label.rt("$x$", p(3,0,0));
drawarrow p(0,0,0) -- p(0,3,0); label.top("$y$", p(0,3,0));
drawarrow p(0,0,0) -- p(0,0,3); label.urt("$z$", p(0,0,3));
drawarrow p(0,0,0) -- p(2,2,0) withpen pencircle scaled 1;
drawarrow p(0,0,0) -- p(2,0,1) withpen pencircle scaled 1;
If you compile this with
lualatex (and you have my
isometric_projection.mp available), then you will get this:
The relevant portion of the isometric file is this:
newinternal ipca, ipsa, ipcb, ipsb, ipscale;
def set_projection(expr alpha, beta) =
ipca := cosd(alpha); ipsa := sind(alpha);
ipcb := cosd(beta); ipsb := sind(beta);
ipscale := 20;
vardef p(expr x, y, z) =
(x * ipcb - z * ipsb, y * ipca + x * ipsa * ipsb + z * ipsa * ipcb) scaled ipscale
You can either include this directly in your MP source, or save it in a file called
isometric_projection.mp somewhere in your input path and
input it as shown above.