games101 - 2 - Shading

games101 - 2 - Shading

GAMES101:现代计算机图形学入门 – 计算机图形学与混合现实研讨会 (games-cn.org)

涉及到的课程有:Lecture 7 ~ Lecture 10

可见性/遮挡

物体在三维空间中的位置是有前后关系的。位于前面的物体会遮挡后面的物体,那么如何保证渲染结果有正确的遮挡关系呢?

画家算法

绘制油画的时候,是从后往前进行绘制的。如下图所示:

该算法在绘制前,需要对物体按照深度关系进行排序,而当对象之间的深度关系有交叠的时候(如下图),该算法将会得到错误的结果。

Z-Buffer算法

该算法的基本思想如下:对于每个像素位置,存储当前最小的深度值(min z value),当绘制一个像素位置的时候,首先得到该位置的深度值,然后和深度缓存中记录的最小深度值进行比较,如果当前的深度值更小,更新深度值,并将颜色绘制到颜色缓冲区。伪代码如下:

initialize depth buffer to +inifinity;
for (each triangle T)
    for (each sample(x,y,z) in T)
        if (z < zbuffer[x,y])             // closest sample so far
            framebuffer[x,y] = rgb;       // update color
			zbuffer[x,y] = z;             // update depth

光照、shading

如上图所示,左边是没有光照的效果,右边是待光照着色的效果。可见想要获得立体的视觉效果,必须加入光照。

shadering:往一个对象上应用材质的过程。

Blinn-Phong Reflection Model

先来直观的感受下什么是镜面反射,什么是漫反射,什么是环境光照。

该光照模型也是从镜面反射,漫反射,环境光出发。先给结果:

漫反射

漫反射与视野方向无关.

点光源的光在传播的时候,会随着距离的平方成反比进行衰减。

下图是漫反射的效果:

镜面反射

镜面反射和视角相关,可以想象下,太阳光照射到一扇镜子上进行反射,只有从特定的视角上看去才能够看到刺眼的阳光。

参数变化对应的效果变化图如下:

环境光

shading frequencies

Gourand shading:传入每个顶点对应的颜色,然后插值确定三角形每个位置的颜色;

Blinn-Phone shading:传入每个顶点对应的法向量,然后插值确定三角形每个位置的法向量,然后通过着色模型计算确定每个位置的颜色;

Face shading:每个三角形的颜色都是一致的。参见:【OpenGL4.0】GLSL-Flat Shading平面着色_江南烟雨-CSDN博客

图形管线

纹理映射

通过光照和着色,可以得到绘制结果,那么为了绘制的结果和真实场景更加接近,或者说更加好看,如何更好的给出k_d这个参数呢?通常采用的方法为,传入k_d纹理。三维空间中物体的表面都是可以拆分成二维的图像,那么也就是说,2D中的图像可以映射回3D表面上特定的位置。如下图所示:

应用纹理

通常情况下传入的纹理用于漫反射系数。具体伪代码如下:

for each rasterized screen sample (x,y):         // 通常是像素中心
	(u,v) = evaluate texture coordinate at (x,y) // 计算当前像素位置所在三角形的重心坐标,
	                                             // 然后利用重心坐标进行对纹理坐标进行插值
	texcolor = texture.sample(u,v)
	set sample's color to texcolor;

如果纹理本身太小:需要对纹理进行放大

该问题的处理方式很简单,只需要对纹理本身进行放大处理即可。放大的方法有,最邻近插值,双线性插值,双三次插值。Lanczos插值,最邻近插值,双线性二次插值,三次插值_Jensen Lee的博客-CSDN博客

如何纹理本身太大?- mipmap

该问题的处理方式相对而言就比较难了。

对纹理进行点采样的时候,可能出现锯齿和摩尔纹的现象,如下图所示:

为什么为出现这种现象呢?考虑到我们绘制的时候采用的是透视投影,那么在近处,一个像素覆盖的纹理区域很小,而在远处一个像素会覆盖很大的一片纹理区域,如下图所示:

当一个覆盖纹理较小区域的时候,用像素位置的颜色值表示区域中的值是没有什么问题的,而当一个像素表示纹理很大的一片区域的时候,从直觉上理解,用一个像素点表示区域的特征是存在问题的。这个从采样的角度理解,这是一个欠采样的问题,必然会存在走样的结果。那么怎么处理这个问题呢?可选的方法有:

首先来看下如果采用512x的超采样,得到的结果对比图如下:

这种方式是通过增加采样点,提高采样频率。虽然能够得到比较高质量的结果,但是有很大的开销。那么我们能不能不用一个点表征一个区域的颜色,而是用一个区域的平均色来表征这个区域呢?这个方法就是mipmap。

通过mipmap允许进行范围查找,这个方法是快速的,近似的,并且要求纹理的形状是正方形。mipmap技术的示意图如下:

Level 0表示原始的纹理图像,每增加一级,纹理大小会对应的缩减一半。那么如何计算图像中的像素对应的mipmap等级呢?

那么此时计算得到的mipmap level是连续的,怎么从非连续的预制mipmap中获取对应的像素值呢?这需要用到三线性插值。先获取\(\left \lfloor D \right \rfloor\)\(\left \lfloor D \right \rfloor +1\)整数等级的颜色值,然后再进行插值,获取D对应的颜色。示意图如下:

但是通过mipmap技术得到的结果可能会出现overblur的现象:

那么为什么会出现这种问题呢?从采样角度理解就是欠采样,从之前的表征方式理解,就是用了不合适的区域特征替代了目标区域的特征,如下图所示:

通过anisotropic filtering可以解决映射后axis-aligned矩形区域的显示问题。anisotropic filtering预制的图形及效果如下:

更多Filter相关内容参见:http://resources.mpi-inf.mpg.de/departments/d4/teaching/ws200708/cg/slides/CG09-Textures+Filtering.pdf

纹理的应用

posted @ 2021-09-06 20:09  grassofsky  阅读(106)  评论(0编辑  收藏  举报