现代计算机图形学入门-闫令琪,课程笔记。
Lecture 7~9: Shading 着色
在图形学中,所谓着色,就是对不同物体使用不同材质的过程 (The process of applying a material to an object)。
物体表面的颜色受光照和材质的影响,光照中光线的颜色也在一定程度上决定物体表面的颜色。着色就是计算物体表面最终该如何显示的这么一个过程。
简单来看,当光照射到物体上时,会有三种表现:高光(镜面反射)、哑光(漫反射)、环境光。如果我们能模拟出类似的表现,着色也就实现了,对于这三种情况我们分别建立不同的数学模型来进行计算。
在此之前我们先定义一些要用到的概念:
漫反射(只考虑理想状态):当光照射一点时,光线均匀的反射至各个方向,此时无论从哪个方向看物体,都是同样的颜色。
理想状态下的漫反射我们采用的是 Lambertian Reflectance(朗博反射/理想散射/朗博余弦定理)数学模型,这是一个理想状态下的简单模型,并不完全符合物理定律。
Kd
:一个系数,表示物体对于光能的吸收率;I/r²
:光的衰减/光能与距离的关系;max(0, n · l)
:入射方向与法线的夹角;Ld
:最终值,值越大亮度越大。高光:接近于镜面反射。当观察方向与光的反射方向很接近时才能看到高光。
此时计算是否显示高光,其实就是计算向量 V 与 R 的夹角,使用的是 Phong Reflectance Model。但是这个计算很麻烦,人们对其进行了改进,叫 Blinn-Phong Reflectance Model。
Blinn-Phone 模型很巧妙的将计算位置改到了向量 h 与法线 n 的夹角。而向量 h 可以由向量 l 和 n 点乘获得,很方便计算。
p
指数代表可以看到高光的范围。一般采用 100 < p < 200
,可视角度大概在 3°.环境光的模型比较简单,主要是为了保证视野内不是一片黑色。
最后,这三种情况叠加在一起,就是我们在着色时使用的模型:
三种方式渲染方式最终效果并没有高低之分,渲染条件不一样,结果也不一样,需要根据不同情况来进行选择。如下图所示,当物体切割的层面无限多时,最终效果是差不多的。
所谓图形管线其实就是从开始建立三维场景到渲染出最终图像的整个过程(类似于生命周期),这个过程中有几个主要操作步骤。
纹理贴图本质上在做一个什么事情?
物体是三维的,但物体表面是二维的。我们可以制作这么一张图片,图片上的每个点与二维表面的每个点一一对应,那么这张图就可以完美的贴在物体表面。这就是纹理贴图要做的事。
贴图上的每个点与二维表面的每个点的对应关系,就是纹理映射。
如上图所示,图中玩具球上所有的点使用的是同一个着色模型,但是表现出来的颜色并不一致。根据着色模型公式的推导我们知道,表现不一致是因为不同点的着色系数不一样(图中红色字体),那么每个点的着色系数我们是需要单独保存的。推广开来,我们可以为每一个点保存一组参数来表示这个点的属性,所有属性综合起来才是这个点最终的表现结果。 映射时用到的一些属性,我们同样可以保存在点的那组参数里。
贴图是二维的,其上的每一个点都可以使用直角坐标 (u, v) 来表示。贴图中每个小三角形顶点的数据我们已经有了,三角形中间的数据,需要使用插值的方式来计算出来。
插值(Interpolation),是一种通过已知的、离散的数据点,在范围内推求新数据点的过程或方法。利用它可通过函数在有限个点处的取值状况,估算出函数在其他点处的近似值。
我的理解:插值与采样相反,采样是已知连续只取部分,插值是已知部分求连续
插值的方式有很多种,这里我们用的是线性插值。如下图,如果已知坐标 (x0, y0) 与 (x1, y1),要得到 [x0, x1]
区间内某一位置 x 在直线上的值,其实就是求出 (x0, y0) 与 (x1, y1) 可能的函数曲线,然后带入 x 求得 y,此时求得的 y 值虽然有误差,但是是一个非常近似正确的值。
什么是重心坐标?
前面我们有讲过单位向量(长度为一,只表示方向),在笛卡尔坐标系中 X 轴 Y 轴的单位向量又叫做基向量,所有的向量都可以表示为 Sx*i + Sy*j
。如下图所示:
也就是说,在笛卡尔坐标系中,任何的向量都是基向量 i, j 进行缩放后相加的结果,这一概念肥肠重要。
我们把这个概念拓展一下,脱离直角坐标系,不再局限于 X 轴和 Y 轴上,而是可以在整个平面内随意移动和缩放,此时如果用 v, w 来表示基向量,那么我们就可以用 Sv*v + Sw*w
来表示这个平面上的任意一个向量!当这个向量的起点是原点时,Sv*v + Sw*w
表示的就是任意一个点。
有了这一个概念,我们看下图这个更直观的例子,在非直角坐标系中,将 abc 看做是三角形的顶点,a 看做原点,a 到 b 和 a 到 c 的向量分别是基向量,α, β, γ 为缩放倍数,那么任一点 p 可以表示成:
好的,我们回到刚刚讨论的三角形。知道啥叫重心坐标了,如何计算 α,β,γ 的值呢?直接给出,不做推导了。
_任意一点重心坐标 (α, β, γ) 的计算公式_重心坐标是计算插值的一种方式,我们只要将三个顶点 ABC 中已知的值作为常量带入上面的计算公式,就可以得到三角形内所有像素点的重心坐标(α, β, γ 的值),也就是这一点的插值!这个“已知的值”可以是三个顶点的任意属性:color、depth、material attributes ...
注意:三维物体上的三角形投影到二维,重心坐标有可能会改变,所以如果想计算一些三维属性的插值,应该取三维空间中的顶点属性再去计算得到的结果才是正确的!
现在我们可以获得三角形上每一个点的属性插值了,同样也就能够获取贴图的 (u, v) 坐标了,获取之后去贴图的二维直角坐标系上查询对应的 (u, v) 坐标赋值即可。当然,在应用的过程我们会遇到问题。
Q:第一个问题,当显示器的分辨率很大,但贴图却很小的时候该怎么做? A:打补丁的事当然少不了插值🤣可以使用双线性插值和双立方插值法来计算插值。如下图,红点位置考虑周围四个点的情况,先水平方向线性插值,后垂直方向。
Q:第二个问题:当显示器分辨率低,贴图太大怎么办? A:本质是像素覆盖的纹理面积太大,会产生走样和锯齿。
Mipmap 带来的问题:过度模糊。因为只能取贴图正方形内的近似值,可像素部分的贴图对应在贴图的 uv 坐标上不一定是正方形,这就会造成偏差增大,结果就是远处的元素过渡模糊。
怎么解决呢?常用的是 EWA filtering:不规则图形分解成多个圆环,进行多次查询求得更准确的近似值。当然,多次计算会耗费更多性能。No free lunch...
本文作者:青波
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!