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
该问题的处理方式相对而言就比较难了。
对纹理进行点采样的时候,可能出现锯齿和摩尔纹的现象,如下图所示:
为什么为出现这种现象呢?考虑到我们绘制的时候采用的是透视投影,那么在近处,一个像素覆盖的纹理区域很小,而在远处一个像素会覆盖很大的一片纹理区域,如下图所示:
当一个覆盖纹理较小区域的时候,用像素位置的颜色值表示区域中的值是没有什么问题的,而当一个像素表示纹理很大的一片区域的时候,从直觉上理解,用一个像素点表示区域的特征是存在问题的。这个从采样的角度理解,这是一个欠采样的问题,必然会存在走样的结果。那么怎么处理这个问题呢?可选的方法有:
- Rasterization一章中介绍的超采样;games101 - 1 - Rasterization - grassofsky - 博客园 (cnblogs.com)
- 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
纹理的应用
- 环境光映射;纹理存储颜色信息
- 微表面信息:
- 凹凸纹理:在shader计算的时候,对每个点法向量进行扰动;可以参见:几种凹凸贴图(Bump Mapping)的学习记录_syddf-CSDN博客, 凹凸纹理 | TwinklingStar
- 函数纹理:三维空间中的噪声函数;
- 环境遮挡纹理映射;
作者: grassofsky
出处: http://www.cnblogs.com/grass-and-moon
本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出, 原文链接 如有问题, 可邮件(grass-of-sky@163.com)咨询.