代码工程地址:
https://github.com/jiabaodan/Direct12BookReadingNotes
学习目标
- 理解基本的材质和光照之间交互方式;
- 熟悉局部光照和全局光照之间的不同;
- 学习如何用数学的方式描述平面上一个点的方向,以便于计算入射光和平面之间的夹角;
- 学习如何准确的变换法向量;
- 区分环境光,漫反射和高光;
- 学习如何实现点光源、方向光和聚光灯;
- 学习如何通过改变一个函数中衰变参数的方式来改变光照强度。
1 灯光和材质的交互
当使用光照后,我们不再直接给顶点设置颜色,而是通过材质和灯光属性,根据光照公式计算顶点的颜色。它可以让物体的颜色更加真实。
本书中的光照模型都是使用局部光照模型。物体之间是不可照亮的,只计算直接从光源发射的灯光。
全局光照不仅计算光源发射的灯光,也计算物体之间反射的间接光照,关于全局光照的介绍可以参考下面的文章:
http://on-demand.gputechconf.com/gtc/2014/presentations/S4552-rt-voxel-based-global-illumination-gpus.pdf
2 法向量
面法线是一个用来描述多边形朝向的单位向量。
为了光照计算,我们知道平面中每个三角形每个点的法线,以便于计算入射光和平面的夹角。为了包含法线,我们为每个顶点定义法线。那么为了近似得到每个顶点的法线,在光栅化阶段会为每个点进行线性差值计算法线。
线性差值求法线并且逐顶点计算光照的算法叫像素光照或者冯氏光照(phong lighting)。另一种性能更高但是准确度更低的光照算法是逐顶点计算。所以将光照从逐像素移动到逐顶点是一个通用的优化方式,这是一种很诱人的优化方式,因为它对画质和视觉效果大部分情况下影响很小。
2.1 法向量的计算
为了计算三角形Δp0, p1, p2的面法线,我们先计算三角形两条边的向量:
u = p1 – p0
v = p2 – p0
面法线就可以计算如下:
n = u × v ∣ ∣ u × v ∣ ∣ n = \frac{u \times v} {||u \times v||} n=∣∣u×v∣∣u×v
下面是计算一个三角面前向向量的代码:
XMVECTOR ComputeNormal(FXMVECTOR p0,
FXMVECTOR p1,
FXMVECTOR p2)
{
XMVECTOR u = p1 - p0;
XMVECTOR v = p2 - p0;
return XMVector3Normalize(XMVector3Cross(u,v));
}
对于一个可微分的平面,我们可以使用微积分算出平面上顶点的法线。但是三角面是不可微分的。所以我们通过共用顶点的每个面法线的平均值来求顶点的法向量。如上图,法向量就等于:
n a v g = n 0 + n 1 + n 2 + n 3 ∣ ∣ n 0 + n 1 + n 2 + n 3 ∣ ∣ n_{avg} = \frac{n_0 + n_1 + n_2 + n_3} {||n_0 + n_1 + n_2 + n_3||} navg=∣∣n0+n1+n2+n3∣∣