一个错误的修正
在之前的basic lighting中,vertexShader中对于FragPos我写错了,不是简单的mat3(modelMat)* aPos,
而是
FragPos = (modelMat * vec4(aPos.xyz,1.0)).xyz;
这样,这是因为,对于坐标变换来说,一定要在四元坐标中来变换不然就会错!
所以,先变换再裁剪。
其实在前面的课程中已经出现了光,但是在那个时候我们只定义了lightColor 和 lightPos,不过,这既不是点光源又不是平行光,在这一节会具体写清楚光该如何实现已经封装成类。
平行光Directional Light)
写一个光的类,里面需要有什么元素呢。
对于平行光 需要有 方向和 颜色
class LightDirectional
{
public:
LightDirectional(glm::vec3 _position, glm::vec3 _angles, glm::vec3 _color = glm::vec3(1.0f,1.0f,1.0f));
glm::vec3 position;
glm::vec3 angles;
glm::vec3 direction = glm::vec3(0, 0, 1.0f);//pointing to Z
glm::vec3 color;
void UpdateDirection();
};
并且修改main中之前设置lightpos的地方,平行光只需要方向和颜色,
在前面声明一个角度是45°的光,前面的那个position就放在那里把,对结果没有影响。
#pragma region Light Declare
LightDirectional light(glm::vec3(10.0f, 10.0f, -5.0f), glm::vec3(glm::radians(45.0f), 0, 0));
#pragma endregion
.......
glUniform3f(glGetUniformLocation(testShader->ID, "lightColor"), light.color.r, light.color.g, light.color.b);
glUniform3f(glGetUniformLocation(testShader->ID, "lightDir"), light.direction.x, light.direction.y, light.direction.z);
点光源Point Light
那么点光源,他就不需要角度了,他需要什么参数呢,位置和颜色。
像上面一样重新建立一个新的点光源的类。
结果如下:
不过,这里面为了更加真实,需要加入衰减因子。
可以看到后面的物体变暗了,bingo!
聚光spotlight
聚光灯就是想舞台上的那种,虽然光从一个点出来,但是和点光源不同的是,他是有范围的。
和之前一样,思考一下一个spotlight需要什么参数,位置position,可以照亮的范围(或者说最大角度)(光切角)Cutoff Angle,和方向spotDir。
我们先抛开颜色,衰减不谈,对于这样的一个光源,最重要的是判断fragment是否可以被光打到。
这里有个很巧妙地思路,不考虑phy和theta谁大,而是直接看他们的cos大小。(因为单位向量点乘得到的标量就是cos)
所以,我们只需要计算cosPhy(这个我们可以直接给出)和cosTheta(这个用spotDIr和lightDIR点乘就行)比较。
ok,接下来就是代码实现。
float cosTheta = dot( normalize(FragPos-lightPos), -1*lightDirUniform);
if(cosTheta>lightS.cosPhy){
//inside
FragColor = vec4( ( ambient + (diffuse + specular))*objColor+emission, 1.0f);
}
else{
//outside
FragColor = vec4( ( ambient )*objColor+emission, 1.0f);
}
最重要的是fragmentShader中,这里一定要保证两个向量的方向一致性。都让方向是从片段指向光源
不过还是有点假,边缘太硬了。而且没有遮挡(这部分在后面会学)先解决边缘问题。
平滑/软化边缘
这个图其实画反了,能理解就行。所以超出范围的角度,我还需要再扩大一点。
此外,我们可以把spot的影响抽象成spotratio,在范围内就是1,外就是0,中间就是过度。
float SpotRatio;
if(cosTheta>lightS.cosInnerPhy){
//inside
SpotRatio = 1.0f;
}else if(cosTheta >lightS.cosOutPhy){
//middle
SpotRatio = (cosTheta-lightS.cosOutPhy)/(lightS.cosInnerPhy-lightS.cosOutPhy);
}else{
//outside
SpotRatio = 0;
}
FragColor = vec4( ( ambient + (diffuse + specular)*SpotRatio)*objColor+emission, 1.0f);
这么些比较好看。
合理