一: 环境光照(Ambient Lighting)
二: 漫反射光照(Diffuse Lighting)
out vec3 Normal;
void main()
{
gl_Position = projection * view * model * vec4(aPos, 1.0);
FragPos = vec3(model * vec4(aPos, 1.0));//`这里的FragPos也就是片段在世界坐标中的位置。
Normal = aNormal;
} ```
5.3 我们已经把法向量从顶点着色器传到了片段着色器。可是,目前片段着色器里的计算都是在世界空间坐标中进行的。所以,我们应该把法向量也转换为世界空间坐标,但是这不是简单地把它乘以一个模型矩阵就能搞定的。
5.4 法向量只是一个方向向量,不能表达空间中的特定位置。同时,法向量没有齐次坐标(顶点位置中的w分量)。这意味着,位移不应该影响到法向量。因此,如果我们打算把法向量乘以一个模型矩阵,我们就要从矩阵中移除位移部分,只选用模型矩阵左上角3×3的矩阵(注意,我们也可以把法向量的w分量设置为0,再乘以4×4矩阵;这同样可以移除位移)。对于法向量,我们只希望对它实施缩放和旋转变换。
5.5 其次,如果模型矩阵执行了**不等比缩放**,顶点的改变会导致法向量不再垂直于表面了。因此,我们不能用这样的模型矩阵来变换法向量。
5.6 修复不等比缩放的诀窍是使用一个为法向量专门定制的模型矩阵。这个矩阵称之为**法线矩阵(Normal Matrix):模型矩阵左上角的逆矩阵的转置矩阵**,它使用了一些线性代数的操作来移除对法向量错误缩放的影响。
5.7 在顶点着色器中,我们可以使用inverse和transpose函数自己生成这个法线矩阵,这两个函数对所有类型矩阵都有效。注意我们还要把被处理过的矩阵强制转换为3×3矩阵,来保证它失去了位移属性以及能够乘以vec3的法向量。
``` Normal = mat3(transpose(inverse(model))) * aNormal; ```
6. 在片段着色器中添加漫反射光照计算
6.1 计算光源和片段位置之间的方向向量。前面提到,光的方向向量是光源位置向量与片段位置向量之间的向量差。**并且进行标准化。**
``` vec3 norm = normalize(Normal);
vec3 lightDir = normalize(lightPos - FragPos); ```***这里的方向差的计算和摄像机方向向量的计算方法相似,这里的方向是片段指向光源***
6.2 我们对norm和lightDir向量进行点乘,计算光源对当前片段实际的漫发射影响。***结果值再乘以光的颜色,得到漫反射分量***。两个向量之间的角度越大,漫反射分量就会越小。
三: 镜面光照(Specular Lighting)
1. 模拟有光泽物体上面出现的亮点。镜面光照的颜色相比于物体的颜色会更倾向于光的颜色。
2. 和漫反射光照一样,镜面光照也是依据光的方向向量和物体的法向量来决定的,但是它也依赖于观察方向,例如玩家是从什么方向看着这个片段的。
3. 我们通过反射法向量周围光的方向来计算反射向量。然后我们***计算反射向量和视线方向的角度差***,如果夹角越小,那么镜面光的影响就会越大。它的作用效果就是,当我们去看光被物体所反射的那个方向的时候,我们会看到一个***高光。***
4. **观察向量**是镜面光照附加的一个变量,我们可以使用观察者世界空间位置和片段的位置来计算它。之后,我们计算镜面光强度,用它乘以光源的颜色,再将它加上环境光和漫反射分量。
5. 为了得到观察者的世界空间坐标,我们简单地***使用摄像机对象的位置坐标代替(它当然就是观察者)***。所以我们把另一个uniform添加到片段着色器,把相应的摄像机位置坐标传给片段着色器:
6. 计算高光强度
6.1 首先,我们定义一个镜面强度(Specular Intensity)变量,给镜面高光一个中等亮度颜色,让它不要产生过度的影响。
6.2 下一步,我们计算视线方向向量,和对应的沿着法线轴的反射向量:
``` vec3 viewDir = normalize(viewPos - FragPos);//观察方向向量
vec3 reflectDir = reflect(-lightDir, norm); //光的反射向量 ```
6.3 需要注意的是我们**对lightDir向量进行了取反**。reflect函数要求第一个向量是从光源指向片段位置的向量,***但是lightDir当前正好相反,是从片段指向光源(由先前我们计算lightDir向量时,减法的顺序决定)。***为了保证我们得到正确的reflect向量,我们通过对lightDir向量取反来获得相反的方向。第二个参数要求是一个法向量,所以我们提供的是已标准化的norm向量。
6.4 剩下要做的是计算镜面分量。我们先计算视线方向与反射方向的点乘(并确保它不是负值),然后取它的32次幂。这个32是高光的反光度(Shininess)。一个物体的反光度越高,反射光的能力越强,散射得越少,高光点就会越小。
``` float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
vec3 specular = specularStrength * spec * lightColor; ```
四: 最后一件事:最终结果:
``` vec3 result = (ambient + diffuse + specular) * objectColor;
FragColor = vec4(result, 1.0); ```
原文:https://www.cnblogs.com/GarrettWale/p/11337844.html