GAMES101 Computer Graphics
- https://sites.cs.ucsb.edu/~lingqi/teaching/games101.html
- https://www.bilibili.com/video/BV1X7411F744
Overview of Computer Graphics (L1)
Review of Linear Algebra (L2)
逆时针旋转 θ
Rθ=[cosθsinθ−sinθcosθ]
Rθ=R−θ=RθT
Homogenous Coordinates
- 2D point xy1
- 2D vector xy0
- x′y′1=ac0bd0txty1⋅xy1
- xyw=x/wy/w1 表示一个二维点
- 两点相加得到中点
变换叠加
Mxy1=An⋯A2A1xy1
三维旋转
Rxyz(α,β,γ)=Rx(α)Ry(β)Rz(γ)
头:上下看 pitch 左右转 yaw 向日葵歪头 roll
Rodrigues’ Rotation Formula
绕轴 n 旋转 α:R(n,α)=cosα⋅I+(1−cosα)⋅nnT+sinα⋅0nz−ny−nz0nxny−nx0
四元数:为了解决旋转矩阵的插值问题
MVP
model view projection
相机
相机:位置 e 正对的方向 g^ 朝上的方向 t^
把相机放到 (0,0,0) 正对 −z 方向 头顶为 y 方向
M=R⋅T 表示先将相机放到原点 然后把相机的方向旋转到上述方向
M=R⋅T=(R−1)−1⋅T=xg^×t^yg^×t^zg^×t^0xtytzt0x−gy−gz−g00001T⋅100001000010−xe−ye−ze1
正交投影
将原空间放到原点 再在三个轴上缩放到 [−1,1]
top/bottom n(靠前的面 成像位置)/f(靠后的面 实际位置) left/right
M=r−l20000t−b20000n−f200001100001000010−2r+l−2t+b−2n+f1
透视投影
先将平面缩放到与期望的画布同大小 类似相似三角形 然后z对应的矩阵行用待定系数法确定 M=n0000n0000n+f100−nf0
做完这一步之后再使用正交投影将f处的画面拉到n处即可
Rasterization - Triangles (L5)
MVP做完之后我们会得到一个 [−1,1]3 的规范立方体
首先将这个立方体变换到 [0,width],[0,height],[−1,1]
M=w/20000h/2000010w/2h/201
然后要将三角形变到像素(这里暂时不考虑深度)
Text Only |
---|
| for pixel in image {
pixel.toRasterize = isInside(triangle, pixel.centerX, pixel.centerY)
}
|
isInside()
的实现:判断三角形三边与要判断的点的关系
AP×AB,BP×BC,CP×CA 的结果同向
加速光栅化:不对所有的像素遍历 只遍历可能的像素
Rasterization - Antialiasing (L6)
走样 - alias:以同一种频率采样两种不同频率的信号得到相同的结果
不希望看到的结果 - artifacts
aliasing artifacts 采样的速度跟不上信号变化的速度
解决方案
- 提高屏幕分辨率
- 先对三角形做模糊将高频分量抑制 然后再采样(回忆时域卷积-频率相乘)
- MSAA(multi-sample) 将像素分割为小像素然后计算出颜色比例
- FXAA(fast-approximate) 对有锯齿的图形作后期处理
- TAA(temporal) 利用两帧之间的运动信息
其他:超分辨率 用深度学习模型来猜缺失的采样点
Rasterization - Z-Buffer (L7)
画家算法
- 先画远处的东西 将近处的东西依次覆盖其上
- 对于三角形不适用
Z-Buffer
- 并行处理所有的三角形 光栅化后得到像素和深度
- 得到一个像素的深度后 和
depth buffer
存储的现有最小深度作比较 如果近的话 就将像素的颜色覆盖到frame buffer
上
Shading - Illumination (L7 L8)
- shading - 着色/上色 主要考虑的是一个小三角形面的材质对光线的反射 是局部的
- shading point 小面的中心点
- n^ 小面的法向量 注意面有厚度/有里外
- l^ 光线入射的方向
- v^ camera的方向
- shadow - 阴影 考虑的是物体间的遮挡关系
shading Blinn-Phong
- L=Ls+Ld+La
- specular highlights - 高光 反射
- 经验判断:出射光和观察方向差不多 也即入射光和观察方向的平均与法向差不多
- Ls=ksr2Imax(0,n^⋅h^)
- Ls 高光反射的光强度
- ks 高光系数
- h^=2v^+l^ 半程向量
- p p越大 高光越明显 光点越小 一般取64/128
- diffuse reflection - 漫反射 光线入射后从半球均匀射出
- Ld=kdr2Imax(0,n^⋅l^)
- Ld 漫反射的光强度
- kd 漫反射系数 越大表示漫反射越强 也就是越亮
- r2I 点光源发出的光强平方衰减
- cosθ=n^⋅l^ 入射光线越倾斜 小面得到光强就越小
- max(0,n^⋅l^) 考虑光线从物体后方入射 这时没有反射
- ambient lighting - 环境光 假定是常数
- La=kaIa
Shading - Frequencies (L8)
- Flat shading - shade each triangle
- Gouraud shading - shade each vertex
- Phong shading - shade each pixel
Shading - Graphics (Real-time Rendering) Pipeline (L8)
- Application
- Vertex Processing (Programmable: for each vertex)
- Triancle Processing
- Rasterization
- Fragment Processing (Programmable: for each pixel/fragment)
- Framebuffer Operations
- Display
在线编写shader https://www.shadertoy.com
Shading - Texture Mapping (L8 L9)
- 目的:将屏幕上的一个像素着色
- 过程:
- 找到屏幕上的像素中心对应的三维三角形 (xsys→xyz)
- 找到这个像素中心在三角形的重心坐标系中的位置 (xyz→αβγ)
- 用材质上面的像素点的颜色去插值得到需要显示的颜色 (αβγ→uv) 如果材质的三角形顶点上有属性 也可以插值得到屏幕上那一点的属性
- 颜色插值方法
- Nearest 点在材质的那个像素里面 就用这个像素的颜色
- Bilinear 点所在位置四周的像素的颜色做一个位置平均(先上下 再左右)
遇到的问题
- 采样走样:远处的像素看不出纹理
- 发生原因:远处屏幕上一个像素应该用纹理的一个很大的区域来平均 而不是直接取一个点附近的四个像素平均 这样不足以代表这个像素
- 解决方案:使用Mipmap
- 提前对纹理进行正方形区域的平均值计算 存储多占用33% 但是查询非常快
- 在查询时可以查询两层之间的值 只要做插值就行
- Mipmap斜的"像素"看起来很奇怪
- 原因:Mipmap只支持正方形查询
- 解决方案:各向异性过滤 Anisotropic Filtering
- 在纹理的存储图中存储矩形 存储量增大
- EWA filtering 使用椭圆切线处的纹理采样
Barycentric Coordinates
点在三角形内部的话 0<α,β,γ<1
αβγ=−(xA−xB)(yC−yB)+(yA−yB)(xC−xB)−(x−xB)(yC−yB)+(y−yB)(xC−xB)=−(xB−xC)(yA−yC)+(yB−yC)(xA−xC)−(x−xC)(yA−yC)+(y−yC)(xA−xC)=1−α−β
Application of Textures
将环境光记录在球面上