summaryrefslogtreecommitdiff
path: root/graphics/sketch/Doc/sketch/Overview.html
blob: 4c8538d4dce4628af12554cf3e69e6b2eb07dfc7 (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
<html lang="en">
<head>
<title>Overview - Sketch</title>
<meta http-equiv="Content-Type" content="text/html">
<meta name="description" content="Sketch">
<meta name="generator" content="makeinfo 4.7">
<link title="Top" rel="start" href="index.html#Top">
<link rel="up" href="Building-a-drawing.html#Building-a-drawing" title="Building a drawing">
<link rel="prev" href="Building-a-drawing.html#Building-a-drawing" title="Building a drawing">
<link rel="next" href="A-technical-drawing.html#A-technical-drawing" title="A technical drawing">
<link href="http://www.gnu.org/software/texinfo/" rel="generator-home" title="Texinfo Homepage">
<!--
Copyright (C) 2005, 2006, 2007, 2008 Eugene K. Ressler.

This manual is for `sketch', version 0.2 (build 131),
Saturday, August 09, 2008, a program that converts descriptions of simple
three-dimensional scenes into static drawings. This version generates
`PSTricks' or `PGF/TikZ' code suitable for use with the
TeX document processing system.

`Sketch' is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.

Sketch is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with `sketch'; see the file COPYING.txt.  If not, see
http://www.gnu.org/copyleft.-->
<meta http-equiv="Content-Style-Type" content="text/css">
<style type="text/css"><!--
  pre.display { font-family:inherit }
  pre.format  { font-family:inherit }
  pre.smalldisplay { font-family:inherit; font-size:smaller }
  pre.smallformat  { font-family:inherit; font-size:smaller }
  pre.smallexample { font-size:smaller }
  pre.smalllisp    { font-size:smaller }
  span.sc { font-variant:small-caps }
  span.roman { font-family: serif; font-weight: normal; } 
--></style>
</head>
<body>
<div class="node">
<p>
<a name="Overview"></a>Next:&nbsp;<a rel="next" accesskey="n" href="A-technical-drawing.html#A-technical-drawing">A technical drawing</a>,
Previous:&nbsp;<a rel="previous" accesskey="p" href="Building-a-drawing.html#Building-a-drawing">Building a drawing</a>,
Up:&nbsp;<a rel="up" accesskey="u" href="Building-a-drawing.html#Building-a-drawing">Building a drawing</a>
<hr><br>
</div>

<!-- node-name,  next,  previous,  up -->
<h3 class="section">4.1 Overview</h3>

<p>As an overview, let's develop a diagram that shows how a perspective
projection transform
<a name="index-perspective-projection-399"></a><a name="index-transform-400"></a><a name="index-projection_002c-perspective-401"></a>works.  We'll start with the traditional reference object
used in computer graphics textbooks, a house-shaped prism.  Begin
by defining the points of the house.  Rather than defining the faces
of the house as polygons and transforming those, we are going to
transform the points themselves with <code>sketch</code> arithmetic so that
we have names for the transformed points later. 
<a name="index-def-402"></a>
<pre class="verbatim">
  % right side (outside to right)
  def R1 (1,1,1) def R2 (1,-1,1) def R3 (1,-1,-1) def R4 (1,1,-1)
  def R5 (1,1.5,0)

  % left side (outside to right--backward)
  def W  [2,0,0]
  def L1 (R1)-[W] def L2 (R2)-[W] def L3 (R3)-[W] def L4 (R4)-[W]
  def L5 (R5)-[W]
</pre>
To add a door to the house, we use a polygon slightly in
front of the foremost face of the house.
<pre class="verbatim">
  % door
  def e .01
  def D1 (0,-1,1+e) def D2 (.5,-1,1+e) def D3 (.5,0,1+e) def D4 (0,0,1+e)
</pre>
Now let's create a new set of points that are a to-be-determined
transform of the originals.
<pre class="verbatim">
  def hp scale(1) % house positioner
  def pR1 [[hp]]*(R1) def pR2 [[hp]]*(R2) def pR3 [[hp]]*(R3)
  def pR4 [[hp]]*(R4) def pR5 [[hp]]*(R5)
  def pL1 [[hp]]*(L1) def pL2 [[hp]]*(L2) def pL3 [[hp]]*(L3)
  def pL4 [[hp]]*(L4) def pL5 [[hp]]*(L5)
  def pD1 [[hp]]*(D1) def pD2 [[hp]]*(D2) def pD3 [[hp]]*(D3)
  def pD4 [[hp]]*(D4) 
</pre>
Note the use of a <dfn>transform definition</dfn>
<a name="index-transform-definition-403"></a><a name="index-definition_002c-transform-404"></a><a name="index-_005b_005bfoo_005d_005d_0040r_007b_002c-transform-reference_007d-405"></a>and
<dfn>transform references</dfn>. 
<a name="index-transform-reference-406"></a><a name="index-reference_002c-transform-407"></a><a name="index-_005b_005bfoo_005d_005d_0040r_007b_002c-transform-reference_007d-408"></a>Now define the seven polygonal faces of the house and the door using
the transformed points as vertices.  Be careful with vertex order! 
<a name="index-polygon-vertex-order-409"></a><a name="index-order_002c-polygon-vertex-410"></a><a name="index-fillcolor-411"></a><a name="index-def-412"></a><a name="index-polygon-413"></a><a name="index-_0040_007b-_0040_007d_0040r_007b_002c-block-drawable_007d-414"></a>
<pre class="verbatim">
  def rgt polygon (pR1)(pR2)(pR3)(pR4)(pR5)
  def lft polygon (pL5)(pL4)(pL3)(pL2)(pL1)
  def frt polygon (pR2)(pR1)(pL1)(pL2)
  def bck polygon (pR4)(pR3)(pL3)(pL4)
  def tfr polygon (pR1)(pR5)(pL5)(pL1)
  def tbk polygon (pR5)(pR4)(pL4)(pL5)
  def bot polygon (pR2)(pL2)(pL3)(pR3)
  def door polygon[fillcolor=brown] (pD1)(pD2)(pD3)(pD4)
  def house { {rgt}{lft}{frt}{bck}{tfr}{tbk}{bot}{door} }
</pre>
Time for a sanity check.  Add the line
<a name="index-_0040_007bfoo_0040_007d_0040r_007b_002c-drawable-reference_007d-415"></a><a name="index-reference_002c-drawable-416"></a>
<pre class="verbatim">
  {house}
</pre>
and this is what we get.

<div align="center"><img src="ex130.png" alt="ex130.png"></div>

<p class="noindent">This is correct, but does not reveal very much.  Common errors are
misplaced vertices and polygons missing entirely due to incorrect
vertex order. 
<a name="index-polygon-vertex-order-417"></a><a name="index-order_002c-polygon-vertex-418"></a>To rule these out, let's inspect all sides of the
house. This is not hard. Merely replace the reference
<tt>{house}</tt> with a <code>repeat</code>. See <a href="Repeats.html#Repeats">Repeats</a>. 
<a name="index-_0040_007bfoo_0040_007d_0040r_007b_002c-drawable-reference_007d-419"></a><a name="index-reference_002c-drawable-420"></a><a name="index-repeat-421"></a><a name="index-rotate-422"></a><a name="index-translate-423"></a>
<pre class="verbatim">
  repeat { 13, rotate(30, [1,2,3]), translate([3,0,0]) } {house}
</pre>
<div align="center"><img src="ex140.png" alt="ex140.png"></div>

<p class="noindent">Again things look correct.  Note that the hidden surface algorithm
handles intersecting polygons correctly where some copies of the house
overlap.

   <p>Let's lay out the geometry of perspective projection of the house onto
a plane with rays passing through the origin.  Begin by positioning the
house twelve units back on the negative z-axis and adding a set
of coordinate axes.  To move the house we need only change the &ldquo;house
positioning&rdquo; transform defined earlier. 
<a name="index-def-424"></a><a name="index-rotate-425"></a><a name="index-translate-426"></a><a name="index-arrows-427"></a><a name="index-linewidth-428"></a><a name="index-linecolor-429"></a><a name="index-linestyle-430"></a><a name="index-special-431"></a><a name="index-line-432"></a>
<pre class="verbatim">
  def hp rotate(-40, [0,1,0]) then translate([0,0,-12])
  def axes {
    def sz 1
    line [arrows=&lt;->] (sz,0,0)(O)(0,sz,0)
    line [arrows=->]  (O)(0,0,sz)
    line [linewidth=.2pt,linecolor=blue,linestyle=dashed] (O)(0,0,-10)
    special |\uput[r]#1{$x$}\uput[u]#2{$y$}\uput[l]#3{$z$}|
      (sz,0,0)(0,sz,0)(0,0,sz)
  }
</pre>

   <p>Time for another test.  Let's build a real view transform,
creating a <dfn>virtual camera</dfn>
<a name="index-virtual-camera-433"></a>to look at the scene we are constructing.  Replace the <code>repeat</code>
with
<pre class="verbatim">
  def eye (10,4,10)
  def look_at (0,0,-5)
  put { view((eye), (look_at)) } { {house}{axes} }
</pre>
The <dfn>view transform</dfn> repositions the scene so that the point
<code>eye</code> is at the origin and the direction from <code>eye</code> to
<code>look_at</code> is the negative z-axis.  This requires a
rotation and a translation that are all packed into the constructor
<code>view</code>.

<div align="center"><img src="ex150.png" alt="ex150.png"></div>

<p class="noindent">This is starting to look good!  Add the projection plane half way
between the origin and the house at z=-5.  We'll try
the angle argument feature of <code>special</code> to position a label.
<pre class="verbatim">
  def p 5 % projection distance (plane at z=-p)
  def projection_plane {
    def sz 1.5
    polygon (-sz,-sz,-p)(sz,-sz,-p)(sz,sz,-p)(-sz,sz,-p)
    special |\rput[b]#1-2#3{\footnotesize\sf projection plane}| 
      (-sz,-sz,-p)(sz,-sz,-p)(0,-sz+.1,-p)
  }
</pre>
Add <tt>{projection_plane}</tt> to the list of objects in the
<code>put</code> above.

<div align="center"><img src="ex160.png" alt="ex160.png"></div>

   <p class="indent">The way we constructed the points of the house now makes it easy to
draw rays of projection.  We'll cast one ray from every visible vertex
of the house and define options so the appearance of
all rays can be changed at the same time.
<pre class="verbatim">
  def projection_rays {
    def rayopt [linewidth=.3pt,linecolor=lightgray]
    line [rayopt](O)(pR1) line [rayopt](O)(pR2) line[rayopt](O)(pR3)
    line [rayopt](O)(pR4) line [rayopt](O)(pR5)
    line [rayopt](O)(pL1) line [rayopt](O)(pL2) line[rayopt](O)(pL5)
    line [rayopt](O)(pD1) line [rayopt](O)(pD2) 
    line [rayopt](O)(pD3) line [rayopt](O)(pD4) 
  }
</pre>
The result is shown here.

<div align="center"><img src="ex170.png" alt="ex170.png"></div>

<p class="noindent">The rays pierce the projection plane at the corresponding points on
the perspective image we are trying to draw.  Albrecht D&uuml;rer and his
Renaissance contemporaries had the same idea in the early 1500's.

<div align="center"><img src="duerer.png" alt="duerer.png"></div>

   <p>All that's left is to find a way to connect the points of the house
on the projection plane.  We could pull out a good computer graphics
text, find the necessary matrix, and enter it ourselves as a
transform literal.  See <a href="Transform-literals.html#Transform-literals">Transform literals</a>. That work is
already done, however.  We can use the <code>project(p)</code> constructor.

   <p>There are still some details that require care.  Projection will
flatten whatever is transformed onto the plane z=-p.  Therefore
any part of the house could disappear behind the projection plane (the
hidden surface algorithm orders objects at the same depth
arbitrarily).  The door may also disappear behind the front of the
house.  To make sure everything remains visible, we'll place the house
a tiny bit in front of the projection plane and a second copy of the
door in front of the house.
<pre class="verbatim">
  def projection {
    % e is a small number defined above
    put { project(p) then translate([0,0,1*e]) } {house}
    put { project(p) then translate([0,0,2*e]) } {door}
  }
</pre>

<div align="center"><img src="ex180.png" alt="ex180.png"></div>

   <p>If you have studied and understand all this, you are well on the way
to success with <code>sketch</code>.  Not shown are the 20 or so iterations
that were required to find a reasonable viewing angle and house
position, etc.  Nonetheless, this drawing was completed in about an
hour.  While a GUI tool may have been a little faster, it is unlikely
that a new drawing, itself a perspective projection of the scene,
could be generated with two more minutes' work!  Just change the view
transform to
<pre class="verbatim">
  put { view((eye), (look_at)) then perspective(9) } { ...
</pre>
and produce this.

<div align="center"><img src="ex190.png" alt="ex190.png"></div>

   </body></html>