简单的冯氏光照模型

冯氏光照模型分为三个部分:

  • 环境光 Ambient 即使在完全黑暗的情况下,世界上也通常会有一些光亮(比如:月光、远处分散的光源),物体不会是完全黑暗的。
  • 漫反射光 Diffuse 视觉上最显著的分量。物体的某一部分越是正对着光源,那么这部分就越亮。
  • 镜面光 Specular 模拟有光泽物体上的亮点。这个颜色会更加倾向于光的颜色。

环境光照

void main()
{
	//1、设置一个很小的常量环境因子,来假设场景中一些发散的光
    float ambientStrength = 0.1;
    //2、环境光 = 常量环境因子 * 光的颜色
    vec3 ambient = ambientStrength * lightColor;
}

漫反射光照!!

首先明确这几点:

1、计算漫反射光照需要的数据是:

  • 法向量 Normal:一个垂直于顶点表面的向量。
  • 定向的光线 = 光源的位置向量 - 顶点的位置向量

2、几乎所有的光照计算都是在片段着色器中运行的。因此需要将相关数据传递到片段着色器中进行计算

  • 需要将法向量从顶点着色器传递到片段着色器;
  • 世界空间中的顶点位置 = (局部空间)顶点位置属性 * 模型矩阵 该计算在顶点着色器中完成,并声明一个输出变量将结果传递到片段着色器中。

3、计算光照时,通常不关心一个向量的模长或它的位置,我们只关心它们的方向。所以,几乎所有的计算都使用单位向量完成,因为这简化了大部分的计算(比如点乘)。

4、两个单位向量的夹角越小,它们点乘的结果越倾向于1。当两个向量的夹角为90度的时候,点乘会变为0。点乘结果越大,光对片段颜色的影响就越大。

1. 法向量

已经简单地把法线数据手工添加到顶点数据中,接下来只需将其传递到片段着色器。
但是我们应用一个不等比缩放时,法向量就不会再垂直于对应的表面了,这样光照就会被破坏。于是新的解决办法为:在顶点着色器中,使用inverse和transpose函数生成一个法线矩阵,这两个函数对所有类型矩阵都有效。注意我们还要把被处理过的矩阵强制转换为3×3矩阵,来保证它失去了位移属性以及能够乘以vec3的法向量。

顶点着色器:

#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.0);
    //Normal = aNormal;
    Normal = mat3(transpose(inverse(model))) * aNormal;
}

片段着色器:

// 在片段着色器中接受这个变量
in vec3 Normal;
2. 定向光线

1)光源位置(是一个静态变量,可以直接设置)
简单地在片段着色器中把它声明为uniform:uniform vec3 lightPos;
然后在渲染循环中(渲染循环的外面也可以,因为它不会改变)更新uniform:lightingShader.setVec3("lightPos", lightPos);

2)顶点位置 (顶点数组中的数据是在局部空间中的,而我们计算光照效果是世界空间中。因此需要将顶点数据与模型矩阵相乘,来将坐标转换到世界空间中)

// 在顶点着色器中完成乘法,然后声明输出变量FragPos,将结果输出到片段着色器中。
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;
}

// 最后,在片段着色器中添加相应的输入变量:`in vec3 FragPos;`

3) 计算定向光线

// 定向光线 = 光源位置向量 - 片段位置向量
// 记得最后将其标准化normalize
vec3 lightDir = normalize(lightPos - FragPos);
3. 已知法向量和定向光线,来计算漫反射光
//1、标准化法向量
vec3 norm = normalize(Normal);
// 2、标准化定向光线向量
vec3 lightDir = normalize(lightPos - FragPos);
// 3、将两者进行点乘,计算出光源对物体影响的大小,由此确定物体的最终颜色
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = diff * lightColor;

镜面光照

计算反射向量和视线方向的角度差,如果夹角越小,那么镜面光的影响就会越大。

新增向量“观察者的位置”:即摄像机的位置,通过在片段着色器中设置uniform这个全局变量,将摄像机的位置传递给片段着色器。

// 1、设置一个合适的镜面光分量
float specularStrength = 0.5;
// 2、计算视线方向向量
vec3 viewDir = normalize(viewPos - FragPos);
// 3、计算反射向量
vec3 reflectDir = reflect(-lightDir, norm);
// 4、将两者进行点乘,计算出镜面光影响的大小
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
// 5、计算镜面分量
vec3 specular = specularStrength * spec * lightColor;

最后计算最终的冯氏光照

// 三个向量相加,并乘以物体的颜色,就是最终的光照后物体的颜色了
 vec3 result = (ambient + diffuse + specular) * objectColor;
 FragColor = vec4(result, 1.0);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值