GAMES101 Notes(First Round) - 闫老师GAMES101课程笔记(一刷)
图形学数学基础 (到这里为止就够了)
- 基础数学: 线性代数/微积分/统计学
- 基础屋里: 光学/力学
- 其他: 信号处理/数值分析
- 其他2: 美学???
向量
- 没有特定的起始点, 有方向和长度
-
Magnitude (length) of vector : $ \vec{a} $ - Unit Vector
- 向量加法
- 向量乘法
- 点积: (得到投影长度) (满足交换律, 分配律, 常数的结合率), 直角坐标系下等于各维度相乘后相加
- 法线相关计算
- 向量投影
- 向量分解为2个垂直向量之和
- 向量相对的向前/向后(cos(x))
- 叉积:
- x x y -> +z (右手系)
- 自己×自己得到0向量
- a x b = -b x a
- 分配律&结合率仍然存在
- 作用
- 判定左右: a x b得到z是正的, 则b在a的左侧 (左右是根据z轴来定的)
- 判定内外: 封闭平面所有向量逆时针排列后, 计算相同起点的叉积, 得到所有向量相同侧, 则在封闭平面内 (不在同一侧就在平面外)
- 得到0向量: 在边上, 自己说了算
- 点积: (得到投影长度) (满足交换律, 分配律, 常数的结合率), 直角坐标系下等于各维度相乘后相加
矩阵
- 单位矩阵和矩阵的逆
- 矩阵转置
- 乘法: 满足分配律和结合率, 不满足交换律
- 向量点乘可以等价为矩阵操作 (a点b = a转置乘b)
- 向量叉乘: 等于a向量的dual matrix x b
后续
- 齐次坐标
作业0
- 搭环境
2.2.2 函数体
- 请观察输出,并尝试解释这些结果(提示:C++ 三角函数运算使用弧度制)。
- 就是a
- a/b
- 根号2
- cos(180度) == -1, 所以arccos(-1) = 180度 = pi
- sin(30度) = 0.5
变换
- 为什么要学变换
- 2D变换: 旋转/缩放/shear(切变)
- 齐次坐标
- 组合变换
- 3D变换
为什么学习变换
- 模型(Modeling)变换
- Transition (摄像机在3D场景里面的移动)
- Rotation (机器人关节的旋转)
- Scaling
- 视图(Viewing)变换
- (3D to 2D) 投影 (拍照)
2D变换
矩阵 <–> 变换
- 缩放变换矩阵
s_x 0 0 s_y
- 切变
// 水平方向切变 1 a 0 1
- 旋转
// a: 逆时针旋转角度 // 通过取(1, 0)和(0, 1)这样2个特殊的点直接求出旋转矩阵 cos(a) -sin(a) sin(a) cos(a)
- 以上三种变换称为线性变换 (都可以写成一个矩阵)
齐次坐标
平移变换不能写成矩阵了! (平移变换不是线性变换)
- 加一个维度! -> 齐次坐标
2D的点, w = 1; 2D的向量, w = 0;
向量+向量 = 向量
点-点 = 向量
点+向量 = 点
点+点 = 无意义
x x/w
y 都表示2D的点 y/w, 其中w不等于0
w 1
- 仿射变换(Affine)矩阵
a b tx c d ty 0 0 1
(因为最后一行都是0 0 1, 所以存储仿射变换矩阵的时候, 都只需要存前2行) (可以看出, 它是先线性变换, 然后平移的!)
- 逆变换
逆变换的变换矩阵就是逆矩阵!
组合变换
- 变换顺序? (矩阵乘法不满足交换律)
- 矩阵变换的计算, 是右结合的!!!
- 一系列的矩阵相乘 (可以先把所有矩阵乘一块儿, 然后再跟被变换的点/向量相乘, 提高效率)
- 复杂变换的decomposing(分解)
- 把旋转中心移动到原点
- 旋转
- 移回去
3D变换
- 3D的齐次坐标一样, 加一维, 变成4维
- x,y,z分别除以w, 就得到了一个3D空间里的点
Lecture 4 变换 Cont’d
- 旋转-a, 对应变换矩阵为原矩阵转置
- 旋转-a, 也等于原矩阵取逆
- 因此转转变换矩阵是个正交矩阵
3D变换
- (Viewing transformation)观测变换
- Viewing (视图变换)/camera transformation
- Projection
- Orthographic Proj
- Perspective Proj
- 3D变换顺序: 缩放旋转平移
- 3D旋转 (通过3个方向的旋转, 可以旋转到任意方向)
- 欧拉角 <–> roll/pitch/yaw
- Rodrigues’ Rotation Formula: 通过该公式可以把3D的旋转(绕着某个轴转a)分解为3个轴的旋转
- 公式里的叉乘形式
View/Camera Transformation
想一下拍照:
- 先把人物摆好(Modeling)
- 然后找个好的角度(Viewing)
- 茄子(Projection)
- 怎么摆摄像机?
- 相机的位置
- 相机看向的方向
- 因为最后得到的照片永远跟相机和被拍摄物体的相对位置有关, 因此我们约定
- 相机永远放在原点, 以y为up, 看向-z (方便换算)
- 计算View矩阵:
- 先写出平移矩阵T
- 然后求xyz矩阵旋转到相机所在旋转的旋转矩阵的逆矩阵 (因为旋转矩阵是正交矩阵, 所以直接求转置就行了!)R
- 那么M = RT
- 然后投影 (3D->2D)
- 正交投影(不会有近大远小的效果)
- 让相机放在原点, 看向-z, up为Y, 然后直接把z坐标扔掉(233)
- 更好的做法:(将一个cuboid变成canonical cube (中心在原点, 边长为2的cube))
- 把cuboid移动到原点
- 然后x对应左右, y对应下上, z对应远近
- 这个变换的矩阵就是正交投影矩阵
- 透视投影(近大远小)
- 透视投影: 先把frustum挤为cuboid, 然后做一次cuboid
- 先把frustum挤为cuboid:
-
- 近平面永远不变, 远平面z值不变, 远平面中心点不变
- M persp->ortho
- 近平面永远不变, 远平面z值不变, 远平面中心点不变
-
- M ortho
-
- 先把frustum挤为cuboid:
- 透视投影: 先把frustum挤为cuboid, 然后做一次cuboid
- 正交投影(不会有近大远小的效果)
Chpt6
傅里叶变换和信号处理
- 任意一个函数都可以表示成很多个不同频率的正弦和余弦函数的和
- 采样频率越高,能够识别出的函数里的频率就越高
- 傅里叶变换可以将函数从“时域”变到“频域”
- 用傅里叶变换变换一张图,可以发现图片的大部分信息都在低频区
- 高通滤波:让高频信息剩下,可发现高频信息(信号发生了剧烈的变化)代表了图像中的边界
- 低通滤波:只让低频信息剩下,得到了一张模糊的图!(边界被去掉了)
- 留下高频和低频之间的信息,得到了一部分边界
- 推荐课程:《数字图像处理》
aliases(走样)
- 同样的采样方式,采样不同频率的函数却得到了相同的结果
Filtering = Convolution(卷积) = Averaging(平均)
- Convolution Theorem: 时域上两个信号的卷积等于频域上的乘积 (时域上两个信号的乘积等于频域上的卷积)
- 应用于图像处理:
- 进行滤波时,可以用一个filter在时域上对图像信号直接进行卷积,也可以把filter和图像信号都用傅里叶变换变到频域上,然后进行乘积,然后再逆傅里叶变换回时域的图像
Box Filter(卷积盒)
- 归一化: 让图像的亮度保持不变
- ?: Box Filter在时域上面变大了, 它在频域上面会如何变化? (会变小)
Sampling = 重复频域上的内容
- 冲击函数跟信号相乘, 得到了原始函数在冲击函数处的值 (时域上的乘积)
- 信号转换到频域, 冲击函数也转换到频域, 两者进行卷积 (频谱被复制粘贴了很多)
所以采样就是复制粘贴了原始信号的频谱
Aliasing
- 时域上采样不够快, 频谱上原始信号重叠, 造成走样
降低Aliasing
- 增加采样率 (更大的分辨率…)
- 先做模糊(低通滤波, 让频谱上的原始信号频域范围变小, 不容易重叠), 再做采样
- 低通滤波? (卷积, 也就是平均, 也就是 box filter)
- 为什么先采样再模糊是错的? 因为先采样会保留重叠的频谱,之后模糊也无法去掉频谱重叠的部分,因此无法降低aliasing
- 实际中的操作(MSAA: Antialiasing by supersampling)
- 模糊(得到每一个像素的覆盖率)
- 采样(直接取该像素的值, 因为就只有一个像素)
- Milestones
- FX(Fast Approximate)AA
- 先得到一个有锯齿的图, 然后把锯齿弄掉(通过图像匹配找到边界, 替换边界为无锯齿的边界)
- T(Temporal)AA (Tempo[c:]ral)
- 复用上一帧的边界感知结果, 在这一帧继续使用
- FX(Fast Approximate)AA
- Super resolution(超分辨率)
- 512512 -> 10241024, 但是不想看到锯齿, 怎么办
- 方案1: DL(Deep Learning)SS
- 512512 -> 10241024, 但是不想看到锯齿, 怎么办
Chpt7
画家算法
- 对所有三角形进行排序,时间复杂度O(nlogn),但是无法解决环型遮挡的问题
Z-Buffer
- frame buffer保存颜色信息
- depth buffer保存深度信息
本文中,我们认为z一直是正的,z越小越近(即往-z的方向看)
Shading
- 材质
- Blinn-Phong Reflection Model
- Diffuse Relection
Chpt 8
- Blinn-Phong着色模型
- 着色频率
- 图形渲染管线
Blinn-Phong模型
漫反射项 (diffuse) (上一节课)
高光项 (specular): 镜面反射方向和观察方向接近的时候才会出现 (半程向量和法线方向接近)
- 半程向量: 入射方向和观察方向的角平分线方向 (因为半程向量比反射方向要好算) 另:
- 高光通常认为是白色的
- 为什么要给高光项加一个指数? 高光很小, 不用指数的话高光范围太大了, 一般用的是100-200的指数
环境光照项 (ambient)
- 环境光应该是一个常数
着色频率
- 每个三角形当成一个平面来着色 (该三角形内部的法线是完全相同的), 就会得到一个全是三角形拼成的球面 (Flat Shading)
- 每个顶点着色 (Gouraud Shading)
- 逐像素着色: Pixel (Phong Shading)
方案:
- 顶点的法线可以认为是它关联的面的法线的平均
- 给平面上的法线进行插值 (重心坐标)
实时渲染 (图形渲染管线: 是一系列不同的操作)
- 输入: 一堆空间里的点
- 3D空间里的点处理到屏幕上 -> MVP
- 屏幕上的点连成三角形
- 光栅化 (Fragment) -> 采样
- Shaded Fragments(着色) -> Shading
- 输出: 三角形拼为图片(pixel)
Shader: 指定一个Vertex或者一个Pixel怎么进行着色 (相当于帮程序员省掉了并行的for循环)
- 推荐工具: Snail Shader Program
- Fragment Shader (像素着色器)
现代图形学的发展
- 超复杂的场景
- GPUs (独显/集显, 异构, 多核)
Texture Mapping (纹理映射)
- 不同位置可以映射到相同的纹理上
- 如果知道三角形的每个顶点的uv, 那么三角形内部的每个像素它应该是什么uv呢?
- 插值: 重心坐标 (Barycentric Coordinates)
chpt 10 几何
光栅化/几何/光线追踪/动画模拟
纹理的应用
- texture = memory + range query (filtering: 滤波)
- 环境贴图 (用一张图把四面八方的光都记录下来) 贴图只记录光的方向信息 (假设光来自无限远)
- Spherical Map -> 球面展开问题, 会变形
- Cube Map -> 变形少
- 凹凸贴图/Normal Map
- 位移贴图 (Displacement mapping): 真的把顶点进行移动
- Dynamic Tesselation : 动态曲面细分
- 3D空间中的噪声 -> 山脉
- ambient occlusion texture map : 环境光遮蔽, 存储阴影信息
- 3D纹理和体积渲染
- 环境贴图 (用一张图把四面八方的光都记录下来) 贴图只记录光的方向信息 (假设光来自无限远)
几何
- 几何形体
- 零件
- 布料
- 水花
- 城市
-
…
- 归类:
- 隐式几何
- 用公式or其他表示一个球
- f(x, y, z) = 0
- 坏处: 难以sampling
- 好处: inside/outside 测试很容易
- 显式几何
- 很容易采样: f(u,v) => (x=.., y=.., z=..), 把所有uv都走一遍就知道所有的xyz
- 难以判断某个点是否在表面内/外
- 隐式几何
- 更多implicit表示方法
- algebraic surface: 数学公式表示 (非常不直观)
- Constructive Solid Geometry (CSG): 各种建模软件/工程制图
- 距离函数: 空间中的任何一个点到想要表述的几何体的最小距离 (距离可以是正的或者负的)
- blend不能获得表示运动过程的中间状态
- 距离函数进行blend之后可以得到运动过程的中间状态
- Level Set Methods (水平集)
- 各种医学图像: CT/MRI等等
- 物理模拟
- Fractals (分形)
- 强烈的走样
Chpt 15
Irradiance: Power(watt) per unit area(m^2) (面与光线垂直)