文章目录
- 前言
- 正文
-
- 视图变换
-
- 视锥(frustum) 、视锥角,宽高比
- 将标准立方体投影到屏幕上(视口变换)
-
- 屏幕像素
- 视口变换
- 光栅化
-
- 显示设备
- 三角形
- 采样
- Bounding Box(包围盒)
前言
本文为GAMES101 学习笔记系列。
我们的系列笔记将分为两部分:
- 课堂笔记
- 作业
2020年2月严令琪教授的原课程 GAMES101 。
课程主页:https://sites.cs.ucsb.edu/~lingqi/teaching/games101.html (幻灯片和课程视频都在这里)
共有22节课。共有8次作业。
对人群:计算机图形学入门新手
: Steve Marschner and Peter Shirley的"Fundamentals of Computer Graphics" 第三版或更新版。目前没有官方中文版。 民间翻译:https://www.stubbornhuang.com/1812/
笔记目录
2022-6-5
正文
本节内容
- 视图变换(续) – 视口变换
- 光栅化 – 光栅三角形
视图变换
视锥(frustum) 、视锥角,宽高比
如何确定视锥?
首先确定距离,即近平面和远平面的z坐标,n和f
然后确定形状。有两种确定方法:
- 给定近平面宽度和高度
- 给定视锥角 field of view(fov) (上下角度和左右角度也是两个参数)
一般来说,我们混合使用它,即:
- 给定宽高比 aspect ratio(width/height)
- 给定上下的可视角度 fovY
根据这两个参数,加上平面距离。我们可以找到任何平面的宽度和高度。
例如:已知距离|n|,以及fovY,以及aspect ratio
于是平面t(top, 也就是说,最大y坐标可以通过以下关系找到 tan ( f o v Y / 2 ) = t ∣ n ∣ \tan (fovY/2) =\frac{t}{|n|} tan(fovY/2)=∣n∣t
平面的r(right,也就是说,最大的x坐标可以通过以下关系找到 a s p e c t = r t aspect = \frac{r}{t} aspect=tr
由此可见,视锥角度+宽高比+距离可以求出视锥上的任意平面
将标准立方体投影到屏幕上(视口变换)
上节课说到,将3D物体显示到2D屏幕上需要两步:
- 将透视投影的视锥转换为正交投影的标准立方体(MVB变换)
- 将正交投影的标准立方体投影到屏幕上(视口变换)
这次我们讲第二步。
首先,我们的标准立方体是[-1, 1]^3的这样一个立方体。
为什么需要这样一个立方体?
因为屏幕的尺寸和分辨率(比如有的是27寸,有的是24寸,有的是4K,有的是2K)各不相同。所以这其实是相当于我们先把所有信息都归一化,然后再缩放到具体的屏幕上去。
为此我们需要先定义屏幕的像素是什么?
屏幕像素
像素pixel是picture element的缩写,可以认为它就是只能表示一种颜色的一个小方块。
它的颜色用R G B三个数来表示,分别代表红绿蓝。将三原色混合就得到了任意颜色。
整个屏幕就是铺满了若干这样的小色块。
由此,我们需要对这些像素进行编号。
我们规定:
- 坐标原点位于左下角
- 像素编号都是整数,x坐标编号从0到width-1,y坐标编号从0到height-1,因此一共有width*height个像素
- 像素的位置设定为色块的中心,也就是说像素位置=(x+0.5, y+0.5)。 这里x和y都是整数编号
接下来我们就可以做变换了。
视口变换
将标准立方体的坐标变换到屏幕上,这样的变换被称为视口变换(viewport transformation) (为什么叫视口?我猜是把屏幕想象成一个窗口,因为是向外看的窗口,所以叫视口)
立方体还有个z坐标,目前我们暂时忽略z坐标。
也就是 [ − 1 , 1 ] 2 = > [ 0 , w i d t h − 1 ] [ 0 , h e i g h t − 1 ] [-1, 1]^2 =>[0, width-1] [0, height-1] [−1,1]2=>[0,width−1][0,height−1]
为此,我们先缩放,再平移即可。
缩放:原本的尺寸是2x2,现在的尺寸是width x height 所以x方向缩放 width/2, y方向缩放height/2
平移:原本位于原点,现在位于 (width/2, height/2) 所以只需要x方向上平移width/2, y方向平移height/2
写出变换矩阵: M v i e w p o r t = ( w i d t h / 2 0 0 w i d t h / 2 0 h e i g h t / 2 0 h e i g h t / 2 0 0 1 0 0 0 0 1 ) M_{viewport} = \begin{pmatrix} width/2 & 0 & 0 & width/2 \\ 0 & height/2 & 0 & height/2\\ 0 & 0& 1 & 0 \\ 0 & 0& 0 & 1 \\ \end{pmatrix} Mviewport=⎝⎜⎜⎛width/20000height/2000010width/2height/201⎠⎟⎟⎞
光栅化
显示设备
-
打印机
-
阴极射线管 隔行扫描
-
帧缓冲(frame buffer) 显示的本质是将显存内的数据输出到屏幕上。
-
LCD LCD(Liquid Crystal Display) 即液晶显示器 利用光的偏振。用一个个光栅控制光波方向 需要发光背板
-
LED Light Emitting Diode 发光二极管 也就是一个个发光的阵列
-
电子墨水(Electrophoretic) 利用电场控制墨滴。缺点是刷新慢。
三角形
为什么用三角形?
- 基础且简单,可以组成任意多边形
- 保证共面
- 很容易定义内外(向量叉积)
- 容易插值,可以根据顶点做渐变(重心插值)
我们关心的问题在于:已知三个顶点定义的一个三角形,我们想把它涂成红色,那么我们该如何对像素进行操作?
最简单的方法就是:采样
采样
什么是采样?就是将一个函数离散化
如下就是一种采样
我们要做的采样如下: 我们要把所有像素中心位置在三角形内的像素涂红
我们定义如下分段函数:
也就是,在三角形内部,就定义为1,不在,就定义为0
我们只需要对屏幕所有像素进行循环
如何判断一个点是否在三角形内部呢?
之前其实已经讲过了:用叉乘。
只需要点在三条边的同一侧即可。
用向量P0P1与P0Q叉乘,会都得到一个向量,看该向量的z坐标是正是负(正的代表Q在P0P1的左侧) 同理,判断Q在P1P2,以及P2P0的左侧还是右侧。如果Q在三条边的同一侧(无所谓是左侧还是右侧),那么Q一定在三角形内部。否则就不在。 假如恰好落在边界上,我们无需处理。
Bounding Box(包围盒)
没必要检查整个屏幕,只需要检查bounding box(包围盒)就行了。
更进一步的,假如对于倾斜的,很狭长的三角形,可以直接去求它边的最小最大坐标。