GAME101笔记汇总
5-6.Rasterization:Triangles
这节课主要介绍光栅化本身,和现代光栅化的对象–三角形 相关的一些操作。即在经过将场景进行基本变换后,如何将变换后的正方形内容呈现在屏幕上。
5.1 介绍成像
首先弄清楚什么是屏幕。
再弄清楚像素,Pixel 原来是 picture element 的浓缩版。
定义屏幕空间,和每个像素的坐标表示方法
此时介绍一下各种成像设备(不仅仅是矩阵式像素成像、甚至不仅仅是屏幕)
绘制机也算作成像设备,但并非用屏幕
事实上即使用屏幕,也不一定是像素阵列
CRT 老式屏幕或电视机
液晶显示
LED 灯阵列
电子墨水
5.2 三角形
选用三角形作为基本形体单位的原因。
但应该如何把一个三角形给光栅化呢?
一种方式是对每个像素去采样,中心在三角形内即标内部颜色,否则标外部颜色。
判断像素是否在三角形以内可以用叉积判断点是否在三条边(全逆时针或全顺时针)的同侧。同即内部,否则外部。
对于刚好在边界的情况,通常只要自己定义清楚就行,在哪边都不回有太大影响(openGL 会根据是否是左上的边进行区别选择)
一些加速遍历的方法
一些实际机器上的像素排列。
三星 Galaxy S5 的排列方式可以节省一些像素点。绿色偏多是由于人眼对绿色更敏感。
一些其他的成像算法。比如打印机用这种排列,目的主要是为了节省油墨。
6.Rasterization:Antialiasing and Z-buffering
事实上仅仅用上节提到的采样方法,会得到这样的结果。非常不像我们想要的三角形。
甚至还有更严重的事情发生,比如采样得到了完全不同的花纹,这已经不是锯齿的问题了。
还有这种运动错觉(同偶尔看到车轮反转的错觉)
这些问题出在哪呢?
都是采样造成的问题
对于其中的锯齿问题
如果考察照相机(照片一般不会有这种问题),会发现位于边界的每个像素会吸收边界两边的光子,得到一个混合的结果,使整体看上去边界顺滑自然。
采样时也理应可以做到人工边界模糊,达到接近相机的效果。
比如先模糊,再采样。
效果还不错
但做这种事情时需要注意顺序:需要先模糊再采样,而非先采样再模糊
6.1 背后的信号原理
针对于前面的现象,应该如何解释呢?
这可以追溯至傅立叶变换
越高频的信号要求越高频的采样,否则会出现走样
对于图片而言,也可以进行二维的傅立叶分解
频域上的两条直线线主要由于做变换时等效于将图片横纵重复了很多次,而边界往往是非常难匹配的,即对应了高频变化。
频域上越远离中心,在时域上越对应突变的边
低频则对应于模糊
卷积定理:时域上的卷积,对应频域上的乘积。而频域上的卷积,对应时域上的乘积。
卷积定理的一个例子
而对于一个时域上的函数a,对其进行固定间隔采样的操作实质等效于用一系列冲击函数c去和a乘,最后得到e。
根据卷积定理,时域上的乘积对应频域上的卷积。
假设a对应的频域为b。而冲击函数c对应的频域为d。b和d卷积后则理应得到f。
这时我们可以看出如果原始函数比较低频,即对应的频域函数局限在较小区域,则在采样之后不会有重叠。
否则,则会在频域上有重叠,进而对于重叠部分无法区分是重叠导致的,还是原始信号天生如此,造成走样。
据此,分析反走样的原理也就比较容易了。
要么提高采样频率,相当于增大频域上的间隔,使其不容易重叠。
也可以通过模糊化操作,使其不包含高频信号,以至于不会重叠
除了模糊化以外,还可以采用对单个像素密集采样求平均的方法来减少锯齿或走样问题。
也能达到很好的效果,不过与此同时也需要付出计算代价。
最后介绍一些当下的反走样技术。
6.2 光栅化一个场景
知道了如何光栅化一个三角形,再介绍如何光栅化一个场景。
为了解决远近覆盖问题。容易想到的一种处理方式是画家算法:由远往近依次画。
画的时候近处物体覆盖远处物体。
但这样做也是有局限的。特别是有些情况下难以对三角形进行远近排序。
对三角形难以远近排序,对像素却是可以做到的,所以有了 Z-Buffer 算法。每个像素用 Z 最近的光栅化值。
实际上等效于在记录 RGB 三色的同时,加入 Depth 的记录。
由于只用找最小,而不是排序,所以 Z-Buffer 复杂度仅 \(O(n)\)
且为了更高的运行效率, Z-Buffer 已经集成在了各个 GPU 内部,直接硬件层面支持。
7-9.Shading:Shading,Pipeline and Texture Mapping
7.1 目前的进度和局限
能够用上面的方法绘制场景,即可做出如图的效果。
但这样是不够的。我们想得到下面的效果
为什么会这样呢?为什么“相同”颜色的方块的每一面颜色不一致呢?
容易发现,是环境光的影响。
我们看到的物体画面是由物体本身和环境光共同作用得到的结果。所以需要考虑环境光。
这个共同作用的方式,则体现出了物体的材质。
7.2 Shading 是什么
而 Shading 在本课中则对应着将材质应用于物体本身的过程。
7.3 Blinn-Phone 模型介绍
Blinn-Phong 是经验总结下的容易实现的材质模型。
其原理来自于观察
类似于绘画中的三大面。可以把物体表面分为高光区域、漫反射区域、环境光区域。
需要注意的是,Shading 有局部性,只关心每个三角形本身,不关心三角形相互的作用,
7.4 Blinn-Phone 漫反射
Blinn-Phong 模型中,漫反射的颜色受到三个部分影响
- 材料的固有色,对应一个系数(可为颜色向量) \(k_d\)
- 反光点和光源的距离光源,距离越远亮度月底,对应于 \(I/r^2\)
- 表面法线与光线的夹角,夹角越大则单位面积能反射的光子理应越少,一旦大过 \(\pi /2\) 则意味着背光,不再漫反射。于是对应于 \(max(0,n*l)\)
仅利用漫反射模型,且单一灰阶的固有色即可渲染出上面的效果。
8.1 Blinn-Phone 高光
再考虑高光项。
高光对应于镜面反射,摄像机越接近光源的镜面反射的出方向,则应接受到越强的镜面反射光。
度量这个“接近度”有一个聪明的比较容易的计算的方法,是比较光源方向和摄像机方向的中间方向(很容易计算)和法线方向的夹角,夹角越大则越不接近。
且对于这个接近度可以取一个次数 \(p\),使整体更容易调整,且接近想要的效果。
\(p\) 越高,高亮区域越小。通常而言会用到 100~200。
加入了高光项后,可以得到上图效果,且可以看出两个参数在调整时对结果的影响
8.2 Blinn-Phone 环境光
最后,对于暗部,并不希望全黑,所以可以加入环境光项,当然,并没有办法保证有光,也不可能环境光处处相同,所以这只是个不符合物理的趋近方法
最后综合 漫反射、高光、环境光 三项后可以得到上图效果
8.3 Shading 频率
同样是应用 Blinn-Phong,也可以由于面向对象不同得到不同结果,上方三张图依次对应于
- 低频:面向三角形
- 中频:面向顶点,三角形内部应用重心坐标差值
- 高频:面向像素
面向三角形的 Shading 计算量最小。但对于不够高面又光滑曲面的物体而言会不再光滑
对顶点着色,并应用差值
对每个像素着色。这里的 Phong Shading 对应于着色频率,而非 Blinn-Phong 着色模型。
这几种着色频率对应足够高面的模型而言表现是近似的。所以如果足够多面,应优先选择更低频的着色方式,减少计算量。
对逐顶点着色而言,是需要获得顶点的法线的。可以采用相邻三角形法线的简单平均,或者根据三角形面积加权平均。
对逐像素着色而言,则需要获得每个像素的法线方向,通常使用自己和附近面的法线用一些方式加权平均。
8.4 渲染管线
将一次渲染分成几步,大部分集成在 GPU 内部,成为硬件逻辑。部分可以编程。
比如一开始先处理顶点(等效于处理三角形,因为三角形被顶点决定)
光栅化
对片面的测试和处理(也可以算作光栅化的一部分)
Shading 根据不同着色频率可以对应至这两个步骤。
纹理映射也属于 Shading 一部分
纯靠 Shader 代码 800 行绘制出蜗牛
8.5 纹理映射
将二维的表面和一张二维的图逐点一一对应
一些纹理是可以上下左右拼接的,做到重复利用
9.1 三角形重心坐标
用对面三角形面积占比计算
用公式计算
9.2 应用纹理
直接采样,又会有锯齿问题
可以通过双线性插值(Bilinear)一定程度解决。当然还可以用 Bicubic 三阶差值(取周围16个点),得到更好的效果
双线性插值的方法
当纹理过大也会有问题,问题源自一个像素对应了纹理上太多像素
超采样可以解决,但计算量过大
Mipmap是一种对贴图进行预处理后很好的一种方式
使用 Mipmap 的情况下,如果直接为每个像素点指定一个层级,会让过渡比较硬。
可以用相邻两个层级进行线性插值
得到更好的结果
不过 Mipmap 依旧不能解决这个问题
这是由于 Mipmap 擅长解决正方形的采样,但不擅长非正方形的采样
所以后来还有 Ripmaps 可以支持任意正放的长方形采样
还有 EWA 更加复杂,但可以支持把任意形状分成多个圆形。但也意味着多次查询需要的更多开销
10.1 贴图的其他应用
记录环境光
环境光可以记录在球上,但球的两极会有扭曲,所以一般记录在正方体的表面
还可以记录表面相对高度,即凹凸贴图(与法线贴图目标近似,但计算和优势不同)
二维上计算法线的方式是查分求导再旋转。
三维也类似
还可以在处理顶点时事实地改变顶点位置。
不过这要求模型的精细度足够高,以保证有足够多的顶点可以随贴图改变。目前 Direct X 支持这种情况下动态改变模型的精细度。
纹理也可以是 3D 的,甚至是函数化的
还可以用于预烘培,提前计算一些阴影啥的
或者记录三维信息