计算机图形学【GAMES-101】4、纹理映射(重心坐标插值、透视投影矫正、双线性插值MipMap、环境光遮蔽AO)

快速跳转:
1、矩阵变换原理Transform(旋转、位移、缩放、正交投影、透视投影)
2、光栅化(反走样、傅里叶变换、卷积)
3、着色计算(深度缓存、着色模型、着色频率)
4、纹理映射(重心坐标插值、透视投影矫正、双线性插值MipMap、环境光遮蔽AO)
5、几何(距离函数SDF、点云、贝塞尔曲线、曲面细分、曲面简化)
6、阴影映射(Shadow Mapping)
7、光线追踪原理(线面求交、预处理光追加速)
8、辐射度量学与光线追踪
9、蒙特卡洛路径追踪(Path Tracing)(光源采样)
10、材质(BRDF)(折射、菲涅尔项、微表面模型、各向异性材质)
11、渲染前沿技术介绍(双向路径追踪BDPT、MLT、光子映射、实时辐射度、外观建模)
12、相机(视场、曝光、光圈(F-Stop)、薄棱镜近似、CoC、景深)
13、光场、颜色与感知
14、动画(物理模拟、质点弹簧系统、粒子系统、运动学、动作捕捉、欧拉方法)


1 Texture Mapping

  • 如图,球上的点共用同一个着色模型(着色计算方式),但不同位置有不同颜色,什么情况?
    就漫反射这一项来看,其实是球上不同点的漫反射系数kd不一样,所以计算出来每个点的漫反射项Ld是不同的。

在这里插入图片描述

  • 如何快捷方便的定义球上不同位置的对应不同属性呢?
    定义:任何三维物体的表面可以展开成一个平面,
    纹理:就是一张有弹性的图,可以放大、缩小、拉伸
    纹理映射:把纹理图盖在三维物体表面
    从而我们可以得到三维物体上任何一个点,与纹理图上的点是一一对应的。
  • 下图就是一个球映射一张世界地图,最终在屏幕空间中输出结果是一个地球仪
    在这里插入图片描述
  • 再比如下面这个孤儿图
    运用布林冯模型计算着色后输出到屏幕和映射一张纹理图后输出到屏幕的差别
    模型每个三角形面都对应到纹理上的某个三角形
    在这里插入图片描述
  • 学习纹理后,顶点存放的就不只是坐标信息了,还要存放uv坐标
    继续上孤儿图,uv坐标就是纹理图上的每个点的坐标,范围是(0,0)~(1,1)
    顶点内存放了uv坐标就知道该顶点应该映射到纹理的哪个点,然后三角形的三个顶点都有各自对应的纹理图上的uv坐标后,三角形内部的面应该对应到哪里就能够知道了,插值呗
    在这里插入图片描述
    有一类纹理是循环使用的,比如以下这个建筑,一张纹理图被贴了很多很多次,右图的颜色代表纹理坐标大小,深色接近1,浅色接近0,可以明显看到纹理坐标在相邻两张纹理图的连接处会突变,但是实际图像中却看不出突变,因为纹理被做成了左右/上下边界完美重复的类型
    在这里插入图片描述在这里插入图片描述

2 Barycentric Coordinates(重心坐标)

这里只简单介绍,具体重心坐标插值公式推导,以及透视投影矫正部分见文章
【重心坐标插值、透视投影矫正】超详细推导

  • 已知三角形三个顶点都存放了一个uv坐标,如何求出三角形内部的点的uv坐标呢?
    重心坐标插值
    重心坐标不光可以插值uv坐标,还能插值颜色、法线、世界坐标等任何属性
    如phong shading就是插值法线,得出三角形内部每个像素的法线后,再单独对每个像素计算着色。

2.1 重心坐标概念

  • 在三角形坐标系中
    三角形任何一个点(包括顶点)都可以表示成三个顶点的线性组合,注意顶点ABC是坐标
    满足以下关系式的三个系数(α,β,γ)就是该点的重心坐标
    还有一个限制条件是这三个系数必须非负,否则就在三角形外了
  • 简而言之,就是三角形内部一个点(x,y)在重心坐标下的表示就是(α,β,γ)
    在这里插入图片描述
  • 其中三个顶点自己的重心坐标分别是
    A:(1,0,0)
    B:(0,1,0)
    C:(0,0,1)

2.2 重心坐标计算方式

  • (α,β,γ)具体怎么算出来呢?
    A的系数α:其对应的三角形面积AA(红色部分)占总面积的比值
    B的系数β:其对应的三角形面积AB(黄色部分)占总面积的比值
    C的系数γ:其对应的三角形面积AC(蓝色部分)占总面积的比值
    在这里插入图片描述
  • 也可以直接用以下公式计算

    β

    =

    (

    y

    y

    A

    )

    (

    x

    C

    x

    A

    )

    (

    x

    x

    A

    )

    (

    y

    C

    y

    A

    )

    (

    y

    B

    y

    A

    )

    (

    x

    C

    x

    A

    )

    (

    x

    B

    x

    A

    )

    (

    y

    C

    y

    A

    )

    γ

    =

    (

    y

    y

    A

    )

    (

    x

    B

    x

    A

    )

    (

    x

    x

    A

    )

    (

    y

    B

    y

    A

    )

    (

    y

    C

    y

    A

    )

    (

    x

    B

    x

    A

    )

    (

    x

    C

    x

    A

    )

    (

    y

    B

    y

    A

    )

    α

    =

    1

    β

    γ
                                                               

    \\color{red}\\large β=\\frac{ (y- y_{\\tiny A})(x_{\\tiny C} – x_{\\tiny A})-(x – x_{\\tiny A})(y_{\\tiny C} – y_{\\tiny A}) }{(y_{\\tiny B} – y_{\\tiny A})(x_{\\tiny C} – x_{\\tiny A})-(x_{\\tiny B} – x_{\\tiny A})(y_{\\tiny C} – y_{\\tiny A})}\\\\ \\: \\\\ \\large γ=\\frac{ (y- y_{\\tiny A})(x_{\\tiny B} – x_{\\tiny A})-(x – x_{\\tiny A})(y_{\\tiny B} – y_{\\tiny A}) }{(y_{\\tiny C} – y_{\\tiny A})(x_{\\tiny B} – x_{\\tiny A})-(x_{\\tiny C} – x_{\\tiny A})(y_{\\tiny B} – y_{\\tiny A})}\\\\ \\: \\\\ α=1-β-γ\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:\\:

    β=(yByA)(xCxA)(xBxA)(yCyA)(yyA)(xCxA)(xxA)(yCyA)γ=(yCyA)(xBxA)(xCxA)(yByA)(yyA)(xBxA)(xxA)(yByA)α=1βγ
    其中目标点坐标(x,y),三角形三个顶点的坐标(xA,yA)(xB,yB)(xC,yC)

三角形的"重心"的重心坐标是多少?
在这里插入图片描述

2.3 重心坐标插值

  • 已知重心坐标的计算方法,怎么插值属性呢?
    算出来的重心坐标(α,β,γ),其实就相当于一个权重比
    直接把对应的VAVBVC换成uv坐标、颜色、法线、深度值、材质属性,V即所求
    在这里插入图片描述

  • 注意,重心插值要用三维空间的属性进行插值,再对应到二维空间中去。

  • 纹理映射的伪代码:
    在这里插入图片描述

3 纹理映射产生的问题

  • 我们要渲染的物体正面对着摄像机,刚好所占用的像素个数纹理大小相同,比如都是 256*256,则映射每个 pixel 到 texel 时,刚好就能得到整数的纹素。但是大多数情况下,物体不是正正好好对着摄像机;就算是正好对着摄像机,也可能出现纹理太小/太大,像素映射纹理纹素的时候映射不到整数位置。
  • 其实呢就是走样问题,后面会细说。

3.1 纹理太小

  • 纹理太小,则需要放大,从而产生纹理放大相关的问题
  • 比如一面墙渲染出来分辨率1024*1024,但是它对应的纹理图仅有256×256
    为了把纹理图应用到墙上,显然纹理需要放大,然后贴到墙上
    结果就是:我的墙可能会查到一些不是很正(不在纹素的中心)的值
  • 纹理元素texel是纹理图中的最小单位,查询位置歪了就不知道该点到底是个什么属性了
  • 对应歪了咋办?根据处理办法不同会产生以下效果
    在这里插入图片描述

3.1.1 Nearst

  • 直接四舍五入取最近的一个纹素作为映射结果
  • 注意下图中的一个方块可不是一个像素,而是n·n个像素,位置上接近的好几个像素(如4×4个像素)映射到同一个纹素,则这堆像素显示同一个颜色,所以这一块像素区域看起来就是一个大像素,出现严重锯齿感觉。
    在这里插入图片描述
    这样太丑了,所以还有后面两种方法

3.1.2 Bilinear Interpolation

从纹理图的角度来看映射不到整数的情况,屏幕上的一个像素映射到纹理图上的某个点(红点)
这个点是没有属性定义的,上个方法是把这个坐标直接使用最近的一个texel的信息,导致很附近多个像素都显示一样的颜色——明显锯齿
在这里插入图片描述

  • 双线性插值
    算出红点处的颜色应该是什么样的!
  • 操作步骤
    找到实际映射点(红点)附近的4个纹素点
    (1)水平上,用距离s,根据线性插值公式,很容易计算出u0和u1的属性
    (2)竖向上,用距离t,对u0和u1再做一次插值,即最终结果。
    在这里插入图片描述
  • 从而得到有一点模糊但是更平滑的图形。
    在这里插入图片描述

3.1.3 Bicubic Interpolation

  • 双三次插值算法
    也可以叫双立方插值
    跟双线性插值类似,但取的是周围16个texel
    不多说

3.2 纹理太大

  • 纹理过大,则需要把纹理变小后贴到屏幕上的物体覆盖的像素区域,纹理变小,那么texel就变密了啊,从而一个像素对应很多个texel,问题就来了,映射结果是随机选一个幸运纹素还是求平均呢?
  • 如下面这张图,左边是参考图(理想结果),右边是实际用按每个像素对纹理图进行映射的结果
    由于这个平面是平着放的,会有近大远小的效果,但不管近处远处,所有的点都会对应一个纹理坐标
    为啥近处产生了锯齿,远处则是摩尔纹?????
    在这里插入图片描述
  • 再看下面这张图
    底下的均匀方格就是纹理上一个个的texel,而蓝色点就是像素对应到纹理图上的点
    此图,从左至右对应分别是上图的由近到远。
  • 该平面近处投影到屏幕上,此时平面很大,纹理过小,距离相机近的点的像素映射到纹理上并不在整数texel上,处理办法在3.1中有介绍如果采用Nearst,就会产生锯齿
  • 该平面远处投影到屏幕上,由于很远,在屏幕上的范围就小,此时纹理还是原来那么大就相对过大了,怎么办?纹理缩小再映射(纹理缩小其实就相当于纹理不变,像素变大嘛 下图就这样的),远处平面的一个像素对应到纹理图上,覆盖了多个texel。
    在这里插入图片描述
  • 解决办法1: 反走样技术嘛,增加采样点个数
    如下图每个像素不再是只采样中心点,增加到512个点,采样512次最后再对采样结果求平均。
    效果不错,但是太昂贵!
    在这里插入图片描述
  • 解决办法2: MipMap
    之前的,一个像素对应一个纹素,或者纹理过大一个像素对应不到一个纹素,对应歪了,我们采用的方式是取最近纹素或者插值求出该对应点的颜色属性,这叫点查询
    而MipMap就是范围查询的算法代表了

3.2.1 MipMap

纹理图上任意一个区域,我要很快速的得到这个区域的颜色平均值是多少这就是MipMap的意义。
MipMap的特点:范围查询特别快、数值不准、必须是方形查询
MipMap:就是用一张图生成一系列图

  • MipMap分层
    原始图为0层,层数越高分辨率越低。分辨率越低,其实图片的尺寸是会变小的(比如1层应该是0层的4分之一),但是为了看得清楚,还是保持原来大小。
    在这里插入图片描述
    这么多层的额外存储量只有1/3。
  • 选择哪一层MipMap作为我们要使用的那一张纹理呢?
    (1)先计算纹理映射到0层覆盖区域大小
    –目标像素和周围4个像素,都映射到纹理图上,原本一个像素大小就是1*1嘛,这个距离1也就是相邻两个像素之间的距离,对应到纹理图上之后呢,两个相邻的位置之间的距离L就是我们目标像素的覆盖区域的边长,那么L怎么求
    在这里插入图片描述
    这个公式来求,具体怎么推导的我也不知道反正就这么求
    在这里插入图片描述
    完事之后呢L就是该像素在纹理图上的覆盖区域的边长了
    然后近似的就是下面这块区域了。
    在这里插入图片描述
  • 然后计算应该选择MipMap哪一层来查询
    如果区域大小为1×1,不就意味着1个像素映射过去刚好是1像素大小的区域,直接在0层查询。
    如果区域大小为4×4,显然这个区域会在1层上变成2×2,在2层上会变成1×1,则应该在2层查询。
    以此类推可以得到公式
    D = log2L
  • 问题又来了,D算出来如果是0.8层呢?
    其实很容易,三线性插值即可
    先用双线性插值分别算出0层对应的值x1,1层的值x2,再纵向的做一次插值lerp(0.8,x1,x2)即可
    在这里插入图片描述
  • 最后做个对比
    在这里插入图片描述在这里插入图片描述
  • 采用MipMap方法,发现远处糊了,为啥?
    在这里插入图片描述
    问题出在,mipmap只能做正方形的查询,像下面这种角度,有些一个像素覆盖在纹理的区域并不是一个近似方形,有可能是个长条形,而这种情况取方形区域内的平均值显然不对的
    在这里插入图片描述

3.2.2 各向异性过滤

MipMap分层,只做了主对角线的图,各向异性又多了很多图,解决了竖向和横向的长方形的查询,但是仍然解决不了斜着的长方形的查询问题,但是依然可以提升很多了,但存储空间是原来的3倍
在这里插入图片描述
各向异性只要显存足够,就问题不大,消耗的是存储空间,不是运算性能

4 纹理的应用

纹理不仅仅是理解成一张图像,它也是内存中的一块区域存放的数据。因此纹理可以表示的东西就太多了,你可以用纹理表示法线、粗糙度、位移、光照等等一系列的属性。

4.1 环境贴图/环境光照

  • 用纹理记录来自周围环境的光线信息,用环境光渲染一个物体,这个物体就接收来自四面八方的光并且反射,如下图最后一张,它反射出了来自周围环境射到物体上该点的光
  • 环境光照只记录光照的方向信息,不记录位置信息,即认为光源(并非真的光源,只是间接光源,反射的光源或者别的间接光源的光线)在无限远处,例如一个小屋子,环境光照贴图记录的就是这个屋子里各种环境(窗户、门、家具)射过来的光,但是不管目标物体在屋子里怎么移动,光照贴图都是不变的,因为记录的只有光照方向,贴到物体上面后,具体的一个点的光照方向就确定了,一直是那个方向。

在这里插入图片描述

  • 环境光照贴图怎么制作?

4.1.1 Spherical Environment Map

  • 假设有一个镜面球,这个球就会反射来自环境的各种直接/间接光,然后把这个球面展开就成了环境光照的贴图了
    在这里插入图片描述
  • 这样直接从球面展开会有一个问题"顶部和底部容易扭曲"
    在这里插入图片描述
  • 缓解办法,立方体映射

4.1.2 Cube Map

  • 还是用一个镜面的球记录周围环境的光,但是不直接球面展开成一个贴图来记录,而是用一个立方体的6个面来记录
    从圆心到球面上的点连接一条射线,击中立方体包围盒的某个点,则把球面点的光照信息记录到立方体包围盒的点上去,得到6张纹理图来记录这个环境光了
    在这里插入图片描述
    在这里插入图片描述

4.2 凹凸贴图

  • 再次强调:纹理就是开辟的一块空间存放信息,因此纹理存啥都行,并不只是存放颜色
    在之前的shading计算时,纹理只是用来替换kd漫反射项的颜色
  • 纹理:定义任何不同位置的属性/信息
    如果用纹理 来存放高度会怎样?
  • 如下高度图,白色部分表示沿着法线往外移动,黑色则向内移动
    在这里插入图片描述
  • 模型的每个点都对应到纹理上,有一个高度变化,并且重新计算变化后的法线,从而影响着色计算
    其实模型的面数完全没有改变,只是贴了一张图,人为的对法线进行造假,就可以产生这种明暗变化从而让人以为这个球是凹凸不平的
  • 流程:每个点映射到高度纹理图->模型获得每个点的相对位移信息->重新计算法线->计算着色
    在这里插入图片描述
  • 如何根据高度重新计算法线?

在这里插入图片描述
(1)2D平面内计算如下
原本法线方向(0,1),用微分求出凹凸贴图定义的变化后点的切线,再负倒数+单位化即得法线n
在这里插入图片描述
(2)实际3D空间中的计算跟2D没啥区别就是加一维而已
求出u、v两个方向的微分(切线斜率)然后负倒数单位化,具体推导过程不清楚,记住结果也行的。
注意: 计算的时候是在局部空间进行计算,即认原本法线在局部空间中永远指向正上方(2D是(0,1),3D是(0,0,1)),最后再做个神秘的变换,变回空间坐标系即可。具体在作业3中学习
在这里插入图片描述

4.3 位移贴图

如果说凹凸贴图是欺骗眼睛的戏法,位移贴图那就是真正的做位移
他们都是用相同的一张纹理图定义不同位置的相对高度变化,区别是什么?

  • 凹凸贴图:通过贴图中高度变化计算新法线,通过法线影响着色计算,并未移动顶点
  • 位移贴图:通过贴图中高度变化直接影响顶点位置,真正的移动顶点
    在这里插入图片描述
  • 但是位移贴图是有条件的,需要原本模型的面数足够多
    位移贴图定义的高度变化如果想完美的展现,那就必须模型顶点数(采样频率)高于高度变化的频率(样本频率),但并不一定一开始就给一个模型面数足够细致,应用动态曲面细分(DirectX提供)技术可以根据需要进行细分

4.4 环境光遮蔽(Ambient Occlusion,AO)

  • AO是来描绘物体和物体相交或靠近的时候遮挡周围漫反射光线的效果,可以解决或改善漏光、阴影不实等问题,解决或改善场景中缝隙、褶皱与墙角以及细小物体等的表现不清晰问题,综合改善细节尤其是暗部阴影,增强空间的层次感、真实感,同时加强和改善画面明暗对比,增强画面的艺术性。
  • 在计算机图形学中全局光照的效果直接影响画面的真实性。使用传统的基于物理的关照算法(例如光线跟踪算法 )可以达到很好的效果,但其计算复杂难以做到实时应用 。所以在游戏等实时应用中一般选用环境光遮蔽 (AO)技术模拟全局光照效果,在画面质量和渲染速度之间取得平衡 。
    应用环境光遮蔽:着色结果x环境光遮蔽
    在这里插入图片描述
    在这里插入图片描述

4.5 三维纹理

不只是定义表面的点的属性,还要定义物体内部的点属性,比如三维空间中任何一个点的密度、颜色等
多用于医学上的核磁共振、CT成像
在这里插入图片描述


GAMES101图形学专栏

© 版权声明
THE END
喜欢就支持一下吧
点赞366 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容