屏幕中的某一个窗口,可放大缩小和移动关闭.
窗口中可以用来绘图的部分.一般设置视口等于窗口.
成像景物所在空间的集合.
裁剪窗口会在三维空间中裁切一部分,其裁剪下来的部分经过投影变换在视口内可见.
整个裁剪窗口的三维坐标将完全映射到整个视口的二维坐标上.
(1) 坐标变换,包括视图变换、模型变换和投影变换。包括平移、旋转、缩放、投影等.
(2) 去除裁剪窗口外的部分
(3) 变换后的物体坐标与屏幕像素之间建立对应关系,成为视口变换
将二维坐标(x, y)扩充为三维坐标(xw, yw, w), 成为齐次坐标.
实际坐标 x = xw / w y = yw / w
e.g. (10, 5)可扩充(10, 5, 1), (20, 10, 2)…
[ x ′ y ′ z ] = [ 1 0 t x 0 1 t y 0 0 1 ] ⋅ [ x y 1 ] \left[ \begin{matrix} x' \\ y' \\ z\end{matrix} \right] = \left[ \begin{matrix} 1 & 0 & t_x \\ 0 & 1 & t_y \\ 0 & 0 & 1\end{matrix} \right] \cdot \left[ \begin{matrix} x \\ y \\ 1\end{matrix} \right] ⎣⎡x′y′z⎦⎤=⎣⎡100010txty1⎦⎤⋅⎣⎡xy1⎦⎤
可简写为
P ′ = T ( t x , t y ) ⋅ P P' = T(t_x, t_y) \cdot P P′=T(tx,ty)⋅P
绕原点旋转\theta角度
[ x ′ y ′ z ] = [ c o s θ − s i n θ 0 s i n θ c o s θ 0 0 0 1 ] ⋅ [ x y 1 ] \left[ \begin{matrix} x' \\ y' \\ z\end{matrix} \right] = \left[ \begin{matrix} cos\theta & -sin\theta & 0 \\ sin\theta & cos\theta & 0 \\ 0 & 0 & 1\end{matrix} \right] \cdot \left[ \begin{matrix} x \\ y \\ 1\end{matrix} \right] ⎣⎡x′y′z⎦⎤=⎣⎡cosθsinθ0−sinθcosθ0001⎦⎤⋅⎣⎡xy1⎦⎤
可简写为
P ′ = R ( θ ) ⋅ P P' = R(\theta) \cdot P P′=R(θ)⋅P
相对于原点的二维缩放
[ x ′ y ′ z ] = [ s x 0 0 0 s y 0 0 0 1 ] ⋅ [ x y 1 ] \left[ \begin{matrix} x' \\ y' \\ z\end{matrix} \right] = \left[ \begin{matrix} s_x & 0 & 0 \\ 0 & s_y & 0 \\ 0 & 0 & 1\end{matrix} \right] \cdot \left[ \begin{matrix} x \\ y \\ 1\end{matrix} \right] ⎣⎡x′y′z⎦⎤=⎣⎡sx000sy0001⎦⎤⋅⎣⎡xy1⎦⎤
可简写为
P ′ = S ( S x , S y ) ⋅ P P' = S(S_x, S_y) \cdot P P′=S(Sx,Sy)⋅P
复合变换时, 必须按操作的次序将每一步的变换矩阵左乘顶点的列矩阵.
P ′ = T n . . . ( T 3 ⋅ ( T 2 ⋅ ( T 1 ⋅ P ) ) ) P' = Tn...(T3 \cdot (T2 \cdot(T1 \cdot P))) P′=Tn...(T3⋅(T2⋅(T1⋅P)))
P ′ = ( T n . . . T 3 ⋅ T 2 ⋅ T 1 ) ⋅ P P' = (Tn ... T3 \cdot T2 \cdot T1) \cdot P P′=(Tn...T3⋅T2⋅T1)⋅P
使用复合矩阵能有效提高计算效率
(1) 平移对象使基准点位置移动到坐标系原点
(2) 绕坐标系原点进行旋转
(3) 反方向平移对象使基准点回到原来位置
R ( x r , y r , θ ) = T ( x r , y r ) ⋅ R ( θ ) ⋅ T ( − x r , − y r ) R(x_r, y_r, \theta) = T(x_r, y_r) \cdot R(\theta) \cdot T(-x_r, -y_r) R(xr,yr,θ)=T(xr,yr)⋅R(θ)⋅T(−xr,−yr)
(1) 平移对象使基准点位置移动到坐标原点
(2) 按坐标系原点进行缩放
(3) 反方向平移对象使基准点回到原来位置
S ( x r , y r , s x , s y ) = T ( x r , y r ) ⋅ S ( s x , s y ) ⋅ T ( − x r , − y r ) S(x_r, y_r, s_x, s_y) = T(x_r, y_r) \cdot S(s_x, s_y) \cdot T(-x_r, -y_r) S(xr,yr,sx,sy)=T(xr,yr)⋅S(sx,sy)⋅T(−xr,−yr)
将对象描述从xy坐标系变换到x’y’坐标系
(1) 将x’y’坐标系原点平移至xy坐标系原点
(2) 将x’轴旋转至x轴位置
M x y , x ′ y ′ = R ( − θ ) ⋅ T ( − x 0 , − y 0 ) M_{xy, x'y'} = R(-\theta) \cdot T(-x_0, -y_0) Mxy,x′y′=R(−θ)⋅T(−x0,−y0)
如果两个坐标系使用不同的比例,还需进行一次缩放变换以补偿两坐标系之间的差别.
将对象描述从x’y’坐标系变换到xy坐标系
M x y , x ′ y ′ = T ( x 0 , y 0 ) ⋅ R ( θ ) M_{xy, x'y'} = T(x_0, y_0) \cdot R(\theta) Mxy,x′y′=T(x0,y0)⋅R(θ)
基本与二维几何变换一致,这里只写一些不太一样的
利用绕坐标轴的旋转(结合适当的平移)的复合变换来表示绕任意轴的旋转.
绕z轴的三维旋转
[ x ′ y ′ z ′ 1 ] = [ c o s θ − s i n θ 0 0 s i n θ c o s θ 0 0 0 0 1 0 0 0 0 1 ] ⋅ [ x y z 1 ] \left[ \begin{matrix} x' \\ y' \\ z' \\ 1\end{matrix} \right] = \left[ \begin{matrix} cos\theta & -sin\theta & 0 & 0\\ sin\theta & cos\theta & 0 & 0\\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1\end{matrix} \right] \cdot \left[ \begin{matrix} x \\ y \\ z \\ 1\end{matrix} \right] ⎣⎢⎢⎡x′y′z′1⎦⎥⎥⎤=⎣⎢⎢⎡cosθsinθ00−sinθcosθ0000100001⎦⎥⎥⎤⋅⎣⎢⎢⎡xyz1⎦⎥⎥⎤
同理可得绕x, y轴的三维旋转
(1) 平移\旋转 对象使其旋转轴与某一坐标轴重合
(2) 绕该坐标轴进行旋转
(3) 反方向平移\旋转 对象使其回到原来位置
同二维坐标系变换
通过改变视口的位置,可以在输出设备的不同位置观察物体, 使用多个视口可在不同的屏幕位置观察场景的不同部分,也可以通过改变视口的尺寸来改变显示对象的尺寸和位置.
因为裁剪窗口要通过映射"占满"整个视口, 所以如果将不同大小的裁剪窗口连续映射到固定尺寸的视口, 可以得到"拉镜头"的效果
视口定义于规范化设备坐标系, 还是定义于设备坐标系取决于图形库
裁剪计算通常在规范化设备坐标系中进行
规范化视口位于一个单位正方形(此单位正方形即窗口)内
视口变换公式:
x v − x v m i n x v m a x − x v m i n = x w − x w m i n x w m a x − x w m i n \frac{xv-xv_{min}}{xv_{max}-xv_{min}} = \frac{xw-xw_{min}}{xw_{max}-xw_{min}} xvmax−xvminxv−xvmin=xwmax−xwminxw−xwmin
y v − y v m i n y v m a x − y v m i n = y w − y w m i n y w m a x − y w m i n \frac{yv-yv_{min}}{yv_{max}-yv_{min}} = \frac{yw-yw_{min}}{yw_{max}-yw_{min}} yvmax−yvminyv−yvmin=ywmax−ywminyw−ywmin
推导结果:
先缩放, 再平移
(1) 以点(xwmin, ywmin)为基准点执行缩放变换, 将裁剪窗口变换到视口大小
(2) 将点(xwmin, ywmin)平移到(xvmin, yvmin)
在选择OpenGL裁剪窗口和视口之前, 必须建立合适的模式以便构建从世界坐标系到屏幕坐标系的变换矩阵
在OpenGL中, 必须将裁剪窗口的参数作为投影变换的一部分来设置
先选择投影模式
glMatrixMode(GL_PROJECTION)
何时裁剪?
裁剪 -> 消隐 -> 投影
二维点的裁剪: 如果判断点在裁剪矩形框中, 保留, 否则裁剪掉
二维线的裁剪:
首要目标: 减少交点计算
若两个端点的区域码均为0000, 则线段完全在裁剪窗口内
若两个端点的区域码中有一对相同位置都为1, 则该线段完全在裁剪窗口外
"左右下上"对应低位1到高位1