精华内容
下载资源
问答
  • 讲 MATLAB高级图形绘制技术 5.1 其他二维图形绘制技术 5.1 其他二维图形绘制技术 5.1 其他二维图形绘制技术 5.2 其他三维图形绘制技术 5.2 其他三维图形绘制技术 5.2 其他三维图形绘制技术 5.2 其他三维图形绘制...
  • 文章目录第章 二维图形变换5.1 向量基础5.2 图形坐标系5.3 二维图形变换原理5.3.1 图形变换概述5.3.2 仿射变换5.3.3 齐次坐标5.4 基本几何变换5.4.1 平移变换5.4.2 比例变换5.4.3 对称变换5.4.4 旋转变换5.4.5 ...

    前言

    如果你对这篇文章可感兴趣,可以点击「【访客必读 - 指引页】一文囊括主页内所有高质量博客」,查看完整博客分类与对应链接。

    第五章 二维图形变换

    5.1 向量基础

    • 向量功能
      • 图形学中,处理三维物体,以及绘制对象的形状、位置、方向。有两大基本工具:向量分析、图形变换。
      • 向量:点和方向的实体 (没有位置)
    • 向量的表示
      • 两点之差是一个向量,方向指向被减点。v=QPv=Q-P
      • nn 维向量就是一个 nn 元组
        • w=(w1,w2,,wn)w=(w_1,w_2,…,w_n)w=[w1w2w3]w=\left[ \begin{matrix} w_1\\ w_2\\ w_3\end{matrix} \right]
    • 向量基本运算
      • 加减、数乘
      • 归一化
        • 即将向量转变为单位向量,方向不变,长度 =1=1
      • 点积
        • $a = (a_1, a_2),b=(b_1,b_2) $
        • ab=a1b1+a2b2=abcosa,ba · b = a_1b_1+a_2b_2 = |a||b|cos\langle a,b\rangle,用向量描述新闻,新闻相似,则向量夹角余弦接近于 1
        • ab>0,θ<90°a·b>0,\theta <90° ; ab=0,θ=90°a·b=0,\theta =90° ; ab<0,θ>90°a·b<0,\theta >90° ;
      • 叉积
        • a=(ax,ay,az)b=(bx,by,bz)a×b=ijkaxayazbxbybz=absina,ba=(a_x,a_y,a_z),b=(b_x,b_y,b_z),a \times b = \begin{vmatrix} i & j & k \\ a_x & a_y & a_z \\ b_x & b_y & b_z \end{vmatrix}=|a||b|sin\langle a,b\rangle
        • a×ba\times baabb 两个向量都正交,因此可以利用叉积求平面的法向量
        • a×ba\times b 的长度等于由 aabb 决定的平行四边形面积
    • 向量线性组合
      • 向量两种特殊线性组合(w=a1v1+a2v2+...+anvnw = a_1v_1 + a_2v_2+...+a_nv_n):
        • 仿射组合:线性组合的系数和等于 1,i=1nai=1\sum\limits_{i=1}^n a_i = 1
        • 凸组合:线性组合的系数和等于 1,且各系数非负,i=1nai=1 (ai0)\sum\limits_{i=1}^n a_i = 1\ (a_i \ge 0)

    5.2 图形坐标系

    • 坐标系的基本概念
      • 坐标系:建立图形和数之间对应联系的参考系
      • 建模 (modeling):程序中用于描述对象几何信息的数值
      • 观察 (viewing):表示对象中大小和位置的数值
        • 二维观察变换的一般方法是在世界坐标系中指定一个观察坐标系统,以该系统为参考通过选定方向和位置来指定矩形裁剪窗口。
    • 坐标系分类
      • 维度分类
        • 一维、二维、三维坐标系
      • 坐标轴之间的空间关系分类
        • 直角坐标系、极坐标系、圆柱坐标系、球坐标系
      • 计算机图形学坐标系分类
        • 世界坐标系:公共坐标系,现实中物体或场景的统一参照系。计算机图形系统中涉及的其它坐标系都是参照它进行定义的。
        • 建模坐标系:又称局部坐标系,每个物体(对象)有它自己的局部中心和坐标系,独立于世界坐标系来定义物体的几何特性。
        • 观察坐标系:依据观察窗口的方向和形状在世界坐标系中定义的坐标系。观察坐标系用于指定图形的输出范围。
        • 设备坐标系:适合特定输出设备输出对象的坐标系,比如屏幕坐标系。设备坐标是整数。
        • 规范化坐标系:规范化坐标系独立于设备,能容易地转变为设备坐标系,是一个中间坐标系。归一化后的坐标,坐标轴取值范围 0~1。

    5.3 二维图形变换原理

    5.3.1 图形变换概述
    • 用途
      • 各种变换:比例、旋转、镜像、错切、平移
      • 由一个基本的图案,经过变换组合成另外一个复杂图形
      • 用很少的物体组成一个场景
      • 可以通过图形变换组合得到动画效果
    • 基本原理
      • 图形变化,但原图形的连边规则没有改变
      • 图形变化,是因为顶点位置改变决定
      • 变换几何关系,保持原拓扑关系。
    5.3.2 仿射变换
    • 仿射变换 (Affine Transformation / Affine Map)
      • 基本功能
        • 平直性:直线变换后仍是直线
        • 平行性:平行线变换后仍平行,且直线上点的位置顺序不变
      • 二维仿射变换
        • xx'yy' 都是原始坐标 xxyy 的线性函数
        • {x=a1x+b1y+c1y=a2x+b2y+c2\begin{cases} x' = a_1x+b_1y+c_1 \\ y'=a_2x+b_2y+c_2 \end{cases}
        • 矩阵形式:[xy]=[xy1][a1a2b1b2c1c2]\left[ \begin{matrix} x^* & y^* \end{matrix}\right] =\left[ \begin{matrix} x & y & 1 \end{matrix}\right]· \left[ \begin{matrix} a_1 & a_2\\ b_1 & b_2 \\ c_1 & c_2 \end{matrix} \right]
    5.3.3 齐次坐标
    • 二维平面中用 (x,y)(x, y) 表示一个点,不妨说是一个向量 (x,y)(x, y) 表示一个点。所以可以用第 33 维为常数的 (x,y,1)(x, y, 1) 表示二维平面上的向量。
    • 这种 n+1n+1 维表示 nn 维的方法称为——齐次坐标表示法,nn 维向量 (p1,p2,,pn)(p_1,p_2,\cdots,p_n) 表示为 (hp1,hp2,,hpn,h)(hp_1,hp_2,\cdots,hp_n, h),其中 $h $ 称为哑坐标,特别的 h=1h=1 时称齐次坐标为规格化坐标。
    • 二维仿射变换,齐次坐标表示:[xy1]=[xy1][a1a20b1b20c1c21]\left[ \begin{matrix} x^* & y^*&1 \end{matrix}\right] =\left[ \begin{matrix} x & y & 1 \end{matrix}\right]· \left[ \begin{matrix} a_1 & a_2 &0\\ b_1 & b_2&0 \\ c_1 & c_2 &1\end{matrix} \right]
    • 不使用齐次坐标可以做比例、对称、旋转变换,但做不到平移变化,无法增加常数项。

    5.4 基本几何变换

    5.4.1 平移变换
    • 不产生变形而移动物体的刚体变换,即物体上的每个点移动相同数量的坐标
    • 坐标形式:{x=x+Txy=y+Ty\begin{cases} x^* = x+T_x \\ y^*=y + T_y \end{cases}
    • 齐次坐标形式:[xy1]=[xy1][100010TxTy1]=[x+Txy+Ty1]\left[ \begin{matrix} x^* & y^* &1\end{matrix}\right] =\left[ \begin{matrix} x & y & 1 \end{matrix}\right]· \left[ \begin{matrix} 1 & 0 &0 \\0&1&0\\T_x&T_y&1 \end{matrix} \right] =\left[ \begin{matrix} x+Tx & y+Ty &1\end{matrix}\right]
    5.4.2 比例变换
    • 相对于坐标原点沿 xx 方向放缩 SxS_x 倍,沿 yy 方向放缩 SyS_y 倍。S>1S > 1 放大,S<1S < 1 缩小。
    • 坐标形式:{x=xSxy=ySy\begin{cases} x^* = x·S_x \\ y^*=y·S_y \end{cases}
    • 齐次坐标形式:[xy1]=[xy1][Sx000Sy0001]=[xSxySy1]\left[ \begin{matrix} x^* & y^* &1\end{matrix}\right] =\left[ \begin{matrix} x & y & 1 \end{matrix}\right]· \left[ \begin{matrix} S_x & 0 &0 \\0&S_y&0\\0&0&1 \end{matrix} \right] =\left[ \begin{matrix} x·S_x & y·S_y &1\end{matrix}\right]
    • Sx=SyS_x =S_y 时,为整体比例变换,[xy1]=[xy1][10001000S]=[xyS]\left[ \begin{matrix} x^* & y^* &1\end{matrix}\right] =\left[ \begin{matrix} x & y & 1 \end{matrix}\right]· \left[ \begin{matrix} 1 & 0 &0 \\0&1&0\\0&0&S \end{matrix} \right] =\left[ \begin{matrix} x & y &S\end{matrix}\right]S>1S>1 放大,0<S<10<S<1 缩小,S<0S<0 发生关于原点的对称等比变换。
    5.4.3 对称变换
    • 也称镜像变换或反射变换。有关于x轴、y轴、原点、某条直线的对称变换。
    • 关于 xx 轴对称:[xy1]=[xy1][100010001]=[xy1]\left[ \begin{matrix} x^* & y^* &1\end{matrix}\right] =\left[ \begin{matrix} x & y & 1 \end{matrix}\right]· \left[ \begin{matrix} 1 & 0 &0 \\0&-1&0\\0&0&1 \end{matrix} \right] =\left[ \begin{matrix} x&-y&1\end{matrix}\right]
    • 关于 yy 轴对称:[xy1]=[xy1][100010001]=[xy1]\left[ \begin{matrix} x^* & y^* &1\end{matrix}\right] =\left[ \begin{matrix} x & y & 1 \end{matrix}\right]· \left[ \begin{matrix} -1 & 0 &0 \\0&1&0\\0&0&1 \end{matrix} \right] =\left[ \begin{matrix} -x&y&1\end{matrix}\right]
    • 关于原点对称:[xy1]=[xy1][100010001]=[xy1]\left[ \begin{matrix} x^* & y^* &1\end{matrix}\right] =\left[ \begin{matrix} x & y & 1 \end{matrix}\right]· \left[ \begin{matrix} -1 & 0 &0 \\0&-1&0\\0&0&1 \end{matrix} \right] =\left[ \begin{matrix} -x&-y&1\end{matrix}\right]
    5.4.4 旋转变换
    • 将点绕原点旋转角度 θ\theta ,逆时针为正,顺时针为负
    • 坐标形式(逆时针):{x=rcos(α+θ)=rcosαcosθrsinαsinθy=rsin(α+θ)=rcosαsinθ+rsinαcosθ{x=xcosθysinθy=xsinθ+ycosθ\begin{cases} x^* =r·cos(\alpha+\theta)=r·cos\alpha ·cos\theta-r·sin\alpha ·sin\theta \\ y^* =r·sin(\alpha+\theta)=r·cos\alpha ·sin\theta + r·sin\alpha ·cos\theta\end{cases} \Rightarrow \begin{cases} x^* =x ·cos\theta-y ·sin\theta \\ y^* =x ·sin\theta + y ·cos\theta\end{cases}
    • 齐次坐标形式(逆时针):[xy1]=[xy1][cosθsinθ0sinθcosθ0001]=[xcosθysinθxsinθ+ycosθ1]\left[ \begin{matrix} x^* & y^* &1\end{matrix}\right] =\left[ \begin{matrix} x & y & 1 \end{matrix}\right]· \left[ \begin{matrix} cos\theta & sin\theta &0\\-sin\theta&cos\theta & 0\\0&0&1 \end{matrix} \right] =\left[ \begin{matrix} x ·cos\theta-y ·sin\theta & x ·sin\theta + y ·cos\theta &1\end{matrix}\right]
    • 顺时针只要将 θ=θ\theta = -\theta 即可。
    5.4.5 错切变换
    • 弹性物体的变形处理

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SRAkw550-1597369488696)(assets/1559033084287.png)]

    • 变换矩阵中的非对角线元素大都为零,若变换矩阵中的非对角元素不为 00,则意味着 xxyy 同时对图形的变换起作用。也就是说,变换矩阵中非对角线元素起着把图形沿 xxyy 方向错切的作用。
    • xx 值或 yy 值越小,错切量越小;xx 值或 yy 值越大,错切量越大。
    • 齐次坐标形式:[xy1]=[xy1][1b0c10001]=[c+cybx+y1]\left[ \begin{matrix} x^* & y^* &1\end{matrix}\right] =\left[ \begin{matrix} x & y & 1 \end{matrix}\right]· \left[ \begin{matrix} 1 & b & 0\\ c &1 &0\\0&0&1 \end{matrix} \right] =\left[ \begin{matrix}c+cy&bx+y &1\end{matrix}\right]
    • 沿 xx 方向错切,即 b=0b=0[xy1]=[xy1][100c10001]=[c+cyy1]\left[ \begin{matrix} x^* & y^* &1\end{matrix}\right] =\left[ \begin{matrix} x & y & 1 \end{matrix}\right]· \left[ \begin{matrix} 1 & 0 & 0\\ c &1 &0\\0&0&1 \end{matrix} \right] =\left[ \begin{matrix}c+cy&y &1\end{matrix}\right]
    5.4.5 复合变换
    • 图形作大于一次的变换,P=PT=P(T1T2Tn)n>1P^* = P · T = P·(T_1·T_2·\cdots ·T_n) ,n\gt 1矩阵相乘不可交换!任何一个复杂的几何变换都可以看作基本几何变换的组合形式。
    • 二维复合平移:T=Tt1Tt2=[100010Tx1Ty11][100010Tx1Ty11]=[100010Tx1+Tx2Ty1+Ty21]T = T_{t1}·T_{t2} = \left[ \begin{matrix} 1 & 0 &0 \\0&1&0\\T_{x1}&T_{y1}&1 \end{matrix} \right] · \left[ \begin{matrix} 1 & 0 &0 \\0&1&0\\T_{x1}&T_{y1}&1 \end{matrix} \right] =\left[ \begin{matrix} 1 & 0 &0 \\0&1&0\\T_{x1}+T_{x2}&T_{y1}+T_{y2}&1 \end{matrix} \right]
    • 二维复合比例:T=Ts1Ts2=[Sx1000Sy10001][Sx2000Sy20001]=[Sx1Sx2000Sy1Sy20001]T = T_{s1}·T_{s2} = \left[ \begin{matrix} S_{x1} & 0 &0 \\0&S_{y1}&0\\0&0&1 \end{matrix} \right] · \left[ \begin{matrix} S_{x2} & 0 &0 \\0&S_{y2}&0\\0&0&1 \end{matrix} \right]= \left[ \begin{matrix} S_{x1}·S_{x2} & 0 &0 \\0&S_{y1}·S_{y2}&0\\0&0&1 \end{matrix} \right]
    • 二维复合旋转:T=Tr1Tr2=[cosθ1sinθ10sinθ1cosθ10001][cosθ2sinθ20sinθ2cosθ20001]=[cos(θ1+θ2)sin(θ1+θ2)0sin(θ1+θ2)cos(θ1+θ2)0001]T = T_{r1}·T_{r2} = \left[ \begin{matrix} cos\theta_1 & sin\theta_1 &0\\-sin\theta_1&cos\theta_1 & 0\\0&0&1 \end{matrix} \right] · \left[ \begin{matrix} cos\theta_2 & sin\theta_2 &0\\-sin\theta_2&cos\theta_2 & 0\\0&0&1 \end{matrix} \right]=\left[ \begin{matrix} cos(\theta_1+\theta_2) & sin(\theta_1+\theta_2) &0\\-sin(\theta_1+\theta_2)&cos(\theta_1+\theta_2) & 0\\0&0&1 \end{matrix} \right]
    5.4.6 坐标系变换
    • 图形变换经常需要从一个坐标系变换到另一个坐标系,如下图从 x0yx0y 变换到 x0yx'0'y'

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3Yi3p4er-1597369488702)(assets/1559034067979.png)]

    • 上图变换分两步完成,x0yx0yx0yx'0'y' \xrightarrow{平移} x'0y' \xrightarrow{旋转} x0y,注意是从目标到源
      • 平移变换 —— 将 x0yx'0'y' 坐标系的原点平移至 x0yx0y 坐标系的原点
      • 旋转变换 —— 将 xx' 轴旋转到 xx 轴上
    • T=TtTr=[100010x0y01][cos(θ)sin(θ)0sin(θ)cos(θ)0001]T = T_{t}·T_{r} = \left[ \begin{matrix} 1 & 0 &0 \\0&1&0\\-x_0&-y_0&1 \end{matrix} \right] · \left[ \begin{matrix} cos(-\theta) & sin(-\theta) &0\\-sin(-\theta)&cos(-\theta) & 0\\0&0&1 \end{matrix} \right]
    5.4.7 任意参考点的几何变换
    • 在以往的变换中,以 (0, 0) 为参考点,倘若以任意点为参考点,则:
      • 将参考点移到原点(平移)
      • 针对原点进行二维几何变换(变换)
      • 将原点移到参考点(反平移)

    5.5 二维变换矩阵

    5.5.1 二维变换矩阵概述
    • 二维空间中某点的变化可以表示成点的齐次坐标与 3 阶的二维变换矩阵 T2dT_{2d} 相乘

      [xy1]=[xy1]T2d=[xy1][abpcdqlms]\left[ \begin{matrix} x^* & y^* &1\end{matrix}\right] =\left[ \begin{matrix} x & y & 1 \end{matrix}\right]·T_{2d}=\left[ \begin{matrix} x & y & 1 \end{matrix}\right]· \left[ \begin{matrix} a&b&p\\c&d&q\\l&m&s \end{matrix} \right]

    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dhihggqr-1597369488704)(assets/1559035081804.png)]

    5.5.2 二维图形几何变换的计算
    • 点的变换:[xy1]=[xy1]T\left[ \begin{matrix} x^* & y^* &1\end{matrix}\right] =\left[ \begin{matrix} x & y & 1 \end{matrix}\right]· T
    • 直线的变换(两端点的变换):[x1y11x2y21]=[x1y11x2y21]T\left[ \begin{matrix} x_1^* & y_1^* &1\\ x_2^* & y_2^* &1\end{matrix}\right] =\left[ \begin{matrix} x_1 & y_1 &1\\ x_2 & y_2 &1\end{matrix}\right] ·T
    • 多边形的变换(每个顶点的变换):p=[x1y11x2y21xnyn1]p =\left[ \begin{matrix} x_1^* & y_1^* &1\\ x_2^* & y_2^* &1 \\ \cdots&\cdots&\cdots\\x_n^* &y_n^*&1\end{matrix}\right]

    5.4 窗口、视图及变换

    5.4.1 窗口和视区
    • 窗口:世界坐标系中要显示的区域

    • 视区:窗口映射到显示器上的区域

    • 窗口定义显示什么;视区定义在何处显示;二者需要进行坐标变换

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fKXV1qy8-1597369488709)(assets/1559035457686.png)]

    • 世界坐标系中的一个窗口可以对应于多个视区

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1UUaZdsV-1597369488710)(assets/1559035487387.png)]

    • 窗口\xrightarrow{观察变换} 视区
    5.4.2 观察变换
    • 观察变换 (Viewing Transformation)

    • 变焦距效果

      • 窗口放大/缩小,视区不变,图形缩小/放大

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VjBZPCOz-1597369488711)(assets/1559035899696.png)]

    • 整体缩放效果

      • 窗口不变,视区放大/缩小,图形放大/缩小

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WyVKYvEv-1597369488713)(assets/1559035942154.png)]

    • 漫游效果

      • 把一个固定大小的窗口在一幅大图形上移动,视区不变。
    5.4.3 窗口到视区的变换
    • 窗口的点 \rightarrow 视区的点

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7icHASZZ-1597369488713)(assets/1559036093678.png)]

    • 保持比例的映射
      • 保持比例:映射之后,中心点仍然在中心,边界点仍然在边界
      • {sx=A×x+Csy=B×y+D\begin{cases} sx = A\times x+C \\ sy = B\times y+D\end{cases}
      • 比例保持:xwxlwxrwxl=sxvxlvxrvxlsx=xwxlwxrwxl(vxrvxl)+vxl\Large \frac{x-w_{xl}}{w_{xr}-w_{xl}} = \frac{sx-v_{xl}}{v_{xr}-v_{xl}} \Rightarrow sx = \frac{x-w_{xl}}{w_{xr}-w_{xl}}(v_{xr}-v_{xl})+v_{xl}
      • 根据倍数关系:sx=vxrvxlwxrwxlx+(vxlvxrvxlwxrwxlwxl)=Ax+CA=vxrvxlwxrwxlC=vxlA×wxl\large sx = \frac{v_{xr}-v_{xl}}{w_{xr}-w_{xl}} x + (v_{xl}-\frac{v_{xr}-v_{xl}}{w_{xr}-w_{xl}} w_{xl}) = Ax + C,\\ A = \frac{v_{xr}-v_{xl}}{w_{xr}-w_{xl}},C=v_{xl}-A\times w_{xl}
      • 同理,B=vytvybwytwybD=vybB×wyb\large B= \frac{v_{yt}-v_{yb}}{w_{yt}-w_{yb}},D=v_{yb}-B\times w_{yb}
    展开全文
  • 转]C语言图形编程() -二维图形变换①    从这一部分开始,进入了图形编程的比较烦琐的部分,要真正对图形编程有所了解,这一部分的内容是必须要掌握的。  在计算机绘图过程中,经常需要进行绘图变换...
     转]C语言图形编程(五) -二维图形变换①
    第一节  用户坐标到屏幕坐标变换
        1. 窗口到视口的变换
        2. 实型值到整型值的变换
        3. y坐标值方向变换
        4. 长宽比例变换
    第二节 二维几何变换
      一、 基本变换
        1、比例变换
        2. 对称变换
        3. 错切变换
        4. 旋转变换
        5. 平移变换
      二、复合变换
        1. 复合平移
        2. 复合比例
        3. 复合旋转
        4. 相对点(xo,yo)的比例变换
        5. 相对点(xo,yo)的旋转变换



       从这一部分开始,进入了图形编程的比较烦琐的部分,要真正对图形编程有所了解,这一部分的内容是必须要掌握的。
       在计算机绘图过程中,经常需要进行绘图变换,主要包括二维图形变换和三维图形变换。这一部分讨论二维图形变换,其内容有用户坐标到屏幕坐标的变换、图形的比例变换、对称变换、错切变换、旋转变换、平移变换和复合变换等。后面讲到了二维剪裁,即线段裁剪与多边形裁剪。

    第一节  用户坐标到屏幕坐标变换
       假设纸上有一个图形,要用计算机把它在屏幕上画出来。那么首先遇到的问题是,纸上的图形采用的坐标是实数域域中的直角坐标系或是极坐标系,统称为用户坐标系。而屏幕上采用的坐标系是整数域中直角坐标系,这类坐标系统称为设备坐标系。因此用户坐标系中图形需要经过变换才能绘制在屏幕上,显然这个变换的内容包括: 1)将用户坐标系中任意范围区域转换到屏幕某个范围区域,从而用户坐标系此范围区域内的图形也转换到屏幕上该范围区域内。 2)用户坐标系此区域内图形上的坐标值转换到屏幕上该范围区域内后不一定是整数,取整后才成为该范围区域内的屏幕坐标值。 3)用户坐标右手系到屏幕坐标左手系的坐标轴方向变换。 4)当屏幕坐标系水平方向与垂直方向刻度不等(即像素间距不等)时,为保持图形不走样,还要进行比例变换。下面介绍这些内容的具体计算问题。

    1.窗口到视口的变换
       更确切地说,是实际图形到屏幕图形的转换。有时也称为数据规格化。
       在用户坐标系中,指定一矩形域以确定要显示(或绘制)的图形部分,这个矩形区域称为窗口。在屏幕上可任选一矩形域以显示(或绘制)窗口内的图形,该域称为视口。如图2-1所示。

     


       一般视窗口的四条边界分别为:
       左边界 x=x1、右边界 x=x2.下边界 y=y1,上边界y=y2。
       视口的四条边界分别为:
       左边界sx=sx1,右边界sx=sx2,上边界sy=sy1,下边界sy=sy2。
       经变换后应有,窗口的上边界线段(或下边界线段)长x2-x1变换成视口上边界线段(或下边界线段)长sx2-sx1。设其比例变换因子为k1,则可得
       k1*(x2-x1)=sx2-sx1
       k1=(sx2-sx1)/(x2-x1)
       对窗口内任一x坐标(x1<=x<=x2)变换后为视口内水平方向sx坐标(sx1<=sx<=sx2)。由上述有:
       k1*(x-x1)=sx-sx1
       sx=sx1+k1*(x-x1)
         =sx1+(x-x1)*(sx2-sx1)/(x2-x1)
       同样,经变换后窗口的左边界线段(或右边界线段)长y2-y1变换成视口左边界线段(或右边界线段)长sy2-sy1。设其比例变换因子为k2,则可得
       k2*(y2-y1)=sy2-sy1
       k2=(sy2-sy1)/(y2-y1)
       对窗口内任一y坐标(y1<=y<=y2)变换后为视口内垂直sy坐标(sy1<=sy<=sy2),应有
       k2*(y-y1)=sy-sy1
       sy=sy1+k2*(y-y1)
         =sy1+(y-y1)*(sy2-sy1)/(y2-y1)
       于是对窗口内图形上任一点坐标(x,y)变换到屏幕上视口内成为(sx,sy),则
       sx=sx1+(x-x1)*(sx2-sx1)/(x2-x1)
       sy=sy1+(y-y1)*(sy2-sy1)/(y2-y1)
       写成简式
       sx=k1*x+a
       sy=k2*y+b
    这里
       a=sx1-k1*x1
       b-sy1-k2*y1
       k1=(sx2-sx1)/(x2-x1)
       k2=(sy2-sy1)/(y2-y1)

    2. 实型值到整型值的变换
       上面对窗口内图形上任一点坐标(x,y)变换到屏幕上视口内成为(sx,sy),
       sx=k1*x+a
       sy=k2*y+b         k1,k2,a,b同上
       这样计算出来的sx,sy一般是实型值,而屏幕上视口内屏幕坐标是整型值,因此要将sx,sy实型值转换成屏幕坐标系的整型值。这可以通过四舍五入的方法将实型值的绝对值圆整化。由于C语言中已经替我们想到了这点,它提供的函数可以自动取整,因此用户在调用标准函数在屏幕上绘图时一般不需要考虑这个问题。当然也可以用赋值的类型转换规则来实现实型值到整型值的变换。

    3. y坐标值方向变换
       一般屏幕坐标系是直角左手系,y轴方向向下为正,原点在屏幕的左上角,如图2-2所示。

     


    窗口内图形上任一点(x,y)变换到视口内成为(sx,xy),而(x,y)是相对用户坐标系(直角右手系)的。(sx,sy)是相对屏幕坐标系(直角左手系)的,因此y轴方向相反。为使窗口内图形变换到视口上图形其形状一致,需将视口上图形y轴方向变换成窗口内图形y轴方向。这只要将求得的视口内各点的sy整型坐标均用sy2去减,即sy2-sy(整型)代替sy(整型)即可,经这样的坐标轴方向变换后得到的视口内图形与窗口内图形一致。

    4.长宽比例变换
       屏幕坐标系x方向与y方向上的刻度可能不一样,这取决于水平方向像素间距与垂直方向偈素间距大小是否一致。如果两个方向的刻度不相等,那么用户坐标系下一个正方形将显示(或绘制)成为一个长方形有,一个圆将成为一个椭圆。
    为保持原图形的长宽比。使图形显示(或绘制)后不走样,需求出屏幕上两侍标轴刻度的比值(即纵横比)。可以用函数getaspectratio()(见前文所述)返回x方向和y方向的比例数,从而求得这个比值。再瘵原图形y方向坐标乘以该比值,这样显示(或绘制)出来的图形应不走样。若不考虑图形的走样,就不必作这个变换。

    第二节 二维几何变换
       图形的几何变换一般是指对图形的几何信息经过变换后产生新的图形,图形几何变换既可以看作是坐标系不动而图形变动,变动后的图形在坐标系中的坐标值发生变化;出可以看作图形不动而坐标系变动,变动后的图形在新坐标系下具有新的坐标值。这两种情况本质上都是一样的,都是图形由新的坐标值表示,因此是新产生的图形。图形几何变换包括比例变换、对称变换、错切变换、旋转变换、平移变换及其复合变换。图形上所有的点在几何变换前后的坐标关系一般用解析几何方法可以求得,但这些几何关系用矩阵方法表示,运算更为方便。

    一、基本变换
       图形基本几何变换是指比例变换、对称变换、错切变换、旋转变换和平移变换等。除平移变换外,这里其它四种几何变换都可以用组成图形的点向量(或称1×2阶矩阵)和2×2阶变换矩阵相乘表示,而平移变换需引入新方法来实现。
    1、比例变换
       设图形上一点P(x,y),经比例变换后成为新的菜上一点P'(x',y'),即有
          x'=a*x
          y'=d*y
    式中a,d为比例因子
       将此比例变换式写成矩阵式得
                        a   0
          [x' y']=[x y]        = [x y] * T
                        0   d
                a   0
       这里 T=         叫做比例变换矩阵。若a=d,则x,y坐标按同一比例变换。当a=d>1时,图形放大;当0<a=d<1时,
                0   d
    图形缩小。
       若a≠d,则x,y坐标按各自不同比例变换。

                               3   0
    例 1: 设有比例变换矩阵 T=        , 三角形abc经过比例变换成为三角形a'b'c'。如图2-3所示。
                               0   1
       

     

              

                   3   0
          a [1 2]         = [3 2]      a'
                   0   1

                   3   0
          b [2 2]         = [6 2]      b'
                   0   1

                   3   0
          c [2 3]         = [6 3]      c'
                   0   1

    2. 对称变换
       图形上一点P(x,y)经关于原点对称变换后成为新图形上一点P'(x',y'),则
             x' = -x
             y' = -y
       写成矩阵形式成为
                              -1   0
             [x' y'] = [x y]          = [x y] * T
                               0  -1
                -1   0
       这里 T =          为关于原点对称变换矩阵。
                 0  -1
       若关于x轴对称,则对称变换的矩阵表示为
                             1   0
             [x' y'] = [x y]        = [x y] * T
                             0  -1
                                    1   0
       于是关于x轴对称变换矩阵 T = 
                                    0  -1
    若关于y轴对称,则对称变换的矩阵表示为
                              -1   0
             [x' y'] = [x y]          = [x y] * T
                               0   1
                                    -1   0
       于是关于y轴对称变换矩阵 T = 
                                     0   1

    若关于直线y = -x对称,则对称变换矩阵表示为
                              0   -1
             [x' y'] = [x y]          = [x y] * T
                             -1    0

                                           0   1
       于是关于直线 y = x对称变换矩阵 T = 
                                           1   0
       各种对称变换的图形均可由实例程序绘出,参见实例程序图形。

    3. 错切变换
       对图形的任一点P(x,y),作线性变换如下
             x' = x + by
             y' = y + dx
       式中b,d为不全为零的常 数,点P'(x',y')为新图形上相应的点,这个变换称为图形的错切变换。
       错切变换的矩阵表示为
                              1   d
             [x' y'] = [x y]         = [x y] * T
                              b   1
            1   d
       T =         叫做错切变换矩阵(b,d不全为零)。
            b   1
       ① 当d=0时,x'=x+by,y'=y,这时图形的y坐标不变,x坐标值随(x,y)及系数b作线性变化。若b>0时,图形沿x轴作错切位移;若b<0,图形沿x轴负向作错切位移。
       ② 当b=0时,x'=x,y'=dx+y,此时图形的x坐标不变y坐标随(x,y)及系数d作线性变化。如d>0,图形沿y轴正向作错切位移;如d<0,图形沿y轴负向作错切位移。
       ③ 当b≠0且d≠0时,x'=x+by,y'=y+dx,图形沿x,y两个方向作错切位移。

                                  1   2
    例 2: 设有错切变换 矩阵 T =         ,正方形abcd经此错切变换成为四边形a'b'c'd',如图2-4所示。
                                  0   1

     


      
                        1   2
               a [0 0]         = [0 0]      a'
                        0   1
      
                        1   2
               b [1 0]         = [1 2]      b'
                        0   1

                        1   2
               c [1 1]         = [1 3]      c'
                        0   1

                        1   2
               d [0 1]         = [0 1]      d'
                        0   1

    4. 旋转变换
       设图形上一点P(x,y)绕原点逆时针旋转θ角后成为新的图形上一点P'(x',y'),则由解析几何方法可得
             x' = xcosθ + ysinθ
             y' = -xsinθ + ycosθ
       用矩阵表示为
                              cosθ   -sinθ
             [x' y'] = [x y]                  = [x y] * T
                              sinθ    cosθ
              cosθ   -sinθ
    这里 T =                  为绕原点逆时针变换矩阵。若顺时针旋转时,θ角为负值。
              sinθ    cosθ

    5. 平移变换
       若图形上一点P(x,y)沿x轴平移 l距离,沿y轴平移m距离后成为新的图形上一点P'(x',y'),则有
             x' = x + l
             y' = y + m
       式中l,m不全为零,这称为平移变换。但此变换无法用组成图形的点向量和2×2阶变换矩阵相乘来实现。
       用二维点向量和2×2阶矩阵相乘不能表示图形的平移变换,那么自然会想到用三维点向量和3×3阶矩阵相乘来实现图形的平移变换。因此对图形上二个坐标的点向量需要添加一个坐标,使之成为三维点向量以便与三阶矩阵相乘,进而实现用矩阵表示平移变换。实际上就是对上面的二个坐标变换式添加第三个坐标变换式,即成为
             x' = x + l
             y' = y + m
             k = k
       这第三个坐标变换式(即k=k)必须是恒等式,因为不需作变换 ,本质上是为了进行矩阵运算而引入的。
       将此三个变换式(仍然是图形的平移变换,不妨将k = k取成1=1)写成矩阵得

                   
                                  1   0   0
             [x' y' l] = [x y l]  0   1   0   = [x y 1] * T
                                  l   m   1

                 1   0   0
       显然 T =  0   1   0  为图形的平移变换矩阵。
                 l   m   1
    这里通过对原图形上二维点向量引进第三个坐标成为三维点向量,从而使原图形的平移变换 能用矩阵表示。同样其它基本变换也可以如此用矩阵表示。因此图形的基本变换都可以在这样的三维点向量下统一、整齐用矩阵表示。这样的三维点向量称为齐次点向量,也叫三维齐次坐标点,简称三维齐次坐标。只有在三维齐次坐标下,二维几何变换才都可以用矩阵表示。下面再进一步讨论一下齐次坐标的优点。
       引用齐次坐标后,可将上面各种基本变换矩阵统一在一个三阶矩阵中。即

                  a   b   0
             T =  c   d   0
                  l   m   1

    式中左上角二阶矩阵实现比例、对称、错切、旋转等变换,左下角1×2阶矩阵实现平移变换,其中a,b,c,d,l,m只要赋以相应的值,并建立图形上点的齐次坐标(即在图形上点的坐标后引入第三个坐标1),这样就可以用图形上点的三维齐次坐标与此三阶矩阵相乘来表示三维图形的基本几何变换了。而变换后,不用考虑第三个坐标1,前面两个坐标就反映了图形的整个变换情况。
       用齐次坐标表示一个图形上的点,可以有多种表示,如(6,8,1)、(12,16,2)、(30,40,5)等均表示图形上同一个点(6,8)。这样,齐次坐标可以表示计算机无法容纳的数。例如当计算机的字长为16位时,它能表示的最大整数为216-1=32767。若点坐标为(80 000,40 000),则计算机无法表示。但用齐次坐标可表示为(20 000,10 000,1/4),经过处理后再用第三个坐标支除前面两个坐标,从而得到原来通常的坐标。
       齐次坐标优点很多,在计算机绘图中都采用这种表示来处理图形。下面介绍的图形复合几何变换就是如此。

    二、复合变换
       图形的复合几何变换是指图形作一次以上的基本几何变换,变换结果是每次基本变换矩阵的乘积。图殂的复合几何变换简称复合变换。

    1. 复合平移
       若对图形首先作平移变换 T1,然后再作平移变换T2,相应的平移变换矩阵分别为
                           1   0   0
                      T1 = 0   1   0
                           l1  m1  1

                           1   0   0
                      T2 = 0   1   0
                           l2  m2  1
       则变换结果为复合平移变换T,其复合平移变换矩阵为
                      T = T1 * T2

                          1   0   0         1   0   0
                        = 0   1   0    *    0   1   0
                          l1  m1  1         l2  m2  1

                          1      0      0
                        = 0      1     0
                          l1+l2  m1|m2  1

    2. 复合比例
       设比例变换T1矩阵为

                     a1   0   0
                T1 = 0   d1   0
                     0    0   1

       比例变换 T2矩阵为

                     a2   0   0
                T2 = 0   d2   0
                     0    0   1
    则复合比例变换T矩阵为

                              a1   0   0     a2   0   0      a1*a2  0       0
                T = T1 * T2 = 0   d1   0  *  0   d2   0   =  0      d1*d2   0
                              0    0   1     0    0   1      0      0       1

    3. 复合旋转
       设旋转变换T1矩阵为

                        cosθ1  -sinθ1   0  
                   T1 = sinθ1   cosθ1   0
                         0       0        1

                        cosθ2   -sinθ2  0
                   T2 = sinθ2   cosθ2   0
                         0        0       1
       则复合旋转变换T矩阵为
                   T = T1 * T2

                       cosθ1    -sinθ1   0         cosθ2    -sinθ2   0
                     = sinθ1    cosθ1    0    *    sinθ2    cosθ2    0
                        0         0        1           0        0        1

                       cos(θ1+θ2)    -sin(θ1+θ2)   0
                     = sin(θ1+θ2)    cos(θ1+θ2)    0
                         0               0             1
       旋转变换和比例变换翥与参考点有关,上面的旋转变换和比例变换均是相对原点的。如果相对某一参考点(xo,yo)作比例、旋转变换,则其变换过程是先把坐标系原点平移至(xo,yo),再在新的坐标系下作比例、旋转变换,然后将坐标原点平移回去,这实际上是复合变换。

    4. 相对点(xo,yo)的比例变换

                       1    0    0        a    0    0        1    0    0
                   T = 0    1    0        0    d    0        0    1    0
                       -xo  -yo  1        0    0    1        xo   yo   1

                       a           0           0
                     = 0           d           0
                       (1-a)*xo    (1-d)*yo    1

    5. 相对点(xo,yo)的旋转变换

                       1    0    0        cosθ    -sinθ     0        1    0    0
                   T = 0    1    0        sinθ    cosθ      0        0    1   0
                       -xo  -yo  1         0      0       1        xo   yo   1

                       cosθ                                -sinθ                           0
                     = sinθ                                cosθ                            0
                       (1-cosθ)*xo+yo*sinθ       (1-cosθ)*yo+xo*sinθ      1

       解决复合变换问题,关键是将其分解为一定顺序的基本变换,然后逐一进行这些基本变换,从而复合变换问题得到解决;或者求出这些基本变换矩阵连乘积,即得复合变换矩阵,进而由矩阵作复合变换使得问题被解决。
    例 3: 设三角形abc其顶点坐标 a=(6,4),b=(9,4),c=(6,6),绕点(5,3)逆时针旋转60度,试求变换后的图形。
       解: 此变换可分解成下面顺序的基本变换来实现:
    1) 将三角形abc连同点(5,3)与原点重合,即沿x轴平移-5,沿y轴平移-3;
    2)平移后的三解形绕原点逆时针旋转60度;
    3)再将旋转后的三角形连同原点平移回点(5,3)。
       这三步具体变换过程计算如下:
       由前面复合变换中的计算公式并代入 cosθ = cos60o = 0.5,sinθ = sin60o = 0.866 便得

     


    展开全文
  • 章 二维图形变换5.1 向量基础向量功能图形学中,处理三维物体,以及绘制对象的形状、位置、方向。有两大基本工具:向量分析、图形变换。向量:点和方向的实体 (没有位置)向量的表示两点之差是一个向量,方向指向...

    第五章 二维图形变换

    5.1 向量基础

    • 向量功能
      • 图形学中,处理三维物体,以及绘制对象的形状、位置、方向。有两大基本工具:向量分析、图形变换。
      • 向量:点和方向的实体 (没有位置)
    • 向量的表示
      • 两点之差是一个向量,方向指向被减点。
      • 维向量就是一个
        元组
    • 向量基本运算
      • 加减、数乘
      • 归一化
        • 即将向量转变为单位向量,方向不变,长度
      • 点积
        • ,用向量描述新闻,新闻相似,则向量夹角余弦接近于 1
        • ;
          ;
          ;
      • 叉积
        • 两个向量都正交,因此可以利用叉积求平面的法向量
        • 的长度等于由
          决定的平行四边形面积
    • 向量线性组合
      • 向量两种特殊线性组合(
        ):
        • 仿射组合:线性组合的系数和等于 1,
        • 凸组合:线性组合的系数和等于 1,且各系数非负,

    5.2 图形坐标系

    • 坐标系的基本概念
      • 坐标系:建立图形和数之间对应联系的参考系
      • 建模 (modeling):程序中用于描述对象几何信息的数值
      • 观察 (viewing):表示对象中大小和位置的数值
        • 二维观察变换的一般方法是在世界坐标系中指定一个观察坐标系统,以该系统为参考通过选定方向和位置来指定矩形裁剪窗口。
    • 坐标系分类
      • 维度分类
        • 一维、二维、三维坐标系
      • 坐标轴之间的空间关系分类
        • 直角坐标系、极坐标系、圆柱坐标系、球坐标系
      • 计算机图形学坐标系分类
        • 世界坐标系:公共坐标系,现实中物体或场景的统一参照系。计算机图形系统中涉及的其它坐标系都是参照它进行定义的。
        • 建模坐标系:又称局部坐标系,每个物体(对象)有它自己的局部中心和坐标系,独立于世界坐标系来定义物体的几何特性。
        • 观察坐标系:依据观察窗口的方向和形状在世界坐标系中定义的坐标系。观察坐标系用于指定图形的输出范围。
        • 设备坐标系:适合特定输出设备输出对象的坐标系,比如屏幕坐标系。设备坐标是整数。
        • 规范化坐标系:规范化坐标系独立于设备,能容易地转变为设备坐标系,是一个中间坐标系。归一化后的坐标,坐标轴取值范围 0~1。

    5.3 二维图形变换原理

    5.3.1 图形变换概述

    • 用途
      • 各种变换:比例、旋转、镜像、错切、平移
      • 由一个基本的图案,经过变换组合成另外一个复杂图形
      • 用很少的物体组成一个场景
      • 可以通过图形变换组合得到动画效果
    • 基本原理
      • 图形变化,但原图形的连边规则没有改变
      • 图形变化,是因为顶点位置改变决定
      • 变换几何关系,保持原拓扑关系。

    5.3.2 仿射变换

    • 仿射变换 (Affine Transformation / Affine Map)
      • 基本功能
        • 平直性:直线变换后仍是直线
        • 平行性:平行线变换后仍平行,且直线上点的位置顺序不变
      • 二维仿射变换
        • 都是原始坐标
          的线性函数
        • 矩阵形式:

    5.3.3 齐次坐标

    • 二维平面中用
      表示一个点,不妨说是一个向量
      表示一个点。所以可以用第
      维为常数的
      表示二维平面上的向量。
    • 这种
      维表示
      维的方法称为——齐次坐标表示法,
      维向量
      表示为
      ,其中
      称为哑坐标,特别的
      时称齐次坐标为规格化坐标。
    • 二维仿射变换,齐次坐标表示:
    • 不使用齐次坐标可以做比例、对称、旋转变换,但做不到平移变化,无法增加常数项。

    5.4 基本几何变换

    5.4.1 平移变换

    • 不产生变形而移动物体的刚体变换,即物体上的每个点移动相同数量的坐标
    • 坐标形式:
    • 齐次坐标形式:

    5.4.2 比例变换

    • 相对于坐标原点沿
      方向放缩
      倍,沿
      方向放缩
      倍。
      放大,
      缩小。
    • 坐标形式:
    • 齐次坐标形式:
    • 时,为整体比例变换,
      放大,
      缩小,
      发生关于原点的对称等比变换。

    5.4.3 对称变换

    • 也称镜像变换或反射变换。有关于x轴、y轴、原点、某条直线的对称变换。
    • 关于
      轴对称:
    • 关于
      轴对称:
    • 关于原点对称:

    5.4.4 旋转变换

    • 将点绕原点旋转角度
      ,逆时针为正,顺时针为负
    • 坐标形式(逆时针):
    • 齐次坐标形式(逆时针):
    • 顺时针只要将
      即可。

    5.4.5 错切变换

    • 弹性物体的变形处理

    6a2485267cb658cb24a737d58f4fd9b1.png
    • 变换矩阵中的非对角线元素大都为零,若变换矩阵中的非对角元素不为
      ,则意味着
      同时对图形的变换起作用。也就是说,变换矩阵中非对角线元素起着把图形沿
      方向错切的作用。
    • 值或
      值越小,错切量越小;
      值或
      值越大,错切量越大。
    • 齐次坐标形式:
    • 沿
      方向错切,即

    5.4.5 复合变换

    • 图形作大于一次的变换,
      矩阵相乘不可交换!任何一个复杂的几何变换都可以看作基本几何变换的组合形式。
    • 二维复合平移:
    • 二维复合比例:
    • 二维复合旋转:

    5.4.6 坐标系变换

    • 图形变换经常需要从一个坐标系变换到另一个坐标系,如下图从
      变换到

    43146883177136cf7eaa332aaf4f98c4.png
    • 上图变换分两步完成,
      ,注意是从目标到源
      • 平移变换 —— 将
        坐标系的原点平移至
        坐标系的原点
      • 旋转变换 —— 将
        轴旋转到
        轴上

    5.4.7 任意参考点的几何变换

    • 在以往的变换中,以 (0, 0) 为参考点,倘若以任意点为参考点,则:
      • 将参考点移到原点(平移)
      • 针对原点进行二维几何变换(变换)
      • 将原点移到参考点(反平移)

    5.5 二维变换矩阵

    5.5.1 二维变换矩阵概述

    • 二维空间中某点的变化可以表示成点的齐次坐标与 3 阶的二维变换矩阵
      相乘

    e79fdf6ec296fb9374467b7b51b03987.png

    5.5.2 二维图形几何变换的计算

    • 点的变换:
    • 直线的变换(两端点的变换):
    • 多边形的变换(每个顶点的变换):

    5.4 窗口、视图及变换

    5.4.1 窗口和视区

    • 窗口:世界坐标系中要显示的区域
    • 视区:窗口映射到显示器上的区域
    • 窗口定义显示什么;视区定义在何处显示;二者需要进行坐标变换

    3bd44645d66ce521cb7f35ea36564c09.png
    • 世界坐标系中的一个窗口可以对应于多个视区

    4c82549a60f5434f114b97b37bae38b4.png

    5.4.2 观察变换

    • 观察变换 (Viewing Transformation)
    • 变焦距效果
      • 窗口放大/缩小,视区不变,图形缩小/放大

    320300b5f1ed860bb3fb364d3cc7249d.png
    • 整体缩放效果
      • 窗口不变,视区放大/缩小,图形放大/缩小

    d9f0cc0628898ef2de92b37252aeadbc.png
    • 漫游效果
      • 把一个固定大小的窗口在一幅大图形上移动,视区不变。

    5.4.3 窗口到视区的变换

    • 窗口的点
      视区的点

    1a156213e1f6ab4e55fc3edd0ecd9737.png
    • 保持比例的映射
      • 保持比例:映射之后,中心点仍然在中心,边界点仍然在边界
      • 比例保持:
      • 根据倍数关系:
      • 同理,
    展开全文
  • 艺术家在作画的时候可以把一个平面的二维图形使用一些技巧(线性投影)绘制成三维的图形,它的原理就是在一个想象中的消失点处把并行的线段聚合在一起,从而创建出立体的幻想。例如当我们站在铁轨上向铁轨的远处看时...

    想象一下你站在一个桌子前面,从你的角度观察桌子,你会看到你那端的桌子会显得较大,因为你是从一个角度向下观察的,而不是从空中俯视的。接下来我会继续改造上一篇文章的图形,让他看起来有三维的效果。

    一、三维的艺术

    艺术家在作画的时候可以把一个平面的二维图形使用一些技巧(线性投影)绘制成三维的图形,它的原理就是在一个想象中的消失点处把并行的线段聚合在一起,从而创建出立体的幻想。例如当我们站在铁轨上向铁轨的远处看时,会发现远处的铁轨消失在地平线上的一个点上了,铁轨上的枕木离我们越远,它看起来就越小,如下图所示:

    二、裁剪空间

    当顶点着色器把一个值写到gl_position的时候,OpenGL期望这个位置是裁剪空间中的,裁剪空间背后的逻辑非常简单:
    对于给定的位置,它的x、y以及z分量都需要在哪个位置的-w和w之间,假设这个位置的w是1,那么其x,y和z分量都需要在
    [-1,1]的范围内,超出该范围的事物在屏幕上都是不可见的。

    三、透视除法

    在一个顶点位置成为一个归一化设备坐标之前,OpenGL实际上执行了一个额外的步骤,它被称为透视除法。
    透视除法之后,那个位置就在归一化设备坐标中了,不管渲染区域的大小和形状,对于其中的每个可视坐标x、y和z分量的取值都位于[-1,1]的范围内。
    为了在屏幕上创建三维幻象,OpenGL 会把每个gl_Position的x、y和z分量都除以它的w分量。当w分量用来表示距离的时候,它使得较远处的物体被移动到距离渲染区域中心更近的地方,这个中心的作用就像一个消失点,中心点位置是(0,0,0)。OpenGL正是用这种方式欺骗我们的,使我们看见一个三维的场景。
    例如有2个坐标(1,1,1,1)和(1,1,1,2),在OpenGL把这些作为归一化设备坐标使用之前,它会进行透视除法,将前3个分量都除以w的值
    因此(1/1,1/1,1/1)变成(1,1,1),以及(1/2,1/2,1/2)变成了(0.5,0.5,0.5),可见有较大的w值的坐标被移动到距离(0,0,0)更近的位置了
    (0,0,0)就是归一化坐标系统里渲染区域的中心。在OpenGL中,三维效果是线性的,并且是沿着直线完成的。

    四、视口变换

    在我们看到屏幕的显示结果之前,OpenGL需要把归一化设备坐标x和y分量映射到屏幕的一个区域内,这个区域是操作系统预留出来用于显示的,称为视口(viewport);这些被映射的坐标被称为窗口坐标,除了要告诉OpenGL怎么映射之外,我们不需要关心这些坐标,因为在代码中我们已经在onSurfaceChanged中用glViewport方法告诉了OpenGL了。
    当OpenGL做映射的时候,会把(-1,-1,-1)到(1,1,1)的范围映射到那个显示预留的窗口上,而范围之外的坐标将会被裁剪掉。

    五、添加w分量创建三维图

    现在我们需要使用w分量加入到顶点的数据数组中,如下图所示:

    矩形区域的每个顶点都有4个分量,x、y、z、w,其中w用来控制距离,因此代码中的tableVerticesWithTriangles数组就需要做下调整了。

    val tableVerticesWithTriangles = floatArrayOf(
        // Order of coordinates: X, Y, Z, W, R, G, B
        // Triangle Fan
        0f, 0f, 0f, 1.5f, 1f, 1f, 1f,
        -0.5f, -0.8f, 0f, 1f, 0.7f, 0.7f, 0.7f,
        0.5f, -0.8f, 0f, 1f, 0.7f, 0.7f, 0.7f,
        0.5f, 0.8f, 0f, 2f, 0.7f, 0.7f, 0.7f,
        -0.5f, 0.8f, 0f, 2f, 0.7f, 0.7f, 0.7f,
        -0.5f, -0.8f, 0f, 1f, 0.7f, 0.7f, 0.7f,
        // Line 1
        -0.5f, 0f, 0f, 1.5f, 1f, 0f, 0f,
        0.5f, 0f, 0f, 1.5f, 1f, 0f, 0f,
        // Mallets
        0f, -0.4f, 0f, 1.25f, 0f, 0f, 1f,
        0f, 0.4f, 0f, 1.75f, 1f, 0f, 0f
    )

    同时还需要修改POSITION_COMPONENT_COUNT的值,将原来的2改成4,表示现在每个顶点有4个分量了。
    由于我把矩形的底部顶点的w分量设置为1,顶部的设置为2,这样顶部的坐标在进行透视除法之后,就会更加靠近中心点的位置了,运行起来的效果就如下图所示:

    六、透视投影

    在介绍透视投影之前,我在上一篇文章中用过一个正交投影矩阵来处理屏幕的宽高比的问题,通过调整显示区域的宽度和高度使之变换为归一化设置的坐标。
    在计算机三维图像中,投影可以看作是一种将三维坐标变换为二维坐标的方法,常用到的有正交投影和透视投影。正交投影多用于三维健模,正交投影的物体不会随距离观测点的位置而大小发生变化;透视投影则由于和人的视觉系统相似,多用于在二维平面中对三维世界的呈现,透视投影距离观测点越远,物体越小,距离观测点越近,物体越大。

    透视投影(Perspective Projection)是为了获得接近真实三维物体的视觉效果而在二维的纸或者画布平面上绘图或者渲染的一种方法,也称为透视图 。它具有消失感、距离感、相同大小的形体呈现出有规律的变化等一系列的透视特性,能逼真地反映形体的空间形象。透视投影通常用于动画、视觉仿真以及其它许多具有真实性反映的方面。

    6.1视椎体

    一旦使用了投影矩阵,场景中的并行线就会在屏幕上的一个消失点出汇聚在一起,当物体离得越来越远,它会变得越来越小。如下图所示,这个形状叫做视椎体

    这个观察空间是由一个透视投影矩阵和投影除法创建的,简单来说,视椎体只是一个立方体,其远端比近端大,从而使其变成了一个被截断的金字塔。两端的大小差别越大,观察的范围就越宽,能看到的也就更多。
    一个视椎体有一个焦点,这个焦点就是从椎体较大端向较小端扩展出来的那些直线,一直向前通过较小端直到它们汇聚到一起的那个点。
    当你用透视投影观察一个场景的时候,那个场景看上去就像你的眼睛放在了焦点位置上,焦点和视椎体小端的距离被称为焦距,它影响视椎体小端和大端的比例,以及其对应的视野,如下图所示就是从焦点处观察的到画面。

    可见从焦点看上去视椎体两端在屏幕上占据了同样大小的空间,视椎体的远端虽然较大,但是它也比较远,它任然占据同样大小的空间,这与我们看到日食是一样的道理,月亮虽然比太阳小很多,但是因为它近了很多,使得它看上去很大,大到可以遮盖太阳的光辉。

    来看看透视投影模型

    设视点E位于原点,视平面P垂直于Z轴,且四边分别平行于x轴和y轴,如上图所示,我们将该模型称为透视投影的标准模型,其中视椎体的近平面离视点的距离为n,远平面离视点的距离为f,且一般取近平面为视平面。基本透视投影模型对视点E的位置和视平面P的大小都没有限制,只要视点不在视平面上即可。P无限大只适用于理论分析,实际情况总是限定P为一定大小的矩形平面,透视结果位于P之外的透视结果将被裁减。可以想象视平面为透明的玻璃窗,视点为玻璃窗前的观察者,观察者透过玻璃窗看到的外部世界,便等同于外部世界在玻璃窗上的透视投影。

    6.2 透视投影矩阵

    透视投影矩阵需要和透视除法一起发挥作用,投影矩阵不能自己做透视除法,而透视除法需要某些东西才能起作用。如果一个物体向屏幕中心移动,当它理我们越来越远时,它的大小也越来越小,因此,投影矩阵最重要的任务就是为w分量产生正确的值,这样当OpenGL做透视除法的时候,远处的物体才会看起来比近处的物体小。能实现这些方法之一是利用z分量,把他作为物体与焦点的距离并把这个距离映射到w分量,这个距离越大,w值就越大,物体就越小。

    让我们来看一个更加通用的投影矩阵,它可以调整视野以及屏幕的宽高比

    其中
    1、变量a表示焦点,由 1/tan(视野/2)求得,tan表示正切函数,视野必须小于180度,比如一个90度的视野,它的焦距就是1/tan45,也就是1/1=1;
    2、aspect表示屏幕宽高比,等于宽度/高度;
    3、f表示到远处平面的距离,必须是正值且大于到近处平面的距离;
    4、n表示到近处平面的距离,必须是正值。比如,如果此值被设为1,那近处平面就位于一个z值为-1的处。

    当视野变小,tan(视野/2)就变小,焦距就会变长,可以映射到归一化坐标中[-1,1]范围内的x和y值的范围就越窄(小)。

    上图左边的是90°视角看到的内容,右边是45°视野看到的内容。

    七、在代码中使用投影矩阵

    创建MatrixHelper工具类

    object MatrixHelper {
    
        /**
         * 这个方法用来创建投影矩阵,和Android的perspectiveM相似,但是perspectiveM是高版本才有的
         * @param m 目标矩阵
         * @param yFovInDegrees 视野
         * @param aspect 宽高比
         * @param n 表示到近处平面的距离
         * @param f 表示到远处屏幕的距离
         */
        fun perspectiveM(m: FloatArray, yFovInDegrees: Float, aspect: Float, n: Float, f: Float) {
            // 视野
            val angleInRadians = (yFovInDegrees * Math.PI / 180.0).toFloat()
            // 首先计算焦距
            val a = (1.0 / tan(angleInRadians / 2.0)).toFloat()
            // 给矩阵填充值,OpenGL把矩阵数据按照以“列”为主的顺序存储,意味着我们一次写一列数据,而不是一行。
            // 第一列
            m[0] = a / aspect
            m[1] = 0f
            m[2] = 0f
            m[3] = 0f
    
            // 第二列
            m[4] = 0f
            m[5] = a
            m[6] = 0f
            m[7] = 0f
    
            // 第三列
            m[8] = 0f
            m[9] = 0f
            m[10] = -((f + n) / (f - n))
            m[11] = -1f
    
            // 第四列
            m[12] = 0f
            m[13] = 0f
            m[14] = -((2f * f * n) / (f - n))
            m[15] = 0f
    
        }
    }

    上面的代码就是完全按照6.2的矩阵图来填充数据的,只是填充的顺序是按列进行填充的。

    然后回到自定义的Renderer类,并删除onSurfaceChanged内的所有代码,只保留glViewport()的调用,然后使用MatrixHelper类创建投影矩阵并赋值给projectionMatrix矩阵数组

    // 调用正交投影矩阵帮助类创建投影矩阵
    MatrixHelper.perspectiveM(
        projectionMatrix!!,
        45f, // 这里使用45°视野创建一个透视投影
        width.toFloat() / height.toFloat(),
        1f, // 视点离近平面的距离,相当于z的起始坐标是-1
        10f // 视点离远平面的距离,相当于z的终止坐标是-10
    )

    上面代码的意思是用45°的视野创建一个透视投影,这个视椎体从z值为-1的位置开始,在-10的位置结束,也就是说视点到近平面的距离是1,到远平面的距离是10。

    然后还需要修改tableVerticesWithTriangles 数组,将顶点坐标的z和w分量去掉,同时将POSITION_COMPONENT_COUNT的值修改为2,表示现在只需要用到2个分量来表示坐标,修改后的数组如下:

    val tableVerticesWithTriangles = floatArrayOf(
        // Order of coordinates: X, Y, R, G, B
        // Triangle Fan
        0f, 0f, 1f, 1f, 1f, // 中心顶点,白色
        -0.5f, -0.8f, 0.7f, 0.7f, 0.7f,  // 顶点2
        0.5f, -0.8f, 0.7f, 0.7f, 0.7f, // 顶点3
        0.5f, 0.8f, 0.7f, 0.7f, 0.7f,// 顶点4
        -0.5f, 0.8f, 0.7f, 0.7f, 0.7f,// 顶点5
        -0.5f, -0.8f, 0.7f, 0.7f, 0.7f,  // 顶点2(为了能让1,5,2组成的三角形闭合,所以还是要重复定义顶点2)
        -0.5f, 0f, 1f, 0f, 0f,
        0.5f, 0f, 1f, 0f, 0f,
        // Mallets
        0f, -0.4f, 0f, 0f, 1f,
        0f, 0.4f, 1f, 0f, 0f
    )

    此时运行代码,会发现什么也看不到,只会看到黑屏,这是因为没有给图形指定z值的位置,那么默认的z值就是0,也就是位于视点的位置上,而我们定义的视椎体是从z值为-1的位置开始的,因此我们还需要把图形移动到那个范围[-1,-10]内,否则是无法看到的画面的,当然你可以修改顶点的坐标设置一个z值,但是我不推荐这种方式,这样相当于硬编码z的值了。我们可以使用平移矩阵来把图形移动到可视范围内。

    八、利用模型矩阵移动图形

    我们需要创建一个新的矩阵,就命名为模型矩阵吧,对应的数组是modelMatrix 

     // 定义模型矩阵用来移动物体的
     private var modelMatrix = FloatArray(16)

    然后回到onSurfaceChanged方法内,加入如下代码

     setIdentityM(modelMatrix, 0)// 先将modelMatrix填充为单位矩阵
     translateM(modelMatrix, 0, 0f, 0f, -2f);// 然后基于单位矩阵修改z的值,沿z轴平移-2

    接下来的操作就是要用投影矩阵与这个模型矩阵相乘,这样投影矩阵就会沿z轴进行平移,让视图出现在可视范围内。
    现在我们需要做一个选择,我们还需要把这个模型矩阵应用于每个顶点上,有两种方案:
    方案一:
    先给顶点着色器新增一个额外的矩阵,然后把每个顶点都与这个模型矩阵相乘,让他们沿着z轴负方向移动2个单位,然后再把每个顶点和投影矩阵相乘,这样OpenGL就可以做透视除法,并把这些顶点变化到归一化设备坐标了。
    方案二(推荐,本篇文章采用的也是这种):
    我们把模型矩阵先和投影矩阵相乘,得到一个新的矩阵,然后在把这个矩阵传递给顶点着色器,这样我们的着色器就不需要额外定义矩阵了。

    8.1 矩阵的乘法

    矩阵与矩阵相乘的原理和矩阵与向量相乘的原理相似,如下图所示:

    其实就是新的矩阵的每个元素的值=第一个矩阵的某一行与第二个矩阵的某一列的乘积之和,如上图所示为了求新矩阵的第一个元素(第一行,第一列),我们需要将第一个矩阵的第一行的每个元素与第二个矩阵的第一列每个元素相乘并求和。要求新矩阵的第二个元素(第一行,第二列),那就要将第一个矩阵的第一行的每个元素与第二个矩阵的第二列每个元素相乘并求和,其他的以此类推。

    8.2 矩阵乘法的顺序

    既然我们知道了如何把两个矩阵相乘了,那么还需要注意一点,当相乘的2个矩阵的位置互换时,结果是完全不一样的,例如:

     反过来相乘就是另一个结果了

    可以看到此时的结果和第一次的结果刚好上下颠倒,左右颠倒了。
    为了弄清楚我们应该使用哪种顺序,让我们看一下只使用投影矩阵的数学运算:
    vertex(clip) = ProjectionMatrix * vertex(eye)
    其中,vertex(eye)代表场景中的顶点在与投影矩阵相乘之前的位置。

    一旦加入模型矩阵来移动图形,那么这个数学公式如下:
    vertex(eye) = ModelMatrix * vertex(model)
    其中,vertex(model)代表顶点在被模型矩阵放进场景中之前的位置。

    合起来的公式如下:
    vertex(clip) = ProjectionMatrix *ModelMatrix * vertex(model)
    为了用一个矩阵替代这两个矩阵,我们不得不把投影矩阵乘以模型矩阵,就是把投影矩阵放左边,把模型矩阵放右边。

    因此,我们还需要在onSurfaceChanged结尾处加入如下代码:

    // 定义临时的矩阵,用来存储投影矩阵和平移矩阵相乘的结果
    val temp = FloatArray(16)
    // 将投影矩阵和模型矩阵相乘的结果赋给临时数组temp中
    multiplyMM(temp, 0, projectionMatrix, 0, modelMatrix, 0)
    // 然后再拷贝到projectionMatrix中,此时的projectionMatrix就包含了投影矩阵和模型矩阵的组合效果了
    System.arraycopy(temp, 0, projectionMatrix, 0, temp.size)

    ok,现在再运行下程序,将会看到下图效果:

    可以看到图形显示出来了,因为我们已经把图形移动到了z轴的可视范围内了,但是看到的是俯瞰的效果,这个并不是我们想要的。我们需要对图形进行旋转操作。

    九、增加旋转

    9.1 旋转的方向

    我们需要弄清楚需要围绕那个轴旋转以及旋转多少度,要搞清楚一个物体怎么围绕一个给定的轴旋转,我们使用右手坐标系统规则:伸出你的右手,握拳,让大母指指向正轴的方向,倘若是一个正角度的旋转,蜷曲的手指会告诉你一个物体是怎样围绕那个轴旋转的。

    想象一下分别用x轴、y轴、和z轴试一下这个旋转,假设围绕着y轴旋转,桌子会绕着它的顶端底端水平旋转。如果绕着z轴旋转,桌子会在一个圆圈内旋转。而我们这里是要让图形绕着x轴向视点方向旋转,因为这样会让图形看起来更有层次感。

    9.2 旋转矩阵

    我们将使用一个旋转矩阵去做实际的旋转,旋转矩阵使用正弦和余旋三角函数把旋转角度换成缩放因子,下面就是绕x轴旋转所用的矩阵定义:

    然后是绕y轴旋转所用的矩阵:

    最后是绕z轴旋转用的矩阵:

    以绕x轴旋转为例,假设旋转90°,那么按照定义,我们将得到一个如下的旋转矩阵

    让我们把这个矩阵与(0,1,0,1)向量相乘,将会得到如下结果:

    结果变由(0,1,0,1)变成了(0,0,1,1),坐标从y轴跑到了z轴上了。

    9.2 在代码中加入旋转

    回到onSurfaceChanged方法,修改平移的操作,加入如下代码

    translateM(modelMatrix, 0, 0f, 0f, -2.5f) // 修改平移为沿z轴移动-2.5f
    rotateM(modelMatrix, 0, -60f, 1f, 0f, 0f) // 旋转-60°

    可以看到我把之前的沿z轴平移-2.0f改成-2.5f了,因为一旦我们进行了旋转操作,它的底部会离我们视点变近了,因此我们需要再往远处移动一些,然后再绕x轴旋转-60°,现在在运行看看效果:

    切换到横屏的效果:

    完整的自意义Renderer代码如下:

    package com.example.openglstudy.demo6
    
    import android.content.Context
    import android.opengl.GLES20.*
    import android.opengl.GLSurfaceView
    import android.opengl.Matrix.*
    import com.example.openglstudy.R
    import com.example.openglstudy.util.LoggerConfig
    import com.example.openglstudy.util.MatrixHelper
    import com.example.openglstudy.util.ShaderHelper.compileFragmentShader
    import com.example.openglstudy.util.ShaderHelper.compileVertexShader
    import com.example.openglstudy.util.ShaderHelper.linkProgram
    import com.example.openglstudy.util.ShaderHelper.validateProgram
    import com.example.openglstudy.util.TextResourceReader.readTextFileFromResource
    import java.nio.ByteBuffer
    import java.nio.ByteOrder
    import java.nio.FloatBuffer
    import javax.microedition.khronos.egl.EGLConfig
    import javax.microedition.khronos.opengles.GL10
    
    class AirHockeyRenderer(private val context: Context) : GLSurfaceView.Renderer {
        private val vertexData: FloatBuffer
        private var program = 0
        private var aPositionLocation = 0
        private var aColorLocation = 0
    
        // 定义投影矩阵
        private val projectionMatrix: FloatArray? = FloatArray(16)
    
        // 定义保存矩阵unifrom的位置变量
        private var uMatrixLocation: Int = 0
    
        // 定义模型矩阵用来移动物体的
        private var modelMatrix = FloatArray(16)
    
        companion object {
            private const val A_POSITION = "a_Position"// a_Position名称对应attribute vec4 a_Position;中的名字
            private const val A_COLOR = "a_Color"// a_Color的名称对应attribute vec4 a_Color;
    //        private const val POSITION_COMPONENT_COUNT = 4 // 顶点分量
            private const val POSITION_COMPONENT_COUNT = 2 // 顶点分量
            private const val COLOR_COMPONENT_COUNT = 3 // 颜色分量
            private const val BYTES_PER_FLOAT = 4// 每个浮点数占的字节大小
    
            // 每个顶点的分量X,Y,R,G,B(包括位置分量和颜色分量)*每个分量占用的字节大小
            private const val STRIDE =
                (POSITION_COMPONENT_COUNT + COLOR_COMPONENT_COUNT) * BYTES_PER_FLOAT
    
            // 定义保存顶点着色器中定义的那个新的uniform的名字
            private const val U_MATRIX = "u_Matrix"
        }
    
        init {
           
            val tableVerticesWithTriangles = floatArrayOf(
                // Order of coordinates: X, Y, R, G, B
                // Triangle Fan
                0f, 0f, 1f, 1f, 1f, // 中心顶点,白色
                -0.5f, -0.8f, 0.7f, 0.7f, 0.7f,  // 顶点2
                0.5f, -0.8f, 0.7f, 0.7f, 0.7f, // 顶点3
                0.5f, 0.8f, 0.7f, 0.7f, 0.7f,// 顶点4
                -0.5f, 0.8f, 0.7f, 0.7f, 0.7f,// 顶点5
                -0.5f, -0.8f, 0.7f, 0.7f, 0.7f,  // 顶点2(为了能让1,5,2组成的三角形闭合,所以还是要重复定义顶点2)
                -0.5f, 0f, 1f, 0f, 0f,
                0.5f, 0f, 1f, 0f, 0f,
                // Mallets
                0f, -0.4f, 0f, 0f, 1f,
                0f, 0.4f, 1f, 0f, 0f
            )
    
            vertexData = ByteBuffer
                .allocateDirect(tableVerticesWithTriangles.size * BYTES_PER_FLOAT)
                .order(ByteOrder.nativeOrder()).asFloatBuffer()
            vertexData.put(tableVerticesWithTriangles)
        }
    
        override fun onSurfaceCreated(glUnused: GL10, config: EGLConfig) {
            glClearColor(0.0f, 0.0f, 0.0f, 0.0f)
            // 读取着色器的代码
            val vertexShaderSource = readTextFileFromResource(context, R.raw.simple_vertex_shader3)
            val fragmentShaderSource = readTextFileFromResource(context, R.raw.simple_fragment_shader2)
    
            // 编译着色器源码
            val vertexShader = compileVertexShader(vertexShaderSource)
            val fragmentShader = compileFragmentShader(fragmentShaderSource)
    
            // 链接程序并返回程序对象
            program = linkProgram(vertexShader, fragmentShader)
            if (LoggerConfig.ON) {
                validateProgram(program)
            }
    
            // 使用OpenGL程序
            glUseProgram(program)
    
            //获取matrix属性
            uMatrixLocation = glGetUniformLocation(program, U_MATRIX)
            // 获取位置属性
            aPositionLocation = glGetAttribLocation(program, A_POSITION)
            // 获取颜色属性
            aColorLocation = glGetAttribLocation(program, A_COLOR)
    
            // 绑定位置数据
            vertexData.position(0)
            glVertexAttribPointer(
                aPositionLocation,
                POSITION_COMPONENT_COUNT,
                GL_FLOAT,
                false,
                STRIDE,
                vertexData
            )
            glEnableVertexAttribArray(aPositionLocation)
    
            // 绑定颜色数据
            vertexData.position(POSITION_COMPONENT_COUNT)
            glVertexAttribPointer(
                aColorLocation,
                COLOR_COMPONENT_COUNT,// 第一个颜色是从缓冲区位置2开始
                GL_FLOAT,
                false,
                STRIDE,
                vertexData
            )
            glEnableVertexAttribArray(aColorLocation)
        }
    
    
        override fun onSurfaceChanged(glUnused: GL10, width: Int, height: Int) {
            // Set the OpenGL viewport to fill the entire surface.
            glViewport(0, 0, width, height)
            // 调用投影矩阵帮助类创建透视投影矩阵,设置投影的z值取值范围为[-1,-10]
            MatrixHelper.perspectiveM(
        	projectionMatrix!!,
        	45f, // 这里使用45°视野创建一个透视投影
        	width.toFloat() / height.toFloat(),
        	1f, // 视点离近平面的距离,相当于z的起始坐标是-1
        	10f // 视点离远平面的距离,相当于z的终止坐标是-10
             )
    
            // 平移操作
            setIdentityM(modelMatrix, 0)// 先将modelMatrix设置为单位矩阵
            translateM(modelMatrix, 0, 0f, 0f, -2.5f)// 然后基于单位矩阵修改z的值,沿z轴平移-2.5f
           
            // 加入旋转
            rotateM(modelMatrix, 0, -60f, 1f, 0f, 0f);
    
            val temp = FloatArray(16)
            // 将投影矩阵和模型矩阵相乘的结果赋给临时数组temp中
            multiplyMM(temp, 0, projectionMatrix, 0, modelMatrix, 0)
            // 然后再拷贝到projectionMatrix中,此时的projectionMatrix就包含了投影矩阵和模型矩阵的组合效果了
            System.arraycopy(temp, 0, projectionMatrix, 0, temp.size)
    
        }
    
    
        override fun onDrawFrame(glUnused: GL10) {
            // Clear the rendering surface.
            glClear(GL_COLOR_BUFFER_BIT)
    
            // 给着色器传递那个投影矩阵
            glUniformMatrix4fv(uMatrixLocation, 1, false, projectionMatrix, 0)
    
            // 现在不需要调用glUniform4f,因为我们已经将顶点数据和a_Color关联起来了,只需要调用glDrawArrays即可,
            // OpenGL会自动从顶点数据读入颜色属性
            // Draw the table.
            glDrawArrays(GL_TRIANGLE_FAN, 0, 6)
    
            // Draw the center dividing line.
            glDrawArrays(GL_LINES, 6, 2)
    
            // Draw the first mallet.
            glDrawArrays(GL_POINTS, 8, 1)
    
            // Draw the second mallet.
            glDrawArrays(GL_POINTS, 9, 1)
        }
    }
    

     

     

     

     

     

    展开全文
  • 图形绘制 特殊图形的绘制 1. 柱状图 matlab中主要有四个函数用于绘制条形图 bar() %绘制纵向的二柱状图 barh() %绘制横向的二柱状图 bar3() %绘制三纵向条形图 bar3h() 语法格式 bar...
  • 第三部分 三维图形的相关知识及三维图形的实现第7章 三维矩阵和变换 7.1 三维数学概念 7.1.1 操作三维对象 7.1.2 数学结构 7.2 三维中的基本矩阵和变换 7.2.1 C#中三维点和矩阵的操作 7.2.2 三维的基本变换 7.3 ...
  • 本人自己亲自完成的七个计算机图形学实验之,需要参考的就下吧,我只为赚取积分。
  • 从这篇文章开始,接下来会连载一系列的OpenGL相关博文,好好探讨...对于Android开发者来说,OpenGL就是用来绘制三维图形的技术手段,当然OpenGL并不仅限于展示静止的三维图形,也能用来播放运动着的三维动画。不管是三
  • 第三部分 三维图形的相关知识及三维图形的实现 第7章 三维矩阵和变换 396 7.1 三维数学概念 396 7.1.1 操作三维对象 396 7.1.2 数学结构 397 7.2 三维中的基本矩阵和变换 402 7.2.1 c#中三维点和矩阵的操作 ...
  • 第三部分 三维图形的相关知识及三维图形的实现 第7章 三维矩阵和变换 396 7.1 三维数学概念 396 7.1.1 操作三维对象 396 7.1.2 数学结构 397 7.2 三维中的基本矩阵和变换 402 7.2.1 c#中三维点和矩阵的操作 ...
  • 第一部分介绍c#基本的数据类型和图形基础技术,第二部分讲述二维图形的基本算法,第三部分介绍三维图形的相关知识及各种三维图形的实现,第四部分介绍c#中应用微软office的excel实现各种二维及三维图形,第部分...
  • matlab三维图形绘制.ppt

    2020-11-22 00:12:28
    4.2 MATLAB的 三维图形绘制;二绘制三维网格图和曲面图;2. 三维网格图;3. 三维曲面图 ;三绘制三维旋转体;四立体图形与图轴的控制;默认值az=-37.5el=30;色彩的控制;2色图的显示和处理(2) 浓淡处理shading;4.3 MATLAB...
  • 第二部分讲述二维图形的基本算法,第三部分介绍了三维图形的相关知识及各种三维图形的实现,第四部分介绍了C#中应用微软Office的Excel实现各种二维及三维图形,第部分讲述了实现文件的相关知识。  本书适用于从事...
  • 章 二维图形变换5.1 向量基础向量功能图形学中,处理三维物体,以及绘制对象的形状、位置、方向。有两大基本工具:向量分析、图形变换。向量:点和方向的实体 (没有位置)向量的表示两点之差是一个向量,方向指向...
  • 第三节 二维裁剪 一、线段裁剪 二、多边形裁剪第三节 二维裁剪 在二维图形的绘制或显示处理中,有时需要给出或显示某一部分原始图形。这可在适当位置按一定边界范围定义一个矩形区域(即窗口),使窗口内图形为所需...
  • http://blog.csdn.net/sky2098/article/details/1542966 第一节 用户坐标到屏幕坐标变换  1....  2....  3.... 4....第二节 二几何变换  一、 基本变换  1、比例变换  2. 对称变换  3. 错切变换
  • 其他三维图形 %绘制魔方阵的三维条形图 subplot(2,2,1); bar3(magic(4)); %以三维杆图形式绘制曲线y=2sin(x) subplot(2,2,2); y=2*sin(0:pi/10:2*pi); stem3(y); %已知x=[2347,1827,2043,3025],...
  • 一、基础使用 pro GrImage;IDL图像对象用例详解 oWindow=IDLgrWindow(DIMENSIONS=[400,300]) oView=IDLgrView() oModel=IDLgrModel() oView.Add,oModel oWindow.SetProperty,GRAPHICS_TREE=oView ...
  • (二维图形的创建) 1,在命令面板的【新建】,单击第二个按钮; 从中选择对象名称,在视图种单击拖动进行创建,特殊:线:摁【shift】限制水平,垂直方向; 2,二维对象参数: 在渲染中启用:显示二维线条(可...
  • 在 Origin 中可以绘制的三维图形主要包括以下这些:三维彩色填充表面图(3D surface)、三维符号图/条状图(3D Symbol/Bar)、数据分析图(Statistics)、等高线图(Contour)、图片(Image)种形式。Or...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 736
精华内容 294
关键字:

五维图形