基础光照

Posted keguniang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基础光照相关的知识,希望对你有一定的参考价值。

一、冯氏光照模型

其主要结构由3个分量组成:环境(ambient)、漫反射(diffuse)、镜面(specular)光照。下边这张图展示了这些分量看起来的样子:

技术分享图片

环境光照:即使在黑暗的环境下,世界上通常也仍然有一些光亮(月亮、远处的光),所以物体几乎永远不是完全黑暗的。为了模拟这种效果,我们会使用一个环境光照常量,它永远会给物体一些颜色。

漫反射光照:模拟光源对物体的方向性影响。它是冯氏光照模型中最显著的分量。物体的某一部分越是正对着光源,它就会越亮。

镜面光照:模拟有光泽物体上面出现的亮点。

二、环境光照

把环境光照添加到场景里非常简单,用光的颜色乘以一个很小的常量环境因子,再乘以物体的颜色,然后将最终结果作为片段的颜色。

1 void main(){
2     float ambientStrength = 0.1;//一个很小的常量环境因子
3     vec3 ambient = ambientStrength * lightColor;
4 
5     vec3 result = ambient * lightColor;
6     FragColor = vec4(result,1.0f);      
7 }

运行结果:

立方体非常暗,但是应用了环境光,所以不是全黑。

 技术分享图片

三、漫反射光照

环境光照本身不能提供显著的结果,漫反射可以对物体产生显著的视觉效果。漫反射光照使物体上与光线方向越接近的片段能从光源处获得更多的亮度。

技术分享图片

 如果光线垂直于物体表面,那么这束光会对物体的影响最大化。为了测量光线和片段的角度,我们使用法向量(黄色箭头)。

注:为了只得到两个向量夹角的余弦值,我们使用单位向量,所以我们需要确保点乘的向量都要经过标准化。

计算漫反射光照需要什么?

1>法向量:一个垂直于顶点表面的向量

2>定向的光线:光源位置与片段位置的向量差。

四、法向量

我们把法向量加入到顶点数据中,更新立方体的顶点着色器

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
out vec3 normal;
void main(){
  gl_Position = projection * view * model * vec4(aPos,1.0f);
  normal = aNormal;
}

五、计算漫反射光照

1、在片段着色器中将光源位置设为uniform

2、我们在世界空间中进行所有的光照计算,因此我们需要一个在世界空间中的顶点位置。我们可以通过把顶点位置属性乘以模型矩阵(不是观察和投影矩阵)来把它变换到世界空间坐标。在顶点着色器中:

out vec3 FragPos;  
out vec3 Normal;

void main()
{
    gl_Position = projection * view * model * vec4(aPos, 1.0);
    FragPos = vec3(model * vec4(aPos, 1.0));
    Normal = aNormal;
}

3、在片段着色器中添加光照计算

1>计算光照方向

1 vec3 normal = normalize(normal);
2 vec3 lightDir =  normalize(lightPos - FragPos);

计算光照时一定对向量进行单位化,只关心方向

2>计算漫反射分量

我们对normlightDir向量进行点乘,计算光源对当前片段实际的漫发射影响。结果值再乘以光的颜色,得到漫反射分量。两个向量之间的角度越大,漫反射分量就会越小:

1 float diff = max(dot(norm,lightDir),0);
2 vec3 diffuse = diff * lightColor;

如果两个向量之间的角度大于90度,点乘的结果就会变成负数,这样会导致漫反射分量变为负数。为此,我们使用max函数返回两个参数之间较大的参数,从而保证漫反射分量不会变成负数。因为负数的光照是没有定义的。

现在我们有了环境光分量和漫反射分量,我们把它们相加,然后把结果乘以物体的颜色,来获得片段最后的输出颜色。

1 vec3 result = (ambient + difuse) * objectColor;
2 FragColor = vec4(result,1.0);

六、镜面光照

也是根据光的方向向量和物体的法向量来决定的,但也依赖于观察方向

技术分享图片

vec3 reflectDir = reflect(-lightDir, norm);

需要注意的是我们对lightDir向量进行了取反。reflect函数要求第一个向量是光源指向片段位置的向量,但是lightDir当前正好相反,是从片段指向光源(由先前我们计算lightDir向量时,减法的顺序决定)。为了保证我们得到正确的reflect向量,我们通过对lightDir向量取反来获得相反的方向。第二个参数要求是一个法向量,所以我们提供的是已标准化的norm向量。

 

我们先计算视线方向与反射方向的点乘(并确保它不是负值),然后取它的32次幂。这个32是高光的反光度(Shininess)。一个物体的反光度越高,反射光的能力越强,散射得越少,高光点就会越小。在下面的图片里,你会看到不同反光度的视觉效果影响:

技术分享图片

我们不希望镜面成分过于显眼,所以我们把指数保持为32。






以上是关于基础光照的主要内容,如果未能解决你的问题,请参考以下文章

Cg入门17:Fragment shader - 片段级光照(添加阴影)

光照 漫反射光照

光照 漫反射光照

光照 漫反射光照

光照 漫反射光照

Unity Shader 光照模型(基础公式和代码实现)