81

I'm trying to find the easiest way to draw a 3D cube (it's for my UML diagram) with TikZ. Could you please give an example?

Like this: enter image description here

3

8 Answers 8

53

I'm sure that there are better ways, but here's one:

\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\pgfmathsetmacro{\cubex}{2}
\pgfmathsetmacro{\cubey}{1}
\pgfmathsetmacro{\cubez}{1}
\draw[red,fill=yellow] (0,0,0) -- ++(-\cubex,0,0) -- ++(0,-\cubey,0) -- ++(\cubex,0,0) -- cycle;
\draw[red,fill=yellow] (0,0,0) -- ++(0,0,-\cubez) -- ++(0,-\cubey,0) -- ++(0,0,\cubez) -- cycle;
\draw[red,fill=yellow] (0,0,0) -- ++(-\cubex,0,0) -- ++(0,0,-\cubez) -- ++(\cubex,0,0) -- cycle;
\end{tikzpicture}
\end{document}

enter image description here

11
  • Any particular reason you're using minimal? If not, I'd suggest replacing it by a standard document class, as we generally want to discourage usage of minimal
    – doncherry
    Commented Mar 21, 2012 at 10:19
  • 17
    @doncherry Because the question tex.stackexchange.com/q/42114/86 hadn't been asked when I wrote that! I was young, I was naive, I didn't know what I was doing. Now I'm old and grumpy and can say, "You want it changed? You know where the 'edit' button is!". (Seriously, you should feel free to make changes like that.) Commented Mar 21, 2012 at 10:22
  • 2
    Good response :). Well, I guess concerning people like you I could just edit it, but then again I think "He knows a lot more about that stuff than I do, perhaps there's a reason he used minimal". When coming across newer users using it, I usually point them to the question you mentioned.
    – doncherry
    Commented Mar 21, 2012 at 10:30
  • A quick grep shows that I've used it 45 times in answers (subject to rounding errors). If you come across any others, feel free to edit. Commented Mar 21, 2012 at 10:32
  • I shall :). Perhaps they'll introduce a gold version of the Archaeologist badge some time ...
    – doncherry
    Commented Mar 21, 2012 at 10:39
67

Drawing a cube seems to be a fairly common task! There are a few other questions here that involve drawing cubes. It's not always right to merge them, but I thought it worth doing a little more than just linking. So this answer is a Community Wiki (so almost anyone can update it) list of the other cubical questions here. The intent is to include at least one representative picture from the answers.

  1. Need help creating a 3D cube from a 2D set of nodes in TikZ

    Tom Bombadil's answer here is well on the way to being a package, showing that he has mastery over cubes as well as rings.

    cubes

  2. How to draw a cube with TikZ where all faces have a distinct color?

    The accepted answer yields the first image, and the second is a another from the same question:

    enter image description here transparent cube

  3. Is there a way to draw TikZ lines on the "inside" or "outside" of a path?

    Although not obviously about cubes, the motivation was to draw a cube and get the corners right.

    cube with corners

  4. How to draw parallelepiped and cube with LaTeX?

One answer provides a pic for drawing annotated cuboids like these:

annotated cuboids

1
  • Also, Tom's answer has made significant progress since the version posted here and now includes some shaded cubes which really look as if they belong among the rings and mists of Middle Earth... ;).
    – cfr
    Commented Jan 18, 2016 at 0:50
45

Since you want to use this for UML diagrams, I think a custom node shape is the right way to go here. It's a lot more overhead and requires getting under PGF's hood/bonnet, but the payoff is that it the drawing code looks just like any other TikZ code:

\documentclass{article}
\usepackage{tikz}

\makeatletter
\pgfkeys{/pgf/.cd,
  parallelepiped offset x/.initial=2mm,
  parallelepiped offset y/.initial=2mm
}
\pgfdeclareshape{parallelepiped}
{
  \inheritsavedanchors[from=rectangle] % this is nearly a rectangle
  \inheritanchorborder[from=rectangle]
  \inheritanchor[from=rectangle]{north}
  \inheritanchor[from=rectangle]{north west}
  \inheritanchor[from=rectangle]{north east}
  \inheritanchor[from=rectangle]{center}
  \inheritanchor[from=rectangle]{west}
  \inheritanchor[from=rectangle]{east}
  \inheritanchor[from=rectangle]{mid}
  \inheritanchor[from=rectangle]{mid west}
  \inheritanchor[from=rectangle]{mid east}
  \inheritanchor[from=rectangle]{base}
  \inheritanchor[from=rectangle]{base west}
  \inheritanchor[from=rectangle]{base east}
  \inheritanchor[from=rectangle]{south}
  \inheritanchor[from=rectangle]{south west}
  \inheritanchor[from=rectangle]{south east}
  \backgroundpath{
    % store lower right in xa/ya and upper right in xb/yb
    \southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
    \northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y
    \pgfmathsetlength\pgfutil@tempdima{\pgfkeysvalueof{/pgf/parallelepiped offset x}}
    \pgfmathsetlength\pgfutil@tempdimb{\pgfkeysvalueof{/pgf/parallelepiped offset y}}
    \def\ppd@offset{\pgfpoint{\pgfutil@tempdima}{\pgfutil@tempdimb}}
    \pgfpathmoveto{\pgfqpoint{\pgf@xa}{\pgf@ya}}
    \pgfpathlineto{\pgfqpoint{\pgf@xb}{\pgf@ya}}
    \pgfpathlineto{\pgfqpoint{\pgf@xb}{\pgf@yb}}
    \pgfpathlineto{\pgfqpoint{\pgf@xa}{\pgf@yb}}
    \pgfpathclose
    \pgfpathmoveto{\pgfqpoint{\pgf@xb}{\pgf@ya}}
    \pgfpathlineto{\pgfpointadd{\pgfpoint{\pgf@xb}{\pgf@ya}}{\ppd@offset}}
    \pgfpathlineto{\pgfpointadd{\pgfpoint{\pgf@xb}{\pgf@yb}}{\ppd@offset}}
    \pgfpathlineto{\pgfpointadd{\pgfpoint{\pgf@xa}{\pgf@yb}}{\ppd@offset}}
    \pgfpathlineto{\pgfqpoint{\pgf@xa}{\pgf@yb}}
    \pgfpathmoveto{\pgfqpoint{\pgf@xb}{\pgf@yb}}
    \pgfpathlineto{\pgfpointadd{\pgfpoint{\pgf@xb}{\pgf@yb}}{\ppd@offset}}
  }
}
\makeatother

\begin{document}
\begin{tikzpicture}
\node[parallelepiped,draw=red,fill=yellow,
  minimum width=2.5cm,minimum height=1.5cm] (1) {Node One};
\node[parallelepiped,draw=blue,fill=green,
  minimum height=2.5cm,minimum width=1.5cm,parallelepiped offset x=4mm] (2)
 at (6,0) {Node Two};
 \draw[ultra thick, ->] (1) -- (2);
\end{tikzpicture}
\end{document}

sample code output

Take a look at the files pgflibraryshapes.*.code.tex in the PGF distribution to learn how to do this kind of thing. I started with a copy of the cross out node which, like this one, inherits from the rectangle node. A further enhancement would be to add anchors to the right/top faces/edges, but as you can guess I have spent enough time on this already. :-D

9
  • Very nice! Plus the text should be in the actual middle of the cube and be a bit faded so that it looked as though it were inside ... Commented Feb 25, 2011 at 14:58
  • @Andrew: yes, if what is desired is a cube with text in the center. But I looked up UML diagrams like the OP is trying to create and they put it on the front of the cube/parallelipiped. See “UML Deployment Diagrams” Commented Feb 25, 2011 at 15:10
  • 1
    Since when has doing what the spec says stopped you from doing what is right?? You are a mathematician after all. Commented Feb 25, 2011 at 15:22
  • 2
    Sometimes doing what is asked and nothing more is wise... (especially for a mathematician who should be writing his book). Commented Feb 25, 2011 at 16:57
  • @Matthew: It's spelled parallelepiped. See en.wikipedia.org/wiki/Parallelepiped Commented Feb 25, 2011 at 21:20
37

I know that this is not what the question was about, but it is an attempt of a 3D cube, with perspective. I don't know how to do it with grids like Stefan's example, but with coordinate calculations and intersections, one can do something like this. It is not mathematically correct, but I think it looks pretty good.

\documentclass[]{article}
\usepackage{tikz}  
\usetikzlibrary{calc,intersections}
\begin{document}
\begin{tikzpicture}
   \clip (-3,-3) rectangle (3,3);
   \coordinate (tf) at (0,0);
   \coordinate (bf) at (0,-3);
   \coordinate (tr) at (15:2.5cm);
   \coordinate (tl) at (165:2.5cm);

   % You can change the perspective by playing with the 5, 5, 15:
   \coordinate (fr) at ($ (tf)!5!(tr) $);
   \coordinate (fl) at ($ (tf)!5!(tl) $);
   \coordinate (fb) at ($ (tf)!15!(bf) $);

   \path[name path=brpath] (bf) -- (fr);
   \path[name path=rbpath] (tr) -- (fb);
   \path[name path=blpath] (bf) -- (fl);
   \path[name path=lbpath] (tl) -- (fb);
   \path[name path=trpath] (tl) -- (fr);
   \path[name path=tlpath] (tr) -- (fl);

   \draw[name intersections={of=brpath and rbpath}] (intersection-1)coordinate (br){}; 
   \draw[name intersections={of=blpath and lbpath}] (intersection-1)coordinate (bl){}; 
   \draw[name intersections={of=trpath and tlpath}] (intersection-1)coordinate (tb){}; 

   \shade[right color=gray!10, left color=black!50, shading angle=105] (tf) -- (bf) -- (bl) -- (tl) -- cycle;
   \shade[left color=gray!10, right color=black!50, shading angle=75] (tf) -- (bf) -- (br) -- (tr) -- cycle;

   \begin{scope}
      \clip (tf) -- (tr) -- (tb) -- (tl) -- cycle;
      \shade[inner color = gray!5, outer color=black!50, shading=radial] (tf) ellipse (3cm and 1.5cm);
   \end{scope}

   \draw (tf) -- (bf);
   \draw (tf) -- (tr);
   \draw (tf) -- (tl);
   \draw (tr) -- (br);
   \draw (bf) -- (br);
   \draw (tl) -- (bl);
   \draw (bf) -- (bl);
   \draw (tb) -- (tr);
   \draw (tb) -- (tl);

   %set the sizes of the little cubes:
   \def\tone{.4}\def\ttwo{.75}\def\fone{.36}\def\ftwo{.70}
   \draw ($ (bf)!\tone!(br) $) -- ($ (tf)!\tone!(tr) $) -- ($ (tl)!\tone!(tb) $);
   \draw ($ (bf)!\ttwo!(br) $) -- ($ (tf)!\ttwo!(tr) $) -- ($ (tl)!\ttwo!(tb) $);
   \draw ($ (bf)!\tone!(bl) $) -- ($ (tf)!\tone!(tl) $) -- ($ (tr)!\tone!(tb) $);
   \draw ($ (bf)!\ttwo!(bl) $) -- ($ (tf)!\ttwo!(tl) $) -- ($ (tr)!\ttwo!(tb) $);
   \draw ($ (tl)!\fone!(bl) $) -- ($ (tf)!\fone!(bf) $) -- ($ (tr)!\fone!(br) $);
   \draw ($ (tl)!\ftwo!(bl) $) -- ($ (tf)!\ftwo!(bf) $) -- ($ (tr)!\ftwo!(br) $);
\end{tikzpicture}
\end{document}

enter image description here

3
  • 1
    I learned something new: name path. Thanks Jan! Commented Feb 25, 2011 at 19:29
  • Nice! And anyone else coming here looking for how to draw a cube will now have a feast of answers to choose from. Commented Feb 25, 2011 at 19:51
  • What do you change in order to extend one dimension (making an orthotope instead of a cuboid)? Thanks. Commented Jul 13, 2020 at 12:42
25

There is already a lot of nice answers to this question, but I would like to promote the 3d TikZ library which makes it easier to manipulate simple objects with three-dimensional coordinates. Here is a solution in the spirit of Stefan's:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{3d}
\begin{document}

\begin{tikzpicture}[x  = {(0.5cm,0.5cm)},
                    y  = {(0.95cm,-0.25cm)},
                    z  = {(0cm,0.9cm)}]
\begin{scope}[canvas is yz plane at x=-1]
  \shade[left color=blue!50,right color=blue!20] (-1,-1) rectangle (1,1);
\end{scope}
\begin{scope}[canvas is xz plane at y=1]
  \shade[right color=blue!70,left color=blue!20] (-1,-1) rectangle (1,1);
\end{scope}
\begin{scope}[canvas is yx plane at z=1]
  \shade[top color=blue!80,bottom color=blue!20] (-1,-1) rectangle (1,1);
\end{scope}
\end{tikzpicture}
\end{document}

Again, the tricky part is to fine tune the perspective and shading, but in my opinion the canvas option provides an easy way to draw in 3D.

enter image description here

22

Here's an example for a shaded 3D cube with TikZ:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{positioning}
\begin{document}
\begin{tikzpicture}[on grid]
  \shade[yslant=-0.5,right color=gray!10, left color=black!50]
    (0,0) rectangle +(3,3);
  \draw[yslant=-0.5] (0,0) grid (3,3);
  \shade[yslant=0.5,right color=gray!70,left color=gray!10]
    (3,-3) rectangle +(3,3);
  \draw[yslant=0.5] (3,-3) grid (6,0);
  \shade[yslant=0.5,xslant=-1,bottom color=gray!10,
    top color=black!80] (6,3) rectangle +(-3,-3);
  \draw[yslant=0.5,xslant=-1] (3,0) grid (6,3);
\end{tikzpicture}
\end{document}

Shaded 3D cube

I used on on my blog.

6
  • The cube is nice, but the shading doesn't give a good 3D-effect IMHO. Commented Feb 25, 2011 at 9:42
  • @Hendrik: quick and easy simulating kind of light which should lead a bit to an optical 3D appearance though it's of course 2D. For an oblique view one could modify it. My answer points to an easy way, as desired.
    – Stefan Kottwitz
    Commented Feb 25, 2011 at 9:45
  • As now there's a picture in the question, showing a different requested style, I consider to remove the answer.
    – Stefan Kottwitz
    Commented Feb 25, 2011 at 9:50
  • 2
    (Voting for it not to be removed as it's a really nice example.) What destroys the 3D effect for me is not the shading but the perspective - or lack of it. Commented Feb 25, 2011 at 9:56
  • @Andrew: I've been too lazy :-) if you know how to easily add perspective, you're welcome to modify. We could bring that enhancement to TeXample.net afterwards.
    – Stefan Kottwitz
    Commented Feb 25, 2011 at 10:25
17

A bit late to join the party, but I found that a bit of corner rounding is sufficient to make the corners look decent:

cube

\documentclass{article}
\usepackage[margin=0cm,nohead]{geometry}
\usepackage[active,tightpage]{preview}
\usepackage{tikz,color}
\usetikzlibrary{calc}
\PreviewEnvironment{tikzpicture}

\begin{document}
    \begin{tikzpicture}
    % Settings
    \definecolor{CUBE}{rgb}{0.3,0.3,0.9};
    \coordinate (CenterPoint) at (0,0);
    \def\width{1.5cm};
    \def\height{1.0cm};
    \def\textborder{0.1cm};
    \def\xslant{0.2cm};
    \def\yslant{0.15cm};
    \def\rounding{0.2pt};
    % Drawing
    \node[thick, draw,
          minimum height  = \height,
          minimum width   = \width,
          text width      = {\width-2*\textborder},
          align           = center,
          fill            = CUBE!50,
          rounded corners = \rounding]
          at (CenterPoint) {``Cube''}; % TEXT HERE?
    % "3D" top
    \draw [rounded corners = \rounding, thick, fill=CUBE!70] %
        ($(CenterPoint) + (-\width/2. - 2*\rounding, \height/2.)$) -- %
        ($(CenterPoint) + (-\width/2. + \xslant - 2*\rounding, \height/2. + \yslant)$) -- %
        ($(CenterPoint) + (\width/2. + \xslant + 2*\rounding, \height/2. + \yslant)$) -- %
        ($(CenterPoint) + (\width/2. + 2*\rounding, \height/2.)$) -- %
        cycle;
    % "3D" side
    \draw [rounded corners = \rounding, thick, fill=CUBE!90] %
        ($(CenterPoint) + (\width/2. + \xslant + 2*\rounding, \height/2. + \yslant)$) -- %
        ($(CenterPoint) + (\width/2. + 2*\rounding, \height/2.)$) -- %
        ($(CenterPoint) + (\width/2. + 2*\rounding, -\height/2.)$) -- %
        ($(CenterPoint) + (\width/2. + \xslant + 2*\rounding, -\height/2. + \yslant)$) -- %
        cycle;
    \end{tikzpicture}
\end{document}

I am sure if this is useful someone with more experience and knowledge can compensate, if required, the extra width (+ 2*\rounding) added to make the corners fit together, add anchors around the drawing, encapsulate it in some routine you can call and even allow for the "3D" part to appear on other sides (change perspective).

But since this article helped me, I thought I would give back what I learned even if little or rudimentary.

Also, details on the corners (please remove them if they are occupying too much space and are not useful):

corner1 corner2 corner3

3
  • Welcome to TeX.SX! You can have a look at our starter guide to familiarize yourself further with our format. This is really quite late, but a nice answer! :)
    – yo'
    Commented Dec 9, 2014 at 12:27
  • 1
    Instead of rounded corners, you may try line cap=round,line join=round (and 0pt as value for \rounding in your MWE). Commented Dec 10, 2014 at 21:55
  • line cap=round and line join=round leave the corners between the three distinct faces pointy, with bits sticking out. 0pt also leaves the same artifacts. I didn't try different values but I guess there should be a best value for each line thickness.
    – berna1111
    Commented Jan 15, 2015 at 14:27
4

A PSTricks solution:

\documentclass{article}

\usepackage{pstricks}

\begin{document}

\begin{center}
\psset{
  dimen = m,
  linejoin = 1,
  fillstyle = solid,
  fillcolor = yellow!30
}
\begin{pspicture}(4,2.5)
  \psframe(0,0)(3.5,2)
  \pspolygon(3.5,0)(3.5,2)(4,2.5)(4,0.5)
  \pspolygon(0,2)(0.5,2.5)(4,2.5)(3.5,2)
  \rput(1.75,1){Node}
\end{pspicture}
\end{center}

\end{document}

output

1
  • This your code does not run on my Windows: undefined control sequence \psframe(0,0)(3.5,2) Commented Apr 18, 2022 at 14:53

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .