OSDN Git Service

cc58ad9b19eea992319732eeb338dbd94ca8daab
[proj16/16.git] / 16 / PCGPE10 / PERSPECT.TXT
1 \r
2                    ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿\r
3                    ³ Perspective Transforms ³\r
4                    ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ\r
5 \r
6         By Andre Yew (andrey@gluttony.ugcs.caltech.edu)\r
7 \r
8 \r
9 \r
10     This is how I learned perspective transforms --- it was\r
11 intuitive and understandable to me, so perhaps it'll be to\r
12 others as well.  It does require knowledge of matrix math\r
13 and homogeneous coordinates.  IMO, if you want to write a\r
14 serious renderer, you need to know both.\r
15 \r
16    First, let's look at what we're trying to do:\r
17                S (screen)\r
18                |    * P (y, z)\r
19                |   /|\r
20                |  / |\r
21                | /  |\r
22                |/   |\r
23                * R  |\r
24              / |    |\r
25             /  |    |\r
26            /   |    |\r
27    E (eye)/    |    | W\r
28 ---------*-----|----*-------------\r
29          <- d -><-z->\r
30 \r
31    E is the eye, P is the point we're trying to project, and\r
32 R is its projected position on the screen S (this is the point\r
33 you want to draw on your monitor).  Z goes into the monitor (left-\r
34 handed coordinates), with X and Y being the width and height of the\r
35 screen.  So let's find where R is:\r
36 \r
37     R = (xs, ys)\r
38 \r
39     Using similar triangles (ERS and EPW)\r
40 \r
41     xs/d = x/(z + d)\r
42     ys/d = y/(z + d)\r
43     (Use similar triangles to determine this)\r
44 \r
45     So,\r
46 \r
47     xs = x*d/(z + d)\r
48     ys = y*d/(z + d)\r
49 \r
50     Express this homogeneously:\r
51 \r
52     R = (xs, ys, zs, ws).\r
53 \r
54     Make xs = x*d\r
55          ys = y*d\r
56          zs = 0 (the screen is a flat plane)\r
57          ws = z + d\r
58 \r
59     and express this as a vector transformed by a matrix:\r
60 \r
61     [x y z 1][ d 0 0 0 ]\r
62              [ 0 d 0 0 ]    =  R\r
63              [ 0 0 0 1 ]\r
64              [ 0 0 0 d ]\r
65 \r
66     The matrix on the right side can be called a perspective transform.\r
67 But we aren't done yet.  See the zero in the 3rd column, 3rd row of\r
68 the matrix?  Make it a 1 so we retain the z value (perhaps for some\r
69 kind of Z-buffer).  Also, this isn't exactly what we want since we'd\r
70 also like to have the eye at the origin and we'd like to specify some\r
71 kind of field-of-view.  So, let's translate the matrix (we'll call\r
72 it M) by -d to move the eye to the origin:\r
73 \r
74     [ 1 0 0  0 ][ d 0 0 0 ]\r
75     [ 0 1 0  0 ][ 0 d 0 0 ]\r
76     [ 0 0 1  0 ][ 0 0 1 1 ]  <--- Remember, we put a 1 in (3,3) to\r
77     [ 0 0 -d 1 ][ 0 0 0 d ]       retain the z part of the vector.\r
78 \r
79     And we get:\r
80 \r
81     [ d 0 0  0 ]\r
82     [ 0 d 0  0 ]\r
83     [ 0 0 1  1 ]\r
84     [ 0 0 -d 0 ]\r
85 \r
86     Now parametrize d by the angle PEW, which is half the field-of-view\r
87 (FOV/2).  So we now want to pick a d such that ys = 1 always and we get\r
88 a nice relationship:\r
89 \r
90     d = cot( FOV/2 )\r
91 \r
92     Or, to put it another way, using this formula, ys = 1 always.\r
93 \r
94     Replace all the d's in the last perspective matrix and multiply\r
95 through by sin's:\r
96 \r
97     [ cos 0   0    0   ]\r
98     [ 0   cos 0    0   ]\r
99     [ 0   0   sin  sin ]\r
100     [ 0   0   -cos 0   ]\r
101 \r
102     With all the trig functions taking FOV/2 as their arguments.\r
103 Let's refine this a little further and add near and far Z-clipping\r
104 planes.  Look at the lower right 2x2 matrix:\r
105 \r
106    [ sin sin ]\r
107    [-cos 0   ]\r
108 \r
109    and replace the first column by a and b:\r
110 \r
111    [ a sin ]\r
112    [ b 0   ]\r
113    [ b 0   ]\r
114 \r
115    Transform out near and far boundaries represented homogeneously\r
116 as (zn, 1), (zf, 1), respectively and we get:\r
117 \r
118    (zn*a + b, zn*sin) and (zf*a + b, zf*sin).\r
119 \r
120    We want the transformed boundaries to map to 0 and 1, respectively,\r
121 so divide out the homogeneous parts to get normal coordinates and equate:\r
122 \r
123     (zn*a + b)/(zn*sin) = 0 (near plane)\r
124     (zf*a + b)/(zf*sin) = 1 (far plane)\r
125 \r
126    Now solve for a and b and we get:\r
127 \r
128    a = (zf*sin)/(zf - zn)\r
129      = sin/(1 - zn/zf)\r
130    b = -a*zn\r
131    b = -a*zn\r
132 \r
133    At last we have the familiar looking perspective transform matrix:\r
134 \r
135    [ cos( FOV/2 ) 0                        0            0 ]\r
136    [ 0            cos( FOV/2 )             0            0 ]\r
137    [ 0            0 sin( FOV/2 )/(1 - zn/zf) sin( FOV/2 ) ]\r
138    [ 0            0                    -a*zn            0 ]\r
139 \r
140    There are some pretty neat properties of the matrix.  Perhaps\r
141 the most interesting is how it transforms objects that go through\r
142 the camera plane, and how coupled with a clipper set up the right\r
143 way, it does everything correctly.  What's interesting about this\r
144 is how it warps space into something called Moebius space, which\r
145 is kind of like a fortune-cookie except the folds pass through\r
146 each other to connect the lower folds --- you really have to see\r
147 it to understand it.  Try feeding it some vectors that go off to\r
148 infinity in various directions (ws = 0) and see where they come\r
149 out.\r