闫令琪教授的games101课程笔记哒
1.Review of Linear Algebra(线性变换总览)
vector:(dot product,cross product)点乘,叉乘
matrices:(matrix-matrix,matrix-vector mult)矩阵和矩阵,矩阵和向量乘法
vector:
length of a vector written as (向量长度)
$$
\vert\vert\vec{a}\vert\vert
$$
unit vector as(单位向量)
$$
\hat a=\vec a/\vert\vert\vec{a}\vert\vert
$$
dot product(点乘)
for is unit vector(对每个单位向量而言) :
$$
\cos \theta=\hat a ·\hat b
$$
properties(属性):
in cartesian coordinates(在笛卡尔坐标系):
dot product in graphic:
find angle between two vectors
(e.g. cosine of angle between light source and surface)
find projection of one vector on another
other benefits of dot product:
测量两个方向有多近
分解一个向量
确定两个向量是同向还是反向
cross product(叉乘)
叉积与两个初始向量正交,由右手法则定义方向,用于构造坐标
properties:
对了顺带一提,OpenGL是右手系,DirectX,unity为左手系
dot product in graphic:
叉积可以定义左和右,定义里和外。
matrix(矩阵)
如图所示为3行2列矩阵。
multiplication :
properties :
妹有交换率啊!!
在2d中对于Y轴对称
AB的转置矩阵=B的转置乘A的转置
点乘和叉乘在向量中的表示
4.18 12:31补完!
2.Transformation (变换)
the formula of linear transform(线性变换公式)
不多bb直接上图,这节课都是公式:
some problem of linear transform(线性变换遇到的问题)
then我们发现平移没办法用线性变换表示,所以我们引入”齐!次!坐!标!“
homogeneous coordinates:
引入第三个坐标系,用1表示点,用0表示坐标
0和1的相加,这是巧合吗?
point+point等于两点的中点
affine transformations(仿射变换)
我们认为仿射变换是线性变换加平移
using homogeneous coordinate:
矩阵没有交换律!!!
以上那些都是2d的,如果我们是3d的呢?
下一章见!!
4.18 13:06补完!!!
3.Transformation Cont
3D transformations(用矩阵表示3D变换)
viewing transformation(观测变换)
view / camera transformation
用公式表示旋转
projection
projection
- orthographic projection
- perspective projection
呜呜呜这话实在太水了因为实在不想写,到时候再看公式回忆吧4.18 13:58补完
4.Resterization 1(Triangle) (三角形光栅化)
- Different raster displays
- Rasterizing a triangle
sometime people prefer:
vertical field-of-view (forY) and aspect ratio (assume symmetry i.e I=-r,b=-t)
即视锥定义需要长宽比和垂直角度
由可视角度和距离即可求屏幕大小
what‘s after MVP(MVP变换)
- model transformation (placing object)
- view transformation(placing object)
- projection transformation(placing object)
canonical cube to screen!(像素是屏幕上规范的正方形)
这里可以暂时抽象认为像素是最小单位
像素被写作(x,y),都为整数,从(0,0)开始,蓝色方块坐标为(2,1)
像素的指数从(0,0)到(width-1,length-1)
像素中心在(x+0.5,y+0.5)
屏幕范围为(0,0)到(width,length)
transform in xy plane:
视口变换
(看不懂的滚回去看第三节!)
小知识:
隔行扫描(先偷懒扫1357…第二次扫2468….)利用了人眼的视觉暂留,提高了扫描的效率
超出人眼视网膜最大分辨率的屏幕被称为视网膜屏幕
LCD(液晶显示器)利用液晶影响光的极化
LED(发光二极管)利用阵列变成屏幕
部分电子书设备(例如kindle)利用电子墨水瓶来控制墨水的朝向
triangle - Fudamental Shape Primitives(三角形是最基本的图形)
- 三角形是最基本的图形,所有图形能拆成三角形
- 三角形一定是平面的,有清晰严格的内外定义区分
- 只需要确定三个点,就可以三角形内部取一个点,控制它到三个点的距离得到一个渐变的过程
a simple approach:sampling(采样)
这里的采样是指利用像素中心对屏幕进行采样,得到每个像素的像素中心是否在图形的内
sample if each pixel center is inside triangle
这里我们定义inside(t,x,y)
{if((x,y)在三角形t内) return 1;else return 0;}
rasterization==sample a 2d indicator function
所以,光栅化则是对2d屏幕进行采样
for (int x=0;x<xmax;++x)
for (int y=0;x<tmax;++t)
image[x] [y]=inside(tri,x+0.5,y+0.5);
白色区域不可能碰到三角形,固不考虑,只考虑三角形的包围盒(bounding box)
初稿完成于2021.4.12 !这里是分割线!
5.Rasterization 2(Antialiasing and Z-Buffering)(反走样和深度缓冲)
这节课介绍反走样和深度缓冲,这节课难得多555
概念:锯齿=走样,抗锯齿=反走样(采样和走样的关系参考卖家秀和实物图,网恋和奔现)
视频是对时间进行采样,得到一帧帧连续的图
problem of sampling(采样遇到的问题)
- 锯齿(Jaggies-sample in space)
- 摩尔纹(图像去掉奇数行和奇数列)(moire undersample images)
- 看到物体倒转(人眼在时间中的采样跟不上运动速度)(wagon wheel effect-sample in time)
原因:信号变化太快但采样跟不上
antialiasing idea is pre-filteringbefore sample(在采样前做滤波/模糊)
先做一个模糊(滤波)然后再采样(行!)
错误示范:先采样再模糊(那岂不是更糊)(不行!)
frequency domain(频域)
傅里叶奇数展开:任何周期函数都能写成正弦和余弦函数和常数项
傅里叶变换:一个函数经过某复杂变换变成另一个函数
逆傅里叶变换:再变回去
每隔一段时间采样,频率越高越不准确
两种频率用同一种方法进行采样,得到的确是一样的结果,我们无法区分他们,这就称为“走样”
模糊(滤波):抹掉特定频域的频率(大师我悟了)
傅里叶变换把一个函数从时域(空间不同位置也算时域 )变到频域,让我们看到图像在各个不同频域长什么样,我们称为频谱。
图像中心最低频,边缘最高频,图像信息的多少通过亮度来表示(例如上图的信息就主要集中在低频区域)
高通滤波(high pass filter):把低频信息屏蔽,再逆傅里叶变换变成图像
如图所示高通滤波后图片剩下边界,我们认为边界是图像中变化较大的交界处
剧烈变化=高频信息
低通滤波(low pass filter):把高频信息屏蔽,再逆傅里叶变换变成图像
如图所示边界变得模糊,因为高频信息被去掉了
如图所示是圆通滤波中通滤波申通滤波(误)
filtering = cnvolution (=averaging)(滤波=卷积=平均)
滤波=卷积=平均?
卷积(图形学简单定义):信号在一个地方的周围做一个平均
卷积定理:时域上对两个信号进行卷积相当于对他们的频域进行乘积
相反也适用(时域上对两个信号进行乘积相当于对他们的频域进行卷积)
所以我们,将图片(时域)进行傅里叶变换,得到频域,把卷积的滤波器也变到频域上,两者相乘,再逆傅里叶变换变回图像
如图所示,图像的频域和滤波器的频域相乘再逆傅里叶变换,就成功对图像进行了模糊
此处盒型滤波器=低通滤波器
若盒子变大,频域上他会变小,因为盒子越大相当于越模糊=边界越不明显=高频信息越来越少,所以频域上变小了
sampling = repeating frequency contents(采样=重复频率上的内容)
采样=重复频率上的内容
如图所示,左边为时域右边为频域
这里a和c乘积=b和d的卷积,得到一堆重复的频谱
所以采样就是重复一个原始信号的频谱
若采样率不足/采样(复制粘贴)的速度太慢(如图所示),原始信号混叠,那这就是走样了!
how can we reduce aliasing error?(我们怎么减少混叠错误)
- 提高显示器分辨率
- 先做模糊再做采样(反走样)(钱不够算法凑)
(有没有豁然开朗的感觉呢)
如图所示以每个像素进行模糊
antialiaing by supersampling(超级采样)
Multi sample antialiaing(MSAA)
把一个像素划分为更小的点,判断是不是在三角形内,然后再平均起来
MSAA不是靠增加分辨率来直接抗锯齿的,而是靠模拟模糊得到近似三角形。
but not free lunch,多倍采样会造成大量的性能损耗(显卡在燃烧)
FXAA(Fast Approximate AA)
先把锯齿图得出,然后再进行后期处理(不是模糊),通过图像匹配找到边界,然后将其换成没有锯齿的边界,非常快速效果也不错。
TAA(Temporal AA)
静态时复用上一帧的结果(先不谈运动时如何使用)
DLSS(Deep Learning Super Sampling)(老黄家RTX的招牌)
通过深度学习把其他样本猜出来,将细节补充,从而提升分辨率
本文于4.15的14:18编辑完成,这周会把前面的补上的!
6.Shading 1(Illumination,Shading)(照明和着色)
小葵花妈妈课堂开课啦(误)
Z-Buffer(深度缓冲)
Visibiliy(可见性):如何把多个物体显示在屏幕上,且位置的对应关系是对的
画家算法:先将远的物体光栅化,如何再逐渐光栅化近的物体
因为画家算法没有办法解决这种杠精问题
所以大伙引入了Z-Buffer(深度缓冲)
Z-Buffer(深度缓冲):
我们之前默认相机放在原点离-z方向看,这里假设z越小离我们越近
同时生成一个frame buffer和一个z buffer(维护每个像素的深度)
就像这样
算法如图所示
假设这里的R是无限大,深度小的(即离我们更近)就会把深度大的遮挡住
这里我们维护的对象是每一个像素
透明物体没办法渲染!!!!!!
小结
总结一下我们目前学习的内容
- 将模型变换(model)
- 将视图变换(view)
- 三维投影到屏幕(projection)
- 进行光栅化,得到采样结果(rasterization)
だから
shading(着色)他来啦!!!
shading(着色)
来跟我读:谢顶
在图形学中,我们定义着色为对不同物体使用不同材质,不同材质和光线的相互作用有不同的方法
我们可以看到高光(specular highlight),漫反射(Diffuse reflection),环境光(ambient lighting)
diffuse reflection in Blinn-Phong Reflectance Model(布林冯中的漫反射)
我们再来做一些定义:
shading point:考虑一个点(在极小范围内的一个平面)的结果
surface normal(平面法线)
view direction(观察方向)
light direction(光照方向)
surface parameters(表面参数):例如颜色,亮度
此处所有向量为单位向量
shading!=shadow!!!!
为什么同一束光打到一个点,角度不同亮度就不同呢?
我们假设光离散成六根光线,看得出来物体法线和光的夹角越小,物体表面受到的光就越少(看我们这里第一幅图,物体表面法线和光平行)
更科学的理解:光是一种能量,所以考虑收到的能量有多少
接下来是一个我并不想关心也不想记住推导过程的公式(请返回原视频56分处)
若光源强度(能量)为I,则距离光源距离r的光强度(能量)等于I/r2
我们可以算出光源到点的距离r,就可以求出点位置有多少能量,然后再和其余弦,漫反射系数,进行相乘。
点位置的能量:(I/r2)
余弦是图中光照方向和法线点乘:max(0,n·l)
(也就是图中的,加上一个0取max是因为我们讨论光的反射,若余弦小于0/角度为负数则没有任何物理意义)
定义漫反射系数:kd
(若kd=1,则表示这个点完全不吸收能量,若kd=0,emm你可以认为这个点是黑洞)
最后就能求出ld(这个点应该表现多少光)
我们看到公示里面没有涉及到观测方向,所以漫反射结果和观测方向没有关系
完成啦完成啦,4.16 19:00,今天是周五玩游戏去啦
7.Shading 1(Shading,pipeline,texture mapping)(着色,管线,纹理映射)
specular highlight in blinn-phong model(布林冯中的高光)
高光相:由于镜面反射光的方向和观测方向接近
半程向量h=取l和v的角平分线,再做归一化
此处h和n(半程向量和法线)接近相当于v和r(观测方向和反射光)接近
真实情况依然要考虑表面的吸收率,我们在此处省略
用h和n的情况比较多,因为更好计算(其实我也不知道为什么更好算)
为什么要有指数p?
因为单单一个余弦图像的容忍度很大,用它生成的高光也很大
在Blinn-Phong model中p一般采用100到200
展示出来就是这样哒
ks表示了其亮度,p越大高光越小
ambient lighting in Blinn-Phong model(布林冯中的环境光)
环境光不讲究光从哪进来,同时从哪看也没有关系,和法线也没有关系
所以近似认为环境光是一个常数(以上都是大胆的假设,因为深究特别难)
总结一下Blinn-Phong model就是这样啦
布林冯是经验模型,并不基于真实物理光照哦
Shading Frequencies(着色频率)
统一模型着色频率不相同会导致什么?
逐三角形着色:三角形表面就是一个平面,把三角形的法线求出(对边做一个叉积)
这种也叫Flat Shading
逐顶点着色:每个顶点做一次着色(先不管顶点的法线怎么求),三个顶点组成三角形,其内部的颜色用插值获取
这种也叫Gouraud Shading
逐像素着色:对前文提到的三角形内的每个像素都插值出独特的法线方向,对每个像素进行一次着色,得到相对比较好的结果
这种也叫Phong Shading(这和前面那个布林冯不一样!虽然都是冯发明的,但这个是着色频率)
哪一种更好呢?并无绝对
几何足够复杂时,使用相对简单的着色模型也能得到不错的结果
(不是很能理解的话具体看图,每一行都是同一种几何形体使用不同的着色模型,我们发现第三种几何形体已经很复杂了,但使用三种方法都相差无几,但使用冯着色模型会造成更大开销)
历史遗留问题:我如何获得逐顶点和逐像素的法线
逐顶点如下:
求一个顶点的法线,取和他关联的平面的法线的平均值(好办法)
逐像素如下:
求得顶点的法线后,用重心坐标求出其中的法线过渡(记得归一化哦)
Graphics(Real-time Rendering)Pipeline(图形管线/实时渲染管线)
给我着色模型!给我三维模型!给我光照条件!就能得到渲染结果!
管线:从一个真实场景到演示一份图像,中间发生了什么?
- 输入空间中的点
- 将三维空间中的点投影到屏幕上
- 这些点形成三角形
- 光栅化(将三角形画在屏幕上)
- 三角形离散成各个像素
- 对每个像素进行着色
- 输出图像
现代GPU允许我们自己编程控制像素和顶点如何进行着色,这个过程我们称为shader
shader是每个顶点或每个像素通用的执行方法,只需要管每个顶点每个像素如何运作,而不是写循环。
如果我们写的是顶点的操作,则这个shader被称为vertex shader(顶点着色器)
如果我们写的是像素的操作,则这个shader被称为fragment/pixel shader(片段/像素着色器)
此处使用的GLSL是OpenGL的着色语言,图片中是像素着色器的一个小程序
接下来闫老师讲了一堆巴拉巴拉的不好总结
硬要总结一下的话就是“非常简单”(圈起来要考的)
讲了一堆硬件相关所以这里就先略过了
texture mapping(纹理映射)
引入纹理映射的基本思路:希望在物体不同位置定义不同的属性(漫反射系数或其他)
先做一个声明:任何三维物体的表面都是二维的
所以texture(纹理)是什么:texture就是一张(image)图
将这张图蒙在物体上(图上的点和物体上的点一一对应),这个过程就叫纹理映射
(闫老师能不能用点阳间的图,san值狂掉)
怎么把空间中的三角形映射到平面上?
- 需要艺术家(美工)做出一个模型,然后展开贴在物体上,对美工来说这是一个繁重的过程
- 给一个模型,我们将其展开为一个平面,希望三角形尽量少扭曲,这个过程很难,会是以后重要的研究方向(参数化)
我们在纹理上定义一个坐标系(u,v)(uv的范围都在0到1)
这样就可以把任意物体的三角形映射到纹理上显示出来
接下来我们想知道:
如果知道三角形对应顶点的uv,那么如何知道三角形内部对应每个点的uv
下节课会着重介绍插值(通过三角形的三个顶点属性,在三角形内部做一个平滑的过渡)
本文于4.20 17:25完成,终于明白什么是管线啦!(豁然开朗好开心)
shading3(texture mapping)
barycentric coordinate(interpolation across triangles)(用重心坐标在三角形内做插值)
为什么我们要做插值?
很多操作在顶点才能操作,希望能在内部得到一个平滑过渡的值
我们能插值什么内容?
纹理的坐标,颜色,法线向量
我们怎么做插值
利用重心坐标!
the definition(定义)
重心坐标定义在一个三角形内,换一个三角形就换一套重心坐标
在三角形ABC形成的平面内的任意一点,都可以表示成为ABC坐标的线性组合(不需要再使用xy坐标系),其中三个系数αβγ之和为1(如果不为1那就不在三角形所在的平面内了)。这αβγ组成的坐标就是重心坐标。但其实我们只需要知道其中两个数,就能求得第三个数。
若这个点在三角形内,那么αβγ必须都为非负数。
所以A点自己的重心坐标就是(1,0,0)啦
这里α的取值就是他对应三角形的面积除以三角形的总面积,其他的也一样。
我们可以很快求得三角形的重心的重心坐标(Soga叫重心坐标原来如此)
简化一下(对计算机来说确实是简化了,但对我不是)就可以求得α和β具体的值(其实就是做叉乘操作)
这个表达式我们没有必要去记忆,因为很好算,我们只需要我们能得到这个重心坐标就行
how to use barycentric coordinate(使用重心坐标)
假设三个点有三个属性(位置,颜色,纹理坐标,法线,深度),就可以用重心坐标把所需要的点插值出来。
如果将空间中的三角形投影到屏幕,那么前后重心坐标的插值结果将不同(已经不是同一个三角形了)
所以我们如果拿到一个三维的三角形,那么我们就应该取他们三维空间中的坐标,然后算这个三角形的插值,然后再放进去,而不能在投影后的三角形中做
applying textures(应用纹理)
对应屏幕上任意一个采样点,我们都能算出这个点插值出来的uv(对应在三角形的位置),在纹理上查询这个点的颜色,我们可以认为纹理定义的就是这个点的漫反射系数(布林冯模型的kd)
,相当于就是把这张图贴在了物体上,同时这个物体也有冯shading 带来的高光。
texture magnification(纹理太小的情况)
假设我们要刷一堵4k的墙,但我们的纹理只有256x256,纹理分辨率太小了怎么办
bilinear interpolation(双线性插值)
图中黑点为纹理,红点为我们的像素,如图所示像素并不是整数
我们找到这四个点,把红点(在四个像素内的坐标范围是0到1)线性插值出来
具体步骤:
把水平的这两对点插值出来,然后得到两个点,再把这两个点进行竖直方向的插值
虽然获得了不错的效果,但还不够完美
bicubic(双三次插值)
取周围十六个点,做三次插值(不是线性的)
所以好质量的东西往往伴随着更大的开销不是吗
texture magnification(纹理太大的情况)
纹理太大的话
远处摩尔纹近处锯齿,走样啦!
那我们可以直接做抗锯齿吗?
当然可以,但是开销不小。
那我们不采样了!那就不会走样了!
mipmap:
允许做range query(范围查询)查到一个区域里面的平均值,算的快,但是近似值,且要求区域是正方形
拿到材质时先把对应的mipmap生成
多出这些图花费了1/3的空间,这样很棒不是吗
(这块有点听不明白)
我们知道一个点映射到纹理上是一块区域,那么我们怎么知道究竟是什么样的区域呢
假设这个像素有边上两个邻居,我们计算一下他到另外两个邻居的长度,然后取较长的那个构造一个正方形,然后这个正方形就是所求的近似区域。(但这不是重点,重点是这个正方形的查询怎么做)
假设原图为4x4,则我们在第二层做mipmap最终会得到一个像素,这个像素就是我们所需要的这个区域的平均值。
所以如图所示,离我们很近这里我们能看到很多细节,所以我们在比较低的层做查询。
离我们特别远的地方,一个像素覆盖的区域就特别大,所以我们要在特别高的层查询,那个时候一个区域才近似是一个像素。
然后我们发现这里的层是离散的,我们算不出1.8层那样的层是什么样的,最终成品说不定我们会看到一条缝,那我们怎么做呢?
插值就行了!
triinear interpolation(三线性插值)
先找第一层,再找第二层,把这两层做双线性插值,把这两层对应的插值算出来,然后再层与层之间再做一次插值
因为本身开销很小,所以游戏画面中很喜欢使用这个技术
mipmap limitation
mipmap并不是在所有情况都能解决问题的
在远处会出现overblur(过分模糊)
因为三线性插值只能查询正方形区域的平均值
所以又有一个办法可以改进三线性插值带来的问题
anisotropic filtering(各向异性过滤)
(在游戏中大量采用)(需要三倍开销)
能解决一部分问题,得到更准确的结果,但对于图中这种斜着的矩形还是很难计算。
好晚才写完,今天效率超级低4.22 21:45
8.Geometry (introduction)(几何)
applications of texture(纹理的应用)
纹理本身是一张图,我们可以把纹理理解成线代GPU上内存上的一份数据,我们可以对它做快速的点查询和范围查询
可以做mipmap
做environment map(环境光)
我们假设有一个球是镜面的,那么他储存的内容就是环境光的内容,我们把这个球平面展开就组成了spherical environment map
但显而易见的造成了扭曲
解决方案是采用cube map,把这个球外边构造一个包围盒,然后把内容储存到球切割开的六个面。
效果就是这样啦
两种方法本质都是一样的,都是为了描述不同方向的光照信息。
texture can affect shading
运用凹凸贴图就可以营造出球面凹凸不平的感觉,而不用使用更多三角形去构造
相当于是不把几何形体变复杂的情况下,通过复杂的材质来定义相对高度,通过影响法线的变化从而影响着色结果
位移贴图(进化版)
位移贴图真的移动了顶点
虽然这样效果更好,但是也有相应的代价,构造的三角形得足够细,细到顶点间隔比纹理频率还要高,这样才能跟得上纹理的变化速度。
3D procedural noise + solid modeling
用噪声算法算出大理石的纹理,或者是山脉的脉络之类
provide precomputed shading
提供提前预计算的环境光遮蔽
volume rendering
体积渲染
Geometry
复杂几何存在的问题:
- 不便存储
- 不便渲染
对几何做一个归类:
implicit geometry(隐式几何)
不给实际的点的位置,通过关系来表示位置,只要找出满足关系f(x,y,z)=0的所有点就能将几何表示出来。例如满足x2+y2+z2=1的话就能构造出三维的球面。
优点:判定一个点和几何的相对位置很容易,(内,外,重合)
缺点:从表达式很难看出几何的形状(不直观)
explicit geometry(显式几何)
直接给出或通过参数映射(例如f(u,v)=xxxx,和隐式的不一样!)给出点的位置,以此来构造曲面。
优点:每个参数都写的清清楚楚
缺点:想判断一个点和几何的相对位置比较难(内,外,重合)
根据问题的不同需要来选择隐式或显式
CSG:通过结合隐性几何进行布尔运算,将简单几何变成复杂几何
距离函数:空间中一个点到需要的几何形体的距离(可以是正的也可以是负的)
因为距离函数f(x)=0的时候,得到的就是物体表面
应用距离函数:A和B如果制作一个简单blend,就会得到左边黑中间灰右边白
而我们将A和B各自做一个有向距离函数(scene distance function),然后将SDF(A)和SDF(B)做一个blend,得到的就是左边黑右边白的结果(我们需要的)
所以两个几何最后得到这种结果
水平集的原理和距离函数有点类似,应用在地理上是等高线(在不同位置有相同的值)
fractals(分形)也叫自相似,和计算机中的递归是一个道理
(简单来说就是套娃)
本文于4.27 13:35完成
接下来要换分段更新啦,不然加载太慢了读着也不方便
更新中~~