从零开始学习opengl-9.光照基础

光照基础

冯氏光照模型的主要结构由3个元素组成:环境(Ambient)、漫反射(Diffuse)和镜面(Specular)光照。这些光照元素看起来像下面这样:在这里插入图片描述

环境光照

就是在颜色上乘上一个值,使它整体变暗或变亮

void main()
{
    float ambientStrength = 0.1f;
    vec3 ambient = ambientStrength * lightColor;
    vec3 result = ambient * objectColor;
    color = vec4(result, 1.0f);
}

漫反射光照

在这里插入图片描述
我们知道两个单位向量的角度越小,它们点乘的结果越倾向于1。当两个向量的角度是90度的时候,点乘会变为0。这同样适用于θ,θ越大,光对片段颜色的影响越小。

注意,我们使用的是单位向量(Unit Vector,长度是1的向量)取得两个向量夹角的余弦值,所以我们需要确保所有的向量都被标准化,否则点乘返回的值就不仅仅是余弦值了。
default.vs

#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

out vec3 Normal;
out vec3 FragPos;
void main()
{
    gl_Position = projection * view * model * vec4(position, 1.0f);
	FragPos=vec3(model*vec4(position,1.0f));
	//片段位置FragPos需要把顶点位置属性乘以模型矩阵把它变换到世界空间坐标
	Normal=normal;//法向量
}

default.frag

#version 330 core
out vec4 color;
  
in vec3 Normal;  //法向量
in vec3 FragPos;  //片段位置
  
uniform vec3 lightPos; //光源位置
uniform vec3 lightColor;
uniform vec3 objectColor;

void main()
{
    // Ambient
    float ambientStrength = 0.1f;
    vec3 ambient = ambientStrength * lightColor;//环境光

    // Diffuse 
    vec3 norm = normalize(Normal);
    vec3 lightDir = normalize(lightPos - FragPos);//光源方向
    //计算方向时要归一化
    float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = diff * lightColor;//散色因子
	//两个向量之间的角度越大,散射因子就会越小:
    vec3 result = (ambient + diffuse) * objectColor;
    color = vec4(result, 1.0f);
} 

注意:上面光源方向是由片段指向光源的,方向根据平行四边形原则结果由减向量的终点指向被减向量的终点。
物体的亮度,根据对应面的法向量与光源方向的角度的变化而变化
越接近90度越亮,如果接近0或180度,就会变得很暗。
如图:在这里插入图片描述

最后一件事

当然我们的法向量也要转换到世界坐标里,但是这不是简单地把它乘以一个模型矩阵就能搞定的。

如果模型矩阵执行了不等比缩放,法向量就不再垂直于表面了,顶点就会以这种方式被改变了。

正规矩阵被定义为“模型矩阵左上角的逆矩阵转置矩阵”。

在顶点着色器中,我们可以使用inverse和transpose函数自己生成正规矩阵,inverse和transpose函数对所有类型矩阵都有效。注意,我们也要把这个被处理过的矩阵强制转换为3×3矩阵,这是为了保证它失去了平移属性,之后它才能乘以法向量。

Normal = mat3(transpose(inverse(model))) * normal;

在环境光照部分,光照表现没问题,这是因为我们没有对物体本身执行任何缩放操作,因而不是非得使用正规矩阵不可,用模型矩阵乘以法线也没错。可是,如果你进行了不等比缩放,使用正规矩阵去乘以法向量就是必不可少的了。

镜面光照

我们观察的角度(摄像机)与光源的角度,在片段表面会产生所反射的高光
在这里插入图片描述
为了得到观察者的世界空间坐标,我们简单地使用摄像机对象的位置坐标代替(它就是观察者)。所以我们把另一个uniform添加到片段着色器,把相应的摄像机位置坐标传给片段着色器:

uniform vec3 viewPos;

GLint viewPosLoc = glGetUniformLocation(lightingShader.Program, "viewPos");
glUniform3f(viewPosLoc, camera.Position.x, camera.Position.y, camera.Position.z);
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, norm);

reflect函数要求的第一个是从光源指向片段位置的向量,但是lightDir当前是从片段指向光源的向量。我们通过lightDir向量的相反数获得它的方向的反向。第二个参数要求是一个法向量

float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
vec3 specular = specularStrength * spec * lightColor;

我们先计算视线方向与反射方向的点乘(确保它不是负值),然后得到它的32次幂。这个32是高光的发光值(Shininess)。一个物体的发光值越高,反射光的能力越强,散射得越少,高光点越小。在下面的图片里,你会看到不同发光值对视觉(效果)的影响:在这里插入图片描述
剩下的最后一件事情是把它添加到环境光颜色和散射光颜色里,然后再乘以物体颜色:在这里插入图片描述
现象:观察不用的角度,会对平面产生不同的高光。

default.frag

#version 330 core
out vec4 color;
  
in vec3 Normal;  
in vec3 FragPos;  
  
uniform vec3 lightPos; 
uniform vec3 lightColor;
uniform vec3 objectColor;
uniform vec3 viewPos;

void main()
{
    // Ambient
    float ambientStrength = 0.1f;
    vec3 ambient = ambientStrength * lightColor;

    // Diffuse 
    vec3 norm = normalize(Normal);
    vec3 lightDir = normalize(lightPos - FragPos);
    float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = diff * lightColor;

	float specularlength=0.4f;
	vec3 viewDir=normalize(viewPos-FragPos);
	vec3 reflectDir=reflect(-lightDir,norm);
	float spec=pow(max(dot(viewDir,reflectDir),0.0),64);
	vec3 specular=specularlength*lightColor*spec;
    vec3 result = (ambient + diffuse+specular) * objectColor;
    color = vec4(result, 1.0f);
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值