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:
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:
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}
minimal
? If not, I'd suggest replacing it by a standard document class, as we generally want to discourage usage of minimal
‽
Commented
Mar 21, 2012 at 10:19
:)
. 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.
Commented
Mar 21, 2012 at 10:30
:)
. Perhaps they'll introduce a gold version of the Archaeologist badge some time ...
Commented
Mar 21, 2012 at 10:39
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.
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.
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:
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.
One answer provides a pic
for drawing annotated cuboids like these:
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}
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
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}
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.
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}
I used on on my blog.
A bit late to join the party, but I found that a bit of corner rounding is sufficient to make the corners look decent:
\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):
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.
Commented
Jan 15, 2015 at 14:27
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}
undefined control sequence \psframe(0,0)(3.5,2)
Commented
Apr 18, 2022 at 14:53