相关链接

几何变换应用(几何变换的详细计算步骤)

Model Tranform(模型变换)

在空间中摆放需要相机,模型等操作,放置模型。

View Tranform(视图变换)

原理:将场景相机移动到坐标原点,并朝向-z方向,其他物体顶点于相机相对位置保持一致,即乘上相同的变换矩阵
移动相机到坐标原点需要平移+旋转矩阵,平移矩阵可以直接通过坐标得出
平移矩阵
旋转矩阵计算步骤:

  1. 需要将原y轴旋转至(0,1,0)方向,将原z轴旋转至(0,0,-1)方向,将原x轴旋转至(1,0,0)方向

  2. 先设当前相机坐标轴表示为[X:g×t,Y:t,Z:g] (注:g×t,g叉乘t),原点规范的坐标轴为X(1,0,0),Y(0,1,0),Z(0,0,1)。从当前旋转至规范坐标轴较为困难,但从规范坐标轴旋转至当前坐标轴非常简单,
    求y轴旋转:M1*(0,1,0,1)=( X(t),Y(t),Z(t),1 )
    求z轴旋转:M2*(0,0,-1,1)=( X(g),Y(g),Z(g),1 ) 注:朝向-z轴
    求x轴旋转:M3*(1,0,0,1)=( X(gxt),Y(gxt),Z(gxt),1 )
    M1+M2+M3最终计算的旋转矩阵如下:
    规范朝向 旋转至 相机朝向

  3. 得到的旋转矩阵为:规范朝向-相机当前朝向的矩阵,我们需要求出:相机当前朝向-规范朝向的矩阵,这相当于求矩阵的逆
    需要掌握前提条件:旋转矩阵满足一个原则,矩阵的转置=矩阵的逆。 通过转置这个矩阵得到最终旋转矩阵如下:
    相机朝向 旋转至 规范朝向

  4. 旋转矩阵*平移矩阵即得到最终的MV矩阵

Projection Tranform(投影变换)

投影分为:正交投影(Orthographic Projection),透视投影(Perspective Projection)。
正交投影 透视投影

正交投影计算过程

最终目的:将可视范围移动到x:[-1,1],y:[-1,1],z:[-1,1]的原点Cube中
正交投影过程

  1. 通过可视范围的中心点得到平移矩阵
  2. 由于正交投影:其可是范围为长方体,只需要通过缩放矩阵,将大小压缩到标准大小即可
    正交投影过程

透视投影计算过程

由于透视投影的可视范围是一个锥形,为了计算压缩成长方体,再进行正交投影,原理如下图所示,将Frustum压缩成Cuboid
透视投影过程
虽然只是压缩,但其中的计算过程比前面的都要复杂很多。

  1. 拆分其变换过程,如下,近平面于原平面形成一个相似三角形
    透视投影过程
    得到变换后的x轴以及y轴值:y’ = y * n/z; x’ = x * n/z; 而z轴暂时还不知道,得到如下变换后的坐标
    透视投影过程

  2. 由第1部分求得坐标可以推算出变换矩阵的部分值:M * (x,y,z,1) = (nx,ny,unknown,z), M如下:
    透视投影过程

  3. 已知条件:
    (1)所有近平面的点压缩后都保持不变
    (2)远平面的点压缩z值不变
    分别将其中的坐标带入矩阵计算:
    (1) 近平面点带入: M * (x,y,n,1) = (nx,ny,n * n,n),注释:变换后的z = n * n 于x,y不存在任何关系,因此可以得到(0,0,A,B)
    透视投影过程
    (2) 远平面点带入: M * (x,y,f,1) = (unknown,unknown,f*f,f)
    透视投影过程
    最终得到两条方程式:
    (1)An + B = n * n
    (2)Af + B = f * f
    求解得:A = n + f; B = -n * f

最终其压缩矩阵如下图:
透视投影过程

Viewport Tranform(视口变换)

原理:先定义好平面的height和width,即平面的像素比,屏幕坐标空间中左下角为(0,0),再经过MVP变换后,当前图片所在空间为[x:[-1,1],y:[-1,1]],需要将其大小变大,再平移至左下角到(0,0)点

视口变换

光栅化阶段

经过视口变换后,所有图形信息都存在屏幕空间,这时需要考虑怎么将其显示出来,这个显示的过程就是光栅化。

三角形遍历

为什么使用的是三角形?

  1. 三角形是最基本的图形,
  2. 一个三角形一定在一个平面上
  3. 可以很方便计算一个点在三角形的内外,使用叉乘

三角形遍历原理:遍历每个可能的像素的中心点是否在三角形内部
但是通过这种方式遍历后,就会出现一个问题:走样(Aliasing),或称为锯齿
三角形遍历

反走样(抗锯齿) (Anti-aliasing)

走样是怎么形成的?根本原因是采样的频率跟不上变化的频率

  1. 频域(Frequency Domain)
  • 正弦/余弦频谱
    正弦/余弦频率

  • 傅里叶变换(Fourier Transform)
    将非常多按照公式计算的频谱相加最终会越来越趋向于方形的频谱
    傅里叶变换
    (1) 通过傅里叶变换可以将图片从 空间域转换到频域
    (2) 通过逆傅里叶变换可以将图片从 频域转换到空间域
    傅里叶变换

  • 频谱采样的一种特殊情况,如下图:对于两个不同频谱采样结果相同造成了走样
    频谱采样

  1. 滤波器(Filter)
    滤波器是针对空间域(Spatial Domain)中的图片进行卷积计算,但滤波器实际可以表示为对频域的操作。
    如下图傅里叶变换结果:低频越趋向于白色,高频趋向于黑色,低频普遍存在于图片中心部分。
    傅里叶变换
  • 低通滤波器:低频通过,实际对频域进行低通滤波,可以达到模糊图片的效果
    实际原理就是将频域图片的高频部分全部过滤,只有低频通过。
    低通滤波

  • 高通滤波器:高频通过,可以达到描边的效果(高频表示图片中变化差异很大的部分,相当于是描边)
    高通滤波

  1. 卷积
    如以3x3的box对图片进行卷积,每个像素的颜色至就相当于当前像素为中心周围9个像素点按照卷积核的比例相加。
    在空间域对图片进行卷积,相当于在频域中的两个图片的乘积,如下图验证了这一点:
    卷积

  2. 实现反走样:在三角形遍历之前先进行模糊操作,再进行三角形遍历,每个像素保持模糊后的颜色值,模糊就是使用低通滤波对像素进行卷积操作
    反走样

深度缓存(Z/Depth Buffer)

在三角形遍历后,我们知道了所有需要渲染的三角形,现在需要考虑将它们画出来,这时需要考虑绘制三角形的先后顺序,正确的先后顺序以保证最终显示的图形是我们想要的图形,最初有一种算法油画家算法,从远到近依次绘制所有三角形,但是对于多个三角形互相穿插的问题无法得到解决,ZBuffer可以很好的规避渲染顺序问题,通过对每一个像素维护一个深度值,绘制三角形不需要考虑顺序,每次绘制时只考虑深度值是否小于缓存值,小于则绘制,大于则剔除,绘制时间复杂度只有O(N)。
深度缓存

着色(Shading)

渲染管线(Rendering pipeline)

实时渲染管线的整体顺序:应用阶段->几何阶段->光栅化阶段

  • 应用阶段:
  • 几何阶段:
  • 光栅化阶段:
    渲染管线

标准着色(Lambert + Ambient + Specular)

  • 漫反射(Lambert)
    渲染管线
  • 高光反射(Specular)
    Phone和Blinn-Phone
    Phone
    Blinn-Phone
  • 环境光(Ambient)
    标准着色

重心坐标(Barycentric Coordinates)

通过三角形的重心坐标可以做到由三角形的三个顶点插值到重心坐标处的值,这个值包括可以包括任何信息(法线,颜色等)
同时可以扩展:三角形内的顶点 Q = aP1 + bP2 + c*P3, 且 a+b+c = 1 && a>0 && b>0 && c>0
重心坐标

纹理映射(Texture Mapping)

通过使用一张纹理图片定义不同像素处的不同值。这些值可以用来做:颜色,高度图,噪声图等等。
将纹理贴图的长宽定义成u,v,范围[0,1]区间方便计算。

纹理贴图

首先定义:一个像素在纹理中的名字叫做纹素(texel),且一个像素内只存在同样的颜色信息
下面介绍纹理贴图在使用过程中遇到的问题以及如何优化

当纹理图片太小

  1. 问题描述:如果需要渲染一个在屏幕上为200x200像素的网格而纹理只有100x100像素大小,这时为了达到完整的渲染会将纹理图片拉伸至200x200像素大小,拉伸后一个纹素相当于原来的4倍,然后网格通过uv读取,可以发现网格中的采样4个像素才相当于原先纹理的1个像素,这导致这些像素使用了相同的颜色信息,因此会出现模糊。

解决方法:双线性插值(Bilinear Interpolation),双立方插值(Bicubic Interpolation)

  1. 双线性插值(Bilinear Interpolation)
    核心思路:当采样一个点时,拿到其周围4个最近的采样坐标,拿到这4个采样像素的值,插值出当前采样点的颜色信息。
    双线性插值
    双线性插值

  2. 双立方插值(Bicubic Interpolation)
    思路于双线性插值一样,只是采样点从4个增加到16个

当纹理图片太小

当纹理图片太大

  1. 问题描述:如果需要渲染一个三角形实际可能很大,但其在屏幕上占据像素为1x1px,而其纹理图片大小100x100px,进行普通采样只会获得其采样点对于的颜色,并不是我们想要的颜色,如下图可以看出摩尔纹以及锯齿(走样)问题。
    当纹理图片太大

  2. 在之前学习过走样形成的根本原因:采样频率低于变化频率,遇到这个问题当然可以通过超采样来避免,将1像素进行512个采样点采样,确实可以避免走样问题,采样结果如下,但是其消耗太大了:
    超采样

  3. 为什么普通点采样会出现上面的走样问题:越远的三角面在屏幕中占据的像素越少,而对于一个像素在纹理中占的范围就越大
    这时通过点采样出来的信息一定是不满足的,采样范围的平均值反而更适合,那么怎么快速采样范围的平均值,一个新的概念使用MipMap。
    采样范围

  4. MipMap

  • MipMap允许做快速,近似的正方形的范围查询。

  • MipMap是预先生成的,从原图比例开始,每次长宽变小为原图的一半,直到像素为1x1px。

  • MipMap只多使用了原图的1/3的内存空间。
    MipMap

  • 计算当前在MipMap中采样第几层的纹理数据
    Compute MipMap

  • 三线性插值(Trilinear Interpolation)
    在MipMap中如果得到层级在2.5层怎么正确获取颜色值?
    同时拿到第2,3层,分别进行双线性插值,将其结果再进行一次插值。
    Trilinear Interpolation

  • MipMap处理后的效果图,出现了一个新的问题,远处过度模糊(OverBlur)
    Trilinear Interpolation

  1. 各向异性过滤(Anisotropic Filtering)
    使用更多的内存保存更多分辨率的图片,MipMap只保存正方形大小,而各项异性过滤需要额外保存长方形的图片。
    各项异性过滤
    各项异性过滤
    效果图:
    各项异性过滤

环境贴图(Environment Map)/立方体贴图(Cube Map)

  • 环境贴图:将环境反射的颜色信息存储在一个球上
    法线贴图
  • 立方体贴图:将环境反射信息存储在立方体上
    法线贴图

法线贴图/凹凸贴图(Bump Mapping)

  • 作用于顶点法线上,使得表面看起来有一定凹凸感

  • 作用原理:相当于将法线贴图的信息当作顶点的偏移值,就会造成一些顶点凹,一些凸,但是并不实际作用于顶点,只是用偏移后的顶点坐标再进行法线计算,就可以得到新的法线,将这个法线用于光照即得到新的视觉效果。

  • 二维法线计算过程:如计算n,取贴图当前坐标值以及偏移1的值的差求出dp = c * [h(p+1) - h(p)],(注:h(p),凹凸贴图定义的是切线,通过贴图拿到值),逆时针旋转90度求得n,如图
    法线贴图

  • 三维法线计算过程: 注:其h(u),也是通过贴图直接拿到值,h:纹理高度,w:纹理宽度
    (1) dp/du = c1 * [h(u+1/w,v) - h(u,v)]
    (2) dp/dv = c2 * [h(u,v+1/h) - h(u,v)]
    (3) 最终:n = (-dp/du, -dp/dv, 1)

  • 位移法线:将贴图影响的偏移应用到顶点上,其效果更好
    法线贴图

阴影 (Shadow)

  • 相机可以看到,而光线看不到即有阴影,如下图:相机看到的深度与光线位置看到的深度不同则说明光线被阻挡,即该点产生阴影。
    阴影

  • 阴影又分为硬阴影,软阴影,硬阴影是由于将光线源当成点光源处理,而软阴影是将光源当成范围光处理。
    阴影

几何(Geometry)

什么是几何?几何就是拥有某种空间结构的形状。

几何模型

  • 几何模型的隐式表达式,通过函数来表示一个几何模型。
    几何模型
  • 通过函数可以表达一些基本的几何模型如立方体,球,圆环,圆等规则的模型,但对于非常复杂的模型,使用隐式表达式几乎不现实,且不直观,因此需要显示表达来表示各种复杂模型:(三角面模型)Triangle Mesh,(贝塞尔曲面)Bezier surfaces,(点云)point clouds,(曲面细分)subdivision surfaces等等方式来表示复杂模型。

贝塞尔曲线 (Bézier Curves)

  • 由多个点共同决定的曲线,关于贝塞尔曲线的计算,如下图黑点左到右a,b,c,d,计算过程。
    贝塞尔曲线
  • 由于通过超多个点决定贝塞尔曲线,会由于点越来越多,越难控制,因此在实际使用时,通常使用分段式的贝塞尔曲线,将一条分成多条,方便控制。
    贝塞尔曲线

贝塞尔曲面 (Bézier Surfaces)

  • 由多个点共同决定的曲面,计算过程描述,如图4x4的曲面,对4条边做贝塞尔曲线,取4条边的值再做一次贝塞尔曲线,对所有uv做同样操作就形成了贝塞尔曲面。
    贝塞尔曲面

模型 (Mesh)

  • 一个Mesh由很多面组成
  • 一个模型文件.obj中存储的数据内容包括:顶点,顶点切线,顶点法线,三角面(一组顶点链接的顺序并组成面)
    模型

模型优化方法

模型细分(Mesh subdivision)

目的:达到更精细的显示效果,细分后模型面会增多,顶点数量也会增多
模型细分

Loop Subdivision (只适用于三角面细分)

思路:将1个三角形等分成4个三角形
Loop Subdivision

Catmull-Clark Subdivision (通常模型的细分,将多边形统一细分成四边形)

思路:将所有不是四边形的面都转换成四边形,再将1个四边形分成4个四边形
Catmull-Clark Subdivision

模型简化(Mesh simplification)

目的:减少渲染计算压力,避免不必要的计算
模型简化

模型规则化(Mesh regularization)

目的:提高模型质量,将所有三角面都转成等边三角形
模型规则化

光线追踪(Ray Tracing)

Whitted-Style Ray Tracing

如何检测射线命中三角面

加速射线检测

如何进行射线检测

如何进行场景分块

Path Tracing

材质(Materials and Appearances)

动画(Animation)

参考

GAMES101-现代计算机图形学入门-闫令琪