summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/doc/generic/pgf/text-en/pgfmanual-en-library-perspective.tex
blob: 61ed10179ec19dc3cb6ad4c9309779ddbd93a790 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
\section{Three Point Perspective Drawing Library}

\noindent\emph{by Max Snippe}

\begin{tikzlibrary}{perspective}
  This library provides tools for perspective drawing with one, two, or three
  vanishing points.
\end{tikzlibrary}

\subsection{Coordinate Systems}

\begin{coordinatesystem}{three point perspective}
  The |three point perspective| coordinate system is very similar to the |xyz|
  coordinate system, save that it will display the provided coordinates with a
  perspective projection.
  %
  \begin{key}{/tikz/cs/x=\meta{number} (initially 0)}
    The $x$ component of the coordinate. Should be given \emph{without} unit.
  \end{key}
  %
  \begin{key}{/tikz/cs/y=\meta{number} (initially 0)}
    Same as |x|.
  \end{key}
  %
  \begin{key}{/tikz/cs/z=\meta{number} (initially 0)}
    Same as |x|.
  \end{key}
\end{coordinatesystem}

\begin{coordinatesystem}{tpp}
  The |tpp| coordinate system is an alias for the |three point perspective|
  coordinate system.
\end{coordinatesystem}

\subsection{Setting the view}

\begin{key}{/tikz/3d view=\marg{azimuth}\marg{elevation}
    (default \{-30\}\{15\})}
  With the |3d view| option, the projection of the 3D coordinates on the 2D page
  is defined. It is determined by rotating the coordinate system by
  $-\meta{azimuth}$ around the $z$-axis, and by \meta{elevation} around the
  (new) $x$-axis, as shown below.

  \begin{tikzpicture}[
    viewpoint/.pic={
      \draw (22.5:0.45) -- (0,0) -- (-22.5:0.45);
      \draw (0,0) ++ (22.5:0.35) arc (22.5:-22.5:0.35);
      \draw (0.225,0) circle (0.02 and 0.09);
    }]
    \begin{scope}[3d view={-20}{20}]
      \draw[->] (-3,0,0) -- (3,0,0) node[pos=1.05]{x};
      \draw[->] (0,-3,0) -- (0,3,0) node[pos=1.05]{y};
      \draw[->] (0,0,-1) -- (0,0,3) node[pos=1.05]{z};

      \pgfmathsetmacro\az{50}
      \begin{scope}[canvas is xy plane at z=0]
        \draw[->] (0,0) ++(0,-2) arc (-90:-90+\az:2) coordinate[pos=0.5](az);
        \draw (az) -- ++(-90+\az/2:1) node[below]{\meta{azimuth}};
        \draw[dashed] (0,0) -- ++(-90+\az:3);
      \end{scope}
      \begin{scope}[rotate around z=\az]
        \pgfmathsetmacro\el{50}
        \begin{scope}[canvas is yz plane at x=0]
          \draw[->] (0,0) ++(-2.5,0) arc (180:180-\el:2.5)
            coordinate[pos=0.5](el);
          \draw (el) -- ++(180-\el/2:1) node[above]{\meta{elevation}};
          \draw[dashed] (0,0) --
            pic[solid,sloped,transform shape,pos=1.2]{viewpoint} ++(180-\el:3);
        \end{scope}
      \end{scope}
    \end{scope}
  \end{tikzpicture}

  For example, when both \meta{azimuth} and \meta{elevation} are 0$^\circ$,
  $+z$ will be pointing upward, and $+x$ will be pointing right. The default is
  as shown below.
\begin{codeexample}[]
\begin{tikzpicture}[3d view]
  \draw[->] (-1,0,0) -- (1,0,0) node[pos=1.1]{x};
  \draw[->] (0,-1,0) -- (0,1,0) node[pos=1.1]{y};
  \draw[->] (0,0,-1) -- (0,0,1) node[pos=1.1]{z};
\end{tikzpicture}
\end{codeexample}
\end{key}

\begin{stylekey}{/tikz/isometric view}
  A special kind of |3d view| is isometric, which can be set with the
  |isometric view| style. It simply sets |3d view={-45}{35.26}|. The value for
  \meta{elevation} is determined with $\arctan(1/\sqrt{2})$. In isometric
  projection the angle between any pair of axes is 120$^\circ$, as shown below.
\begin{codeexample}[]
\begin{tikzpicture}[isometric view]
  \draw[->] (-1,0,0) -- (1,0,0) node[pos=1.1]{x};
  \draw[->] (0,-1,0) -- (0,1,0) node[pos=1.1]{y};
  \draw[->] (0,0,-1) -- (0,0,1) node[pos=1.1]{z};
\end{tikzpicture}
\end{codeexample}
\end{stylekey}

\subsection{Defining the perspective}

\newcommand\simplecuboid[3]{%
  \fill[gray!80!white] (tpp cs:x=0,y=0,z=#3)
    -- (tpp cs:x=0,y=#2,z=#3)
    -- (tpp cs:x=#1,y=#2,z=#3)
    -- (tpp cs:x=#1,y=0,z=#3) -- cycle;
  \fill[gray]  (tpp cs:x=0,y=0,z=0)
    -- (tpp cs:x=0,y=0,z=#3)
    -- (tpp cs:x=0,y=#2,z=#3)
    -- (tpp cs:x=0,y=#2,z=0) -- cycle;
  \fill[gray!50!white] (tpp cs:x=0,y=0,z=0)
    -- (tpp cs:x=0,y=0,z=#3)
    -- (tpp cs:x=#1,y=0,z=#3)
    -- (tpp cs:x=#1,y=0,z=0) -- cycle;}

\newcommand{\simpleaxes}[3]{%
  \draw[->] (-0.5,0,0) -- (#1,0,0) node[pos=1.1]{x};
  \draw[->] (0,-0.5,0) -- (0,#2,0) node[pos=1.1]{y};
  \draw[->] (0,0,-0.5) -- (0,0,#3) node[pos=1.1]{z};}

In this section, the following example cuboid will be used with various scaling.
As a reference, the axes will be shown too, without perspective projection.
\begingroup
\let\simplecuboid\relax
\let\simpleaxes\relax
\begin{codeexample}[]
\newcommand\simplecuboid[3]{%
  \fill[gray!80!white] (tpp cs:x=0,y=0,z=#3)
    -- (tpp cs:x=0,y=#2,z=#3)
    -- (tpp cs:x=#1,y=#2,z=#3)
    -- (tpp cs:x=#1,y=0,z=#3) -- cycle;
  \fill[gray]  (tpp cs:x=0,y=0,z=0)
    -- (tpp cs:x=0,y=0,z=#3)
    -- (tpp cs:x=0,y=#2,z=#3)
    -- (tpp cs:x=0,y=#2,z=0) -- cycle;
  \fill[gray!50!white] (tpp cs:x=0,y=0,z=0)
    -- (tpp cs:x=0,y=0,z=#3)
    -- (tpp cs:x=#1,y=0,z=#3)
    -- (tpp cs:x=#1,y=0,z=0) -- cycle;}
\newcommand{\simpleaxes}[3]{%
  \draw[->] (-0.5,0,0) -- (#1,0,0) node[pos=1.1]{x};
  \draw[->] (0,-0.5,0) -- (0,#2,0) node[pos=1.1]{y};
  \draw[->] (0,0,-0.5) -- (0,0,#3) node[pos=1.1]{z};}

\begin{tikzpicture}[3d view]
  \simplecuboid{2}{2}{2}
  \simpleaxes{2}{2}{2}
\end{tikzpicture}
\end{codeexample}
\endgroup

\begin{key}{/tikz/perspective=\meta{vanishing points}
    (default p=\{(10,0,0)\},q=\{(0,10,0)\},r=\{(0,0,20)\})}
  The `strength' of the perspective can be determined by setting the location of
  the vanishing points. The default values have a stronger perspective towards
  $x$ and $y$ than towards $z$, as shown below.
\begin{codeexample}[]
\begin{tikzpicture}[3d view,perspective]
  \simplecuboid{2}{2}{2}
  \simpleaxes{2}{2}{2}
\end{tikzpicture}
\end{codeexample}
  From this example it also shows that the maximum dimensions of the cuboid are
  no longer 2 by 2 by 2. This is inherent to the perspective projection.
  %
  \begin{key}{/tikz/perspective/p=\marg{x,y,z} (initially (0,0,0))}
    The location of the vanishing point that determines the `strength' of the
    perspective in $x$-direction can be set with the |p| key.
\begin{codeexample}[]
\begin{tikzpicture}[
  3d view,
  perspective={
    p = {(5,0,0)}}]
  \simplecuboid{2}{2}{2}
  \simpleaxes{2}{2}{2}
\end{tikzpicture}
\end{codeexample}
    Note also that when only |p| is provided, the perspective in $y$ and $z$
    direction is turned off.

    To turn of the perspective in $x$-direction, one must set the $x$ component
    of |p| to \texttt{0} (e.g. |p={(0,a,b)}|, where \texttt{a} and \texttt{b}
    can be any number and will be ignored). Or one can provide |q| and |r| and
    omit |p|.

    By changing the $y$ and $z$ components of |p|, one can achieve various
    effects.
\begin{codeexample}[]
\begin{tikzpicture}[
  3d view,
  perspective={
    p = {(5,0,1)}}]
  \simplecuboid{2}{2}{2}
  \simpleaxes{2}{2}{2}
\end{tikzpicture}
\end{codeexample}
\begin{codeexample}[]
\begin{tikzpicture}[
  3d view,
  perspective={
    p = {(5,1,0)}}]
  \simplecuboid{2}{2}{2}
  \simpleaxes{2}{2}{2}
\end{tikzpicture}
\end{codeexample}
\begin{codeexample}[]
\begin{tikzpicture}[
  3d view,
  perspective={
    p = {(5,1,1)}}]
  \simplecuboid{2}{2}{2}
  \simpleaxes{2}{2}{2}
\end{tikzpicture}
\end{codeexample}
  \end{key}
  %
  \begin{key}{/tikz/perspective/q=\marg{x,y,z} (initially (0,0,0))}
    Similar to |p|, but can be turned off by setting its $y$ component to
    \texttt{0}.
\begin{codeexample}[]
\begin{tikzpicture}[
  3d view,
  perspective={
    q = {(0,5,0)}}]
  \simplecuboid{2}{2}{2}
  \simpleaxes{2}{2}{2}
\end{tikzpicture}
\end{codeexample}
  \end{key}
  %
  \begin{key}{/tikz/perspective/r=\marg{x,y,z} (initially (0,0,0))}
    Similar to |p|, but can be turned off by setting its $z$ component to
    \texttt{0}.
\begin{codeexample}[]
\begin{tikzpicture}[
  3d view,
  perspective={
    r = {(0,0,5)}}]
  \simplecuboid{2}{2}{2}
  \simpleaxes{2}{2}{2}
\end{tikzpicture}
\end{codeexample}
  \end{key}
\end{key}

\subsection{Shortcomings}
  Currently a number of things are not working, mostly due to the fact that PGF
  uses a 2D coordinate system underwater, and perspective projection is a
  non-linear affine transformation which needs to be aware of all three
  coordinates. These three coordinates are currently lost when processing a 3D
  coordinate.
  The issues include, but possibly are not limited to:
  \begin{itemize}
    \item Keys like |shift|, |xshift|, |yshift| are not working
    \item Keys like |rotate around x|, |rotate around y|, and |rotate around z|
      are not working
    \item Units are not working
    \item Most keys from the |3d| library are unsupported, e.g. all the
      |canvas is .. plane| keys.
  \end{itemize}

\subsection{Examples}
An |r| that lies `below' your drawing can mimic a macro effect.
\nopagebreak
\begin{codeexample}[]
\begin{tikzpicture}[
  isometric view,
  perspective={
    p = {(8,0,0)},
    q = {(0,8,0)},
    r = {(0,0,-8)}}]

  \simplecuboid{2}{2}{2}]

\end{tikzpicture}
\end{codeexample}

A peculiar phenomenon inherent to perspective drawing, is that however great
your coordinate will become in the direction of the vanishing point, it will
never reach it.
\nopagebreak
\begin{codeexample}[]
\begin{tikzpicture}[
  isometric view,
  perspective={
    p = {(4,0,0)},
    q = {(0,4,0)}}]

    \node[fill=red,circle,inner sep=1.5pt,label=above:p] at (4,0,0){};

    \foreach \i in {0,...,100}{
      \filldraw[fill = gray] (tpp cs:x=\i,y=0,z=0)
        -- (tpp cs:x=\i+0.5,y=0,z=0)
        -- (tpp cs:x=\i+0.5,y=2,z=0)
        -- (tpp cs:x=\i,y=2,z=0)
        -- cycle;}
\end{tikzpicture}
\end{codeexample}

Even for simple examples, the added perspective might add another `dimension' to
your drawing. In this case, two vanishing points give a more intuitive result
then three would.
\nopagebreak
\begin{codeexample}[]
\begin{tikzpicture}[
  scale=0.7,
  3d view,
  perspective={
    p = {(20,0,0)},
    q = {(0,20,0)}}]

  \filldraw[fill=brown] (tpp cs:x=0,y=0,z=0)
    -- (tpp cs:x=0,y=4,z=0)
    -- (tpp cs:x=0,y=4,z=2)
    -- (tpp cs:x=0,y=2,z=4)
    -- (tpp cs:x=0,y=0,z=2) -- cycle;
  \filldraw[fill=red!70!black] (tpp cs:x=0,y=0,z=2)
    -- (tpp cs:x=5,y=0,z=2)
    -- (tpp cs:x=5,y=2,z=4)
    -- (tpp cs:x=0,y=2,z=4) -- cycle;
  \filldraw[fill=brown!80!white] (tpp cs:x=0,y=0,z=0)
    -- (tpp cs:x=0,y=0,z=2)
    -- (tpp cs:x=5,y=0,z=2)
    -- (tpp cs:x=5,y=0,z=0) -- cycle;
\end{tikzpicture}
\end{codeexample}

With the vanishing points nearby, the distortion of parallel lines becomes very
strong. This might lead to \texttt{Dimension too large} errors.
\nopagebreak
\begin{codeexample}[]
\begin{tikzpicture}[
  3d view,
  perspective={
    p = {(2,0,0)},
    q = {(0,2,0)},
    r = {(0,0,2)}},
  scale=4,
  vanishing point/.style={fill,circle,inner sep=2pt}]

  \simplecuboid{3}{1}{2}

  \node[vanishing point,label = right:p] (p) at (2,0,0){};
  \node[vanishing point,label = left:q] (q) at (0,2,0){};
  \node[vanishing point,label = above:r] (r) at (0,0,2){};

  \begin{scope}[dotted]
    \foreach \y in {0,1}{
      \foreach \z in {0,2}{
        \draw (tpp cs:x=0,y=\y,z=\z) -- (p.center);}}
    \foreach \x in {0,3}{
      \foreach \z in {0,2}{
        \draw (tpp cs:x=\x,y=0,z=\z) -- (q.center);}}
    \foreach \x in {0,3}{
      \foreach \y in {0,1}{
        \draw (tpp cs:x=\x,y=\y,z=0) -- (r.center);}}
  \end{scope}
\end{tikzpicture}
\end{codeexample}

% A more complex example.
\iffalse
Of course these examples can become as complex as desired, but as with any 3D
drawing using \tikzname, the order of drawing commands is important and can
become increasingly more complex.
\nopagebreak
\begin{codeexample}[]
\begin{tikzpicture}[
  cycle of vertices/.style 2 args={
    insert path={
      foreach \i [count=\j,evaluate=\j as \k using
        {ifthenelse(\j==1,"","-- "}] in {#2}{\k (vert-#1-\i)} -- cycle}},
  scale=0.7,
  line join=round,
  bottom/.style={draw=white!50!black,fill=white!40!black},
  front/.style={draw=white!50!black,fill=black},
  side/.style={draw=white!50!black,fill=white!80!black},
]
  \begin{scope}[
    3d view={-20}{0},
    perspective={
      p = {(20,0,0)},
      q = {(0,20,0)},
      r = {(5,1,50)},
    }]
    \path foreach \x/\y/\z [count=\i] in {
      3.5/2.0/0.0,3.5/2.0/4.0,6.0/2.0/4.0,6.5/2.0/3.5,6.5/2.0/0.5,6.0/2.0/0.0,
      4.5/2.0/1.0,4.5/2.0/3.0,5.5/2.0/3.0,5.5/2.0/1.0,3.5/0.0/0.0,3.5/0.0/4.0,
      6.0/0.0/4.0,6.5/0.0/3.5,6.5/0.0/0.5,6.0/0.0/0.0,4.5/0.0/1.0,4.5/0.0/3.0,
      5.5/0.0/3.0,5.5/0.0/1.0%
    }{(tpp cs:x=\x,y=\y,z=\z) coordinate[name=vert-D-\i]};
    \filldraw[front,cycle of vertices={D}{1,...,6},
      cycle of vertices={D}{7,10,9,8}];
    \filldraw[side,cycle of vertices={D}{10,9,19,20}];
    \filldraw[bottom,cycle of vertices={D}{8,9,19,18}];
    \filldraw[front,cycle of vertices={D}{11,...,16},
      cycle of vertices={D}{17,20,19,18}];
    \filldraw[side,cycle of vertices={D}{1,2,12,11}];
    % '3'
    \path foreach \x/\y/\z [count=\i] in {
      0.0/2.0/0.0,0.0/2.0/1.0,2.0/2.0/1.0,2.0/2.0/1.5,0.0/2.0/1.5,0.0/2.0/2.5,
      2.0/2.0/2.5,2.0/2.0/3.0,0.0/2.0/3.0,0.0/2.0/4.0,3.0/2.0/4.0,3.0/2.0/0.0,
      0.0/0.0/0.0,0.0/0.0/1.0,2.0/0.0/1.0,2.0/0.0/1.5,0.0/0.0/1.5,0.0/0.0/2.5,
      2.0/0.0/2.5,2.0/0.0/3.0,0.0/0.0/3.0,0.0/0.0/4.0,3.0/0.0/4.0,3.0/0.0/0.0%
    }{(tpp cs:x=\x,y=\y,z=\z) coordinate[name=vert-3-\i]};
    \filldraw[front,cycle of vertices={3}{1,...,12}];
    \filldraw[side,cycle of vertices={3}{3,4,16,15}];
    \filldraw[side,cycle of vertices={3}{7,8,20,19}];
    \filldraw[side,cycle of vertices={3}{1,2,14,13}];
    \filldraw[side,cycle of vertices={3}{5,6,18,17}];
    \filldraw[side,cycle of vertices={3}{9,10,22,21}];
    \filldraw[bottom,cycle of vertices={3}{4,5,17,16}];
    \filldraw[bottom,cycle of vertices={3}{8,9,21,20}];
    \filldraw[front,cycle of vertices={3}{13,...,24}];
  \end{scope}
\end{tikzpicture}
\end{codeexample}
\fi