光栅化
如何定义视椎体宽高比和垂直可视角度?
fov:垂直可视角度
t:在y轴的高度
n:近平面上的z轴上的点
tan(fov/2)= t/|n|
r:中心点到右边的距离
宽高比(aspect) = 2r/2t = r/t
如何将投射完成的标准立方体显示到屏幕上?
什么是屏幕?
- 二维数组
- 每个元素是一个像素
- 一种经典的光栅成像设备
光栅化:在屏幕上绘画
像素:
- 在屏幕上最小单位的小方块
- 由红绿蓝三原色混合而成
屏幕空间
- 像素都是以(x,y)的形式表示,其中x、y都是整数
- 像素的范围从(0,0)到(宽度-1,长度-1)
- 像素的中心在(x+0.5,y+0.5)
- 屏幕覆盖范围为(0, 0) 到 (宽, 高)
视口变换
- Z轴被忽略
- 将原本【-1,1】²的正方体变换为【0,宽】x【0,高】(视口变换)
- 视口变换矩阵
光栅显示设备
- 阴极射线管
- 隔行扫描方法
- CRT显示器
- 示波器
- 帧缓冲器
- 平板显示设备
- LCD(液晶显示器)
- OLED
- LED(发光二极管)
- 电子墨水屏
三角形-基本形状单元
- 最基础的多边形
- 任何多边形都可以
- 独特的性质
- 除非折成两个三角形,否则永远是一个面
- 三角形的内外很明确
- 可以利用重心插值进行三角形顶点插值
采样
在某个点对函数求值就是采样,我们通过采样将函数离散化。
Inside函数
inside(tri,x,y)
1:point(x,y)在三角形内
0:其余情况
遍历所有点,判断所有点是否在像素内
“`c++
for(int x = 0; x < xmax; ++x)
{
for(int y = 0; y < ymax; ++y)
{
image[x][y] = inside(tri, x + 0.5, y + 0.5);
}
}
<pre><code class="line-numbers">通过叉乘计算出(见叉乘在图形学的应用)点是否在三角形内
如果碰巧点在三角形的边界,本课程中不做处理,也可以特殊处理
#### 包围盒优化
利用包围盒(Bounding Box)对一定不会包含三角形的像素进行优化
<img src="../images/22.png" alt="包围盒" style="zoom:50%;" />
对于窄长的三角形并不友好
#### 采样的瑕疵
– 锯齿
<img src="../images/23.png" alt="抗锯齿1" style="zoom:40%;" />
通过inside函数渲染出来的三角形有明显锯齿
抗锯齿是图形学中重要的难题
**通过对原本三角形做模糊处理再进行采样可以抗锯齿(反走样)**
不能先采样再做模糊
之所以会出现锯齿(走样)是因为出现了**频谱混叠**(后面有讲)
– 摩尔纹
<img src="../images/24.png" alt="摩尔纹" style="zoom:40%;" />
– 车轮效应
信号时间变化太快以至于采样跟不上变化的速度
#### 时域与频域
频域是描述信号在频率方面特性时用到的一种坐标系
时域是描述数学函数或物理信号对时间的关系的一种坐标系。
#### **傅里叶级数展开**
傅里叶变换会将时域转化为频域
<img src="../images/25.png" alt="傅里叶级数展开1" style="zoom:60%;" />
<img src="../images/26.png" alt="傅里叶级数展开2" style="zoom:50%;" />
将函数表示为正弦余弦的加权和
随着展开式越来越多,越来越接近我们想要表达的函数
<img src="../images/27.png" alt="采样精度" style="zoom:50%;" />
如果采样的频率不够,还原过来的函数就会越来越不精准
频域和时域可以通过傅里叶变换和逆变换互相转换
#### 傅里叶频域图
<img src="../images/28.png" alt="傅里叶频域图" style="zoom:60%;" />
#### 滤波
删除特定的频率被称之为滤波
高通滤波:只显示高频信息(只显示边界-锐化),将低频信息盖住
低通滤波:只显示低频滤波(画面变模糊),将高频信息盖住
#### 卷积
滤波=卷积(=平均)
<img src="../images/29.png" alt="卷积" style="zoom:40%;" />
简化的定义:结果为相邻数的平均值
定理:时域的卷积等于频域的乘积
<img src="../images/30.png" alt="卷积" style="zoom:40%;" />
#### 频谱混叠
<img src="../images/31.png" alt="频谱混叠" style="zoom:60%;" />
由于采样稀疏,因此出现频谱混叠从而出现锯齿(走样)如果屏幕中像素非常多,密集的采样就不容易出现走样。
因此使用分辨率高的显示器,频谱的搬移间隔大,不容易出现频谱混叠。
<img src="../images/32.png" alt="抗锯齿2" style="zoom:70%;" />
同时,将信息进行低通采样再进行采样即可反走样。
#### 反走样(抗锯齿)
解决方法:
– 通过将每个像素进行模糊卷积f(x,y)
– 卷积=滤波=平均
– 然后再对灭个像素的中心取样
在光栅化一个三角形时,像素颜色的平均值f(x,y)= 三角形的覆盖像素的面积
<img src="../images/33.png" alt="抗锯齿3" style="zoom:50%;" />
##### 超采样抗锯齿(MSAA)
MSAA: Antialiasing By Supersampling
这是一种对反走样的近似
将每个像素的内部多增加采样点再进行模糊卷积
<img src="../images/34.png" alt="MSAA" style="zoom:50%;" />
MSAA X4
缺点:增加了很多的计算量
##### 其他的抗锯齿方法
– FXAA (Fast Approximate AA)
– 快速近似抗锯齿
– 图像的快速处理
– TAA (Temporal AA)
– 对上一帧进行处理
### 超分辨率
从低分辨率处理成高分辨率
与反走样类似,也是解决了样本不足的问题
目前可使用DLSS(深度学习的方法)进行超分辨率处理
### 画家算法
灵感来源于画优化
先画(渲染)距离远的,再画(渲染)距离近的。
问题:难以确定谁在前谁在后
<img src="../images/35.png" alt="画家算法" style="zoom:70%;" />
### 深度缓冲(Z-Buffer)
– 深度图-储存每个像素对应的最浅的深度
– 结果图-储存最终的结果
特别定义:Z越小(越黑)越近,越大越远(与通常的右手系不同,仅仅为了便于理解)
<img src="../images/36.png" alt="深度缓存1" style="zoom:70%;" />
算法:
“`c++
//默认深度为无限远
for(each triangle T)
{
for(each sample(x,y,z) in T)//遍历任意一个三角形中的任意一个像素
{
if(z<zbuffer[x,y])//如果此时的深度小于之前记录好的深度
{
framebuffer[x,y] = rgb;//三角形着色
zbuffer[x,y] = z;//更新小的深度
}
else
{
//…
}
}
}