服务器上的网站不能访问,建公司网站要提供哪些素材,找合作项目的平台,网站建设公司被网监大队检查观测主要解决的问题是如何把物体的三维“模型”变成我们在屏幕所看到的二维“图片”#xff0c;我们在计算机看到实体模型可以分成这样几步#xff1a; 相机变换(camera transformation)或眼变换(eye transformation)#xff1a;想象把相机放在任意一个位置来观测物体#…观测主要解决的问题是如何把物体的三维“模型”变成我们在屏幕所看到的二维“图片”我们在计算机看到实体模型可以分成这样几步 相机变换(camera transformation)或眼变换(eye transformation)想象把相机放在任意一个位置来观测物体我们首先就要把物体的世界坐标转换为相机坐标这一步称为相机变换或眼变换。投影变换(projection transformation)相机把物体拍成照片本质是从三维的相机坐标转化为二维的平面坐标这一步称为投影变换。投影可以分为正射投影和透视投影。视口变换(viewport transformation)或窗口变换(windowing transformation)相机拍成的图片最后是要显示在屏幕上我们需要把二维的图片坐标再转换为电脑屏幕的像素坐标这一步称为视口变换或窗口变换。
下面这个照相的类比非常地生动形象。 2.1 Viewport Transformation-视口变换
一般来说我们规定相机沿着 − z -\mathbf{z} −z方向在观测过程中为了简化会使用canonical view volume(CCV)它是一个正方体 x x x, y y y, z z z坐标都位于 − 1 -1 −1到 1 1 1之间也即 ( x , y , z ) ∈ [ − 1 , 1 ] 3 (x,y,z)\in[-1,1]^3 (x,y,z)∈[−1,1]3我们将 x − 1 x-1 x−1投影到电脑屏幕的左侧将 x 1 x1 x1投影到屏幕的右侧将 y − 1 y-1 y−1投影到屏幕的底部将 y 1 y1 y1投影到屏幕的顶部。 如果我们定义屏幕每个像素的长和宽为1最小的像素中心坐标是 ( 0 , 0 ) (0,0) (0,0)则图像的中心到其边界为 0.5 0.5 0.5如果屏幕上的像素总长度为 n x n_x nx总宽度为 n y n_y ny那么我们可以将canonical view volume(CCV)的 x o y \mathbf{xoy} xoy平面的方形 [ − 1 , 1 ] 2 [-1,1]^2 [−1,1]2映射为长方形 [ − 0.5 , n x − 0.5 ] × [ − 0.5 , n y − 0.5 ] [-0.5,n_x-0.5]\times[-0.5,n_y-0.5] [−0.5,nx−0.5]×[−0.5,ny−0.5]。 注意我们现在假设所有的线都在CCV正方体里后面这个假设将在讲裁剪的时候放松这个条件。 对于视口变换我们需要想把CCV正方体的 x o y \mathbf{xoy} xoy平面进行放缩然后将原点平移到屏幕的左下角CCV的原点在 x o y \mathbf{xoy} xoy正方形的正中心其可以写作一个二维的变换【这里相当于计算上面的线性映射 − 1 → − 0.5 , 1 → n x − 0.5 ( n y − 0.5 ) -1\rightarrow -0.5,1\rightarrow n_x-0.5(n_y-0.5) −1→−0.5,1→nx−0.5(ny−0.5)】 [ x screen y screen 1 ] [ n x 2 0 n x − 1 2 0 n y 2 n y − 1 2 0 0 1 ] [ x canonical y canonical 1 ] \begin{bmatrix} x_{\text {screen }} \\ y_{\text {screen }} \\ 1 \end{bmatrix}\begin{bmatrix} \frac{n_{x}}{2} 0 \frac{n_{x}-1}{2} \\ 0 \frac{n_{y}}{2} \frac{n_{y}-1}{2} \\ 0 0 1 \end{bmatrix}\begin{bmatrix} x_{\text {canonical }} \\ y_{\text {canonical }} \\ 1 \end{bmatrix} xscreen yscreen 1 2nx0002ny02nx−12ny−11 xcanonical ycanonical 1
这里忽略了 z \mathbf{z} z轴的坐标因为投影最终和 z z z坐标无关这里我们可以扩充矩阵尽管在这里没有用 M v p [ n x 2 0 0 n x − 1 2 0 n y 2 0 n y − 1 2 0 0 1 0 0 0 0 1 ] \mathbf{M}_{\mathrm{vp}}\begin{bmatrix} \frac{n_{x}}{2} 0 0 \frac{n_{x}-1}{2} \\ 0 \frac{n_{y}}{2} 0 \frac{n_{y}-1}{2} \\ 0 0 1 0 \\ 0 0 0 1 \end{bmatrix} Mvp 2nx00002ny0000102nx−12ny−101
2.2 Orthographic Projection Transformation-正射变换
我们通常想把在渲染某个空间区域的几何元素而不是CCV我们要调整我们的坐标轴的方向来实现正射变换让坐标轴的 − z -\mathbf{z} −z轴对着物体让 y \mathbf{y} y轴朝上 x \mathbf{x} x轴按照右手定则定义。我们看到的view volume是一个 [ l , r ] × [ b , t ] × [ f , n ] [l,r]\times[b,t]\times[f,n] [l,r]×[b,t]×[f,n]的box。 关于 l , r , b , y , f , n l,r,b,y,f,n l,r,b,y,f,n的物理含义可以看下面的表格
{% tabs active:1 align:center %} planemeaningplanemeaning x l xl xlleft plane x r xr xrright plane y b yb ybbottom plane y t yt yttop plane z n zn znnear plane z f zf zffar plane
{% endtabs %}
我们同样可以写出变换矩阵把这个box映射为CCV参考原书公式的6.7英文原版132页,变换的好处是简化数字在 − 1 -1 −1到 1 1 1之间方便后续计算 M orth [ 2 r − l 0 0 0 0 2 t − b 0 0 0 0 2 n − f 0 0 0 0 1 ] [ 1 0 0 − r l 2 0 1 0 − t b 2 0 0 1 − n f 2 0 0 0 1 ] [ 2 r − l 0 0 − r l r − l 0 2 t − b 0 − t b t − b 0 0 2 n − f − n f n − f 0 0 0 1 ] \begin{aligned}\mathbf{M}_{\text {orth }}\left[\begin{array}{cccc} \frac{2}{r-l} 0 0 0 \\ 0 \frac{2}{t-b} 0 0 \\ 0 0 \frac{2}{n-f} 0 \\ 0 0 0 1 \end{array}\right]\left[\begin{array}{cccc} 1 0 0 -\frac{rl}{2} \\ 0 1 0 -\frac{tb}{2} \\ 0 0 1 -\frac{nf}{2} \\ 0 0 0 1 \end{array}\right]\\\begin{bmatrix} \frac{2}{r-l} 0 0 -\frac{rl}{r-l} \\ 0 \frac{2}{t-b} 0 -\frac{tb}{t-b} \\ 0 0 \frac{2}{n-f} -\frac{nf}{n-f} \\ 0 0 0 1 \end{bmatrix}\end{aligned} Morth r−l20000t−b20000n−f200001 100001000010−2rl−2tb−2nf1 r−l20000t−b20000n−f20−r−lrl−t−btb−n−fnf1
现在我们可以转换视角中任意看到的点 ( x , y , z ) (x,y,z) (x,y,z)在像素上看到的位置 ( x p i x e l , y p i x e l , z c a n o n i c a l ) (x_{pixel},y_{pixel},z_{canonical}) (xpixel,ypixel,zcanonical) [ x pixel y pixel z canonical 1 ] ( M v p M orth ) [ x y z 1 ] \left[\begin{array}{c} x_{\text {pixel }} \\ y_{\text {pixel }} \\ z_{\text {canonical }} \\ 1 \end{array}\right]\left(\mathbf{M}_{\mathrm{vp}} \mathbf{M}_{\text {orth }}\right)\left[\begin{array}{c} x \\ y \\ z \\ 1 \end{array}\right] xpixel ypixel zcanonical 1 (MvpMorth ) xyz1
CCV坐标变换至屏幕坐标直线算法流程 z \mathbf{z} z坐标的范围是 [ − 1 , 1 ] [-1,1] [−1,1]现在我们还没有用到这将在z-buffer算法时很有用。
2.3 Camera Transformation-相机变换
当我们需要改变3D视角和观测的方向时我们需要重新定义观测者的位置和方向改变相机的放置位置。可以定义相机坐标系我们期望的相机的朝向可以由两个向量 g \mathbf{g} g和向量 t \mathbf{t} t来定义以及一个点 e \mathbf{e} e来表示。 e \mathbf{e} e相机位置 g \mathbf{g} g观测方向 t \mathbf{t} t上视方向
于是我们可以根据上面所说的向量和电定义我们的相机坐标系 u v w \mathbf{uvw} uvw世界坐标系是 x y z \mathbf{xyz} xyz其中坐标系的原点就是 e \mathbf{e} e v \mathbf{v} v轴和 t \mathbf{t} t矢量方向相同 w \mathbf{w} w轴和 − g -\mathbf{g} −g矢量方向相同 u \mathbf{u} u轴根据右手定则确定。 w − g ∥ g ∥ u t × w ∥ t × w ∥ v w × u \begin{aligned} \mathbf{w} -\frac{\mathbf{g}}{\|\mathbf{g}\|} \\ \mathbf{u} \frac{\mathbf{t} \times \mathbf{w}}{\|\mathbf{t} \times \mathbf{w}\|} \\ \mathbf{v} \mathbf{w} \times \mathbf{u} \end{aligned} wuv−∥g∥g∥t×w∥t×ww×u 接下来我们会把世界坐标系的点坐标转换到相机坐标系中。我们可以把变换矩阵分解为两步先平移再旋转。
由于将坐标系 u v w \mathbf{uvw} uvw转换为坐标系 x y z \mathbf{xyz} xyz的变换矩阵可以看做是 M c a m − 1 [ u v w e 0 0 0 1 ] \mathbf{M}_{\mathrm{cam}}^{-1}\left[\begin{array}{cccc} \mathbf{u} \mathbf{v} \mathbf{w} \mathbf{e} \\ 0 0 0 1 \end{array}\right] Mcam−1[u0v0w0e1]
相机坐标系是要将坐标系 x y z \mathbf{xyz} xyz转换到坐标系 u v w \mathbf{uvw} uvw于是这等价于对矩阵求一个逆。 M c a m [ u v w e 0 0 0 1 ] − 1 [ x u y u z u 0 x v y v z v 0 x w y w z w 0 0 0 0 1 ] [ 1 0 0 − x e 0 1 0 − y e 0 0 1 − z e 0 0 0 1 ] \mathbf{M}_{\mathrm{cam}}\left[\begin{array}{cccc} \mathbf{u} \mathbf{v} \mathbf{w} \mathbf{e} \\ 0 0 0 1 \end{array}\right]^{-1}\left[\begin{array}{cccc} x_{u} y_{u} z_{u} 0 \\ x_{v} y_{v} z_{v} 0 \\ x_{w} y_{w} z_{w} 0 \\ 0 0 0 1 \end{array}\right]\left[\begin{array}{cccc} 1 0 0 -x_{e} \\ 0 1 0 -y_{e} \\ 0 0 1 -z_{e} \\ 0 0 0 1 \end{array}\right] Mcam[u0v0w0e1]−1 xuxvxw0yuyvyw0zuzvzw00001 100001000010−xe−ye−ze1
世界坐标正式投影变换至屏幕坐标画直线算法流程 2.4 Perspective Projective Transformations-透视变换
投影变换符合我们的视觉直观主要体现在有近大远小的特性平行线相交于一点。在实际的计算机图形中用得更多。 如上图所示我们从视点 e \mathbf{e} e沿着 g \mathbf{g} g方向看看到的实际的点的高度为 y y y反映在观察平面上高度为 y s y_s ys观察平面距离视点为 d d d实际的点距离视点为 z z z根据简单的相似三角形的关系我们有这里我们认为 z z z是距离为正数而不是坐标意义下的负数 y s d z y y_{s}\frac{d}{z} y yszdy
虎书里还提到了线性有理变换这里把变换矩阵简单写一下感兴趣可以直接看虎书 [ x ~ y ~ z ~ w ~ ] [ a 1 b 1 c 1 d 1 a 2 b 2 c 2 d 2 a 3 b 3 c 3 d 3 e f g h ] [ x y z 1 ] \left[\begin{array}{c} \tilde{x} \\ \tilde{y} \\ \tilde{z} \\ \tilde{w} \end{array}\right]\left[\begin{array}{cccc} a_{1} b_{1} c_{1} d_{1} \\ a_{2} b_{2} c_{2} d_{2} \\ a_{3} b_{3} c_{3} d_{3} \\ e f g h \end{array}\right]\left[\begin{array}{c} x \\ y \\ z \\ 1 \end{array}\right] x~y~z~w~ a1a2a3eb1b2b3fc1c2c3gd1d2d3h xyz1 ( x ′ , y ′ , z ′ ) ( x ~ / w ~ , y ~ / w ~ , z ~ / w ~ ) \left(x^{\prime}, y^{\prime}, z^{\prime}\right)(\tilde{x} / \tilde{w}, \tilde{y} / \tilde{w}, \tilde{z} / \tilde{w}) (x′,y′,z′)(x~/w~,y~/w~,z~/w~)
上面的第二个公式刚好使用了计算机图形学笔记1-Transformation Matrix-变换*中注意的第二点齐次坐标的等价性。使用上述的变换可以进行下面的操作 前面我们已经讲了二维的情况。但是我们实际要处理的是三维的情况。经过投影变换就好像把一个棱台给变成了一个轴平行的box。这将方便我们使用正交投影变换矩阵变成CCV。 这里我们就搬出之前在相机变换所建立的坐标系我们依然使用 z n zn zn近端平面和 z f zf zf远端平面并使用 z n zn zn近端平面作为观察平面。需要注意的是上面的 n n n和 z z z在坐标系定义下都是小于 0 0 0的。对于投影变换后的 x s x_s xs和 y s y_s ys类似前面二维情况 y s n z y x s n z x y_{s}\frac{n}{z} y\quad x_{s}\frac{n}{z} x ysznyxsznx
我们可以整理成矩阵的形式 ( x y z 1 ) ⇒ ( n x / z n y / z u n k n o w n 1 ) ≜ ( n x n y u n k n o w n z ) \begin{pmatrix} x\\y\\z\\1 \end{pmatrix}\Rightarrow\begin{pmatrix} nx/z\\ny/z\\\mathrm{unknown}\\1 \end{pmatrix}\triangleq\begin{pmatrix} nx\\ny\\\mathrm{unknown}\\z \end{pmatrix} xyz1 ⇒ nx/zny/zunknown1 ≜ nxnyunknownz
于是我们所要求的投影变换矩阵满足 P ( x y z 1 ) ( n x n y u n k n o w n z ) ⇒ P ( n 0 0 0 0 n 0 0 ? ? ? ? 0 0 1 0 ) \mathbf{P}\begin{pmatrix} x\\y\\z\\1 \end{pmatrix}\begin{pmatrix} nx\\ny\\\mathrm{unknown}\\z \end{pmatrix}\Rightarrow \mathbf{P} \left(\begin{array}{cccc} n 0 0 0 \\ 0 n 0 0 \\ ? ? ? ? \\ 0 0 1 0 \end{array}\right) P xyz1 nxnyunknownz ⇒P n0?00n?000?100?0
那么 z s z_{s} zs是多少呢对投影变换我们注意到 近端平面 z n zn zn的点映射以后点不发生变化。 远端平面 z f zf zf的点映射以后z坐标不变。 根据第(1)点近端平面 z n zn zn的点映射以后点不发生变化。我们有 P ( x y n 1 ) ( x y n 1 ) ≜ ( n x n y n 2 1 ) \mathbf{P}\begin{pmatrix} x\\y\\n\\1 \end{pmatrix}\begin{pmatrix} x\\y\\n\\1 \end{pmatrix} \triangleq\begin{pmatrix} nx\\ny\\n^2\\1 \end{pmatrix} P xyn1 xyn1 ≜ nxnyn21
所以 P \mathbf{P} P的第三行形式为 ( 0 0 A B ) \begin{pmatrix} 0\,0\,A\,B \end{pmatrix} (00AB)前两个元素为0是因为该齐次坐标的 z z z坐标为 n 2 n^2 n2和 x , y x,y x,y的取值无关。我们单独拿出第三行和齐次坐标相乘有 ( 0 0 A B ) ( x y n 1 ) n 2 ⇒ A n B n 2 \begin{pmatrix} 0 0 A B \end{pmatrix}\begin{pmatrix} x \\ y \\ n \\ 1 \end{pmatrix}n^{2}\Rightarrow AnBn^2 (00AB) xyn1 n2⇒AnBn2
根据第(2)点远端平面 z f zf zf的点映射以后z坐标不变。我们有 ( 0 0 f 1 ) ⇒ ( 0 0 f 1 ) ≜ ( 0 0 f 2 f ) ⇒ A f B f 2 \left(\begin{array}{l} 0 \\ 0 \\ f \\ 1 \end{array}\right) \Rightarrow\left(\begin{array}{l} 0 \\ 0 \\ f \\ 1 \end{array}\right)\triangleq\left(\begin{array}{c} 0 \\ 0 \\ f^{2} \\ f \end{array}\right)\Rightarrow AfBf^2 00f1 ⇒ 00f1 ≜ 00f2f ⇒AfBf2
于是我们有 { A n B n 2 A f B f 2 ⇒ { A n f B − n f \left\{\begin{aligned} AnBn^2\\ AfBf^2 \end{aligned}\right.\quad\Rightarrow\quad\left\{\begin{aligned} Anf\\ B-nf \end{aligned}\right. {AnBn2AfBf2⇒{AnfB−nf
这样我们就确定了投影变换的变换矩阵 P [ n 0 0 0 0 n 0 0 0 0 n f − f n 0 0 1 0 ] \mathbf{P}\begin{bmatrix} n 0 0 0 \\ 0 n 0 0 \\ 0 0 nf -f n \\ 0 0 1 0 \end{bmatrix} P n0000n0000nf100−fn0
经过投影变换最终我们看到坐标发生了如下的变化 P [ x y z 1 ] [ n x n y ( n f ) z − f n z ] ≜ [ n x z n y z n f − f n z 1 ] \mathbf{P}\left[\begin{array}{l} x \\ y \\ z \\ 1 \end{array}\right]\left[\begin{array}{c} n x \\ n y \\ (nf) z-f n \\ z \end{array}\right] \triangleq\left[\begin{array}{c} \frac{n x}{z} \\ \frac{n y}{z} \\ nf-\frac{f n}{z} \\ 1 \end{array}\right] P xyz1 nxny(nf)z−fnz ≜ znxznynf−zfn1
有时候我们想把屏幕坐标变换回世界坐标这时候我们就需要用到 P \mathbf{P} P的逆矩阵 P − 1 [ 1 n 0 0 0 0 1 n 0 0 0 0 0 1 0 0 − 1 f n n f f n ] ≜ [ f 0 0 0 0 f 0 0 0 0 0 f n 0 0 − 1 n f ] \mathbf{P}^{-1}\left[\begin{array}{cccc} \frac{1}{n} 0 0 0 \\ 0 \frac{1}{n} 0 0 \\ 0 0 0 1 \\ 0 0 -\frac{1}{f n} \frac{nf}{f n} \end{array}\right]\triangleq\left[\begin{array}{cccc} f 0 0 0 \\ 0 f 0 0 \\ 0 0 0 f n \\ 0 0 -1 nf \end{array}\right] P−1 n10000n100000−fn1001fnnf ≜ f0000f00000−100fnnf
完整的透视变换包括了正视变换和投影变换的组合先处理近大远小的投影变换为box然后把box变回一个CCV。 M p e r M o r t h P [ 2 n r − l 0 l r l − r 0 0 2 n t − b b t b − t 0 0 0 f n n − f 2 f n f − n 0 0 1 0 ] \mathbf{M}_{\mathrm{per}}\mathbf{M}_{\mathrm{orth}} \mathbf{P}\left[\begin{array}{cccc} \frac{2 n}{r-l} 0 \frac{lr}{l-r} 0 \\ 0 \frac{2 n}{t-b} \frac{bt}{b-t} 0 \\ 0 0 \frac{fn}{n-f} \frac{2 f n}{f-n} \\ 0 0 1 0 \end{array}\right] MperMorthP r−l2n0000t−b2n00l−rlrb−tbtn−ffn100f−n2fn0
在OpenGL中这一矩阵的定义可能不一样 M OpenGL [ 2 ∣ n ∣ r − l 0 r l r − l 0 0 2 ∣ n ∣ t − b t b t − b 0 0 0 ∣ n ∣ ∣ f ∣ ∣ n ∣ − ∣ f ∣ 2 ∣ f ∣ ∣ n ∣ ∣ n ∣ − ∣ f ∣ 0 0 − 1 0 ] \mathbf{M}_{\text {OpenGL }}\left[\begin{array}{cccc} \frac{2|n|}{r-l} 0 \frac{rl}{r-l} 0 \\ 0 \frac{2|n|}{t-b} \frac{tb}{t-b} 0 \\ 0 0 \frac{|n||f|}{|n|-|f|} \frac{2|f||n|}{|n|-|f|} \\ 0 0 -1 0 \end{array}\right] MOpenGL r−l2∣n∣0000t−b2∣n∣00r−lrlt−btb∣n∣−∣f∣∣n∣∣f∣−100∣n∣−∣f∣2∣f∣∣n∣0
这里我们使用了 M o r t h \mathbf{M}_{\mathrm{orth}} Morth随之而来的问题是 M o r t h \mathbf{M}_{\mathrm{orth}} Morth中的 l , r , t , b l,r,t,b l,r,t,b这些值怎么定义呢它们定义了我们的窗口看到的物体由于近端平面 z n zn zn的 x x x和 y y y不变我们这里选择了近端平面 z n zn zn来定义 l , r , t , b l,r,t,b l,r,t,b。
我们最后来看一下从相机坐标经过透视变换到屏幕坐标的算法流程 2.5 Field-of-View-视场
我们通过 ( l , r , t , b ) (l,r,t,b) (l,r,t,b)和 n n n定义我们的窗口我们可以进一步简化如果我们屏幕的中心是原点那么有 l − r , b − t . \begin{aligned} l -r, \\ b -t . \end{aligned} lb−r,−t.
另外我们可以添加每个像素是正方形的约束使得图形没有形状的畸变我们使用的 r r r和 t t t一定要和水平像素数 n x n_x nx和竖直像素数 n y n_y ny成比例 n x n y r t \frac{n_{x}}{n_{y}}\frac{r}{t} nynxtr
当 n x n_x nx和 n y n_y ny被确定以后只剩下一个自由度我们经常使用 θ \theta θ作为视场下图为垂直视场它满足关系 tan θ 2 t ∣ n ∣ \tan\frac{\theta}{2}\frac{t}{|n|} tan2θ∣n∣t 通过确定 n n n和 θ \theta θ我们就可以计算 t t t来得到更一般的观测系统。
参考资料 GAMES101-现代计算机图形学入门-闫令琪Shirley Marschner, Fundamentals of Computer Graphics. forth edition