LearnOpenGL学习笔记—光照06:Multiple lights
0 前言
本节笔记对应官网学习内容:多光源
在光照01中我们初识了颜色的概念,试着做了一下环境光
在光照02中我们学习了一下Phong光照模型与Blinn-Phong光照模型
在光照03中我们初识了材质的概念并封装了对应的类
在光照04中我们认识了光照贴图,丰富了材质的代码。
在光照05中我们讨论几种不同类型的投光物:平行光,点光,还有聚光
我们在前面的教程中已经学习了许多关于OpenGL中光照的知识,其中包括布林冯氏着色(Blinn-Phong Shading)、材质(Material)、光照贴图(Lighting Map)以及不同种类的投光物(Light Caster)。
在这一节中,我们将结合之前学过的所有知识,创建一个包含六个光源的场景。
我们将模拟一个类似太阳的定向光(Directional Light)光源,四个分散在场景中的点光源(Point Light),以及一个手电筒(Flashlight)。
1 Render Pipeline
从我们用glViewport(0, 0, 800, 600);
开完窗,之后绝大部分都是经典的Render Pipeline:
深度测试
实例化shader / 实例化material / 整备模型设置VAO与VBO / 整备Texture(杂活)
准备MVP矩阵(经典的Render Pipeline一部分)
进入渲染循环中
-buffer清屏(经典的Render Pipeline一部分)
–画10个物件
—设置uniform(经典的Render Pipeline一部分)
渲染管线与Shader密不可分,改渲染管线很多时候也要改shader
我们到现在实现了一个非常轻便的渲染管线,从开窗到画图形
不但如此,我们还实现了一套对应的shader
我们这节要做的就是让它适应六光源
我们接下来的代码,我们要意识到我们什么时候在改渲染管线,是否是因为我们改了渲染管线所以去改了shader。
带着这些问题,我们能对渲染管线有更深的认识。
2 Directional Light
之前的代码我们写的很凌乱,这一次我们把shader进行整合改动,清爽一些
fragmentSource进行修改 把平行光单独变成一个方法
#version 330 core
//着色点和法向
in vec3 FragPos;
in vec3 Normal;
in vec2 TexCoord;
struct Material {
vec3 ambient;
sampler2D diffuse;
sampler2D specular;
sampler2D emission;
float shininess;
};
uniform Material material;
struct LightDirectional{
vec3 dirToLight;
vec3 pos;
vec3 color;
};
uniform LightDirectional lightD;
out vec4 FragColor;
uniform vec3 objColor;
uniform vec3 ambientColor;
uniform vec3 cameraPos;
uniform float time;
vec3 CalcLightDirectional(LightDirectional light, vec3 uNormal, vec3 dirToCamera){
//diffuse
float diffIntensity = max(dot(uNormal, light.dirToLight), 0.0);
vec3 diffuseColor = diffIntensity * texture(material.diffuse,TexCoord).rgb * light.color;
//Blinn-Phong specular
vec3 halfwarDir = normalize(light.dirToLight + dirToCamera);
float specularAmount = pow(max(dot(uNormal, halfwarDir), 0.0),material.shininess);
vec3 specularColor = texture(material.specular,TexCoord).rgb * specularAmount * light.color;
vec3 result = diffuseColor+specularColor;
return result;
}
void main(){
vec3 finalResult = vec3(0,0,0);
vec3 uNormal = normalize(Normal);
vec3 dirToCamera = normalize(cameraPos - FragPos);
//emission 32 distance
float eDistance = length(cameraPos-FragPos);
float eCoefficient= 1.0 / (1.0f + 0.14f * eDistance + 0.07f * (eDistance * eDistance));
vec3 emission;
if( texture(material.specular,TexCoord).rgb== vec3(0,0,0) ){
emission= texture(material.emission,TexCoord).rgb;
//fun
emission = texture(material.emission,TexCoord + vec2(0.0,time/2)).rgb;//moving
emission = emission * (sin(time) * 0.5 + 0.5) * 2.0 * eCoefficient;//fading
}
//ambient
vec3 ambient= material.ambient * ambientColor * texture(material.diffuse,TexCoord).rgb;
finalResult += CalcLightDirectional(lightD, uNormal, dirToCamera)+emission+ambient;
FragColor=vec4(finalResult,1.0);
}
在main文件中也做对应修改
#pragma region Light Declare
//position angle color
LightDirectional lightD (glm::vec3(1.0f, 1.0f, -1.0f),
glm::vec3(glm::radians(45.0f), glm::radians(45.0f),0),
glm::vec3(1.0f, 1.0f, 1.0f));
#pragma endregion
......
glUniform3f(glGetUniformLocation(myShader->ID, "lightD.pos"), lightD.position.x, lightD.position.y, lightD.position.z);
glUniform3f(glGetUniformLocation(myShader->ID, "lightD.color"), lightD.color.x, lightD.color.y, lightD.color.z);
glUniform3f(glGetUniformLocation(myShader->ID, "lightD.dirToLight"), lightD.direction.x, lightD.direction.y, lightD.direction.z);
平行光的效果就做好了
3 Point Light
在fragmentSource进行修改,加入点光源的方法
......
struct LightPoint{
vec3 pos;
vec3 color;
float constant;
float linear;
float quadratic;
};
uniform LightPoint lightP0;
......
vec3 CalcLightPoint(LightPoint light, vec3 uNormal, vec3 dirToCamera){
//attenuation
vec3 dirToLight=light.pos-FragPos;
float dist =length(dirToLight);
float attenuation= 1.0 / (light.constant + light.linear * dist + light.quadratic * (dist * dist));
//diffuse
float diffIntensity = max(dot(uNormal, normalize(dirToLight)), 0.0);
vec3 diffuseColor = diffIntensity * texture(material.diffuse,TexCoord).rgb * light.color;
//Blinn-Phong specular
vec3 halfwarDir = normalize(dirToLight + dirToCamera);
float specularAmount = pow(max(dot(uNormal, halfwarDir), 0.0),material.shininess);
vec3 specularColor = texture(material.specular,TexCoord).rgb * specularAmount * light.color;
vec3 result = (diffuseColor+specularColor)*attenuation;
return result;
}
void main(){
vec3 finalResult = vec3(0,0,0);
vec3 uNormal = normalize(Normal);
vec3 dirToCamera = normalize(cameraPos - FragPos);
//emission 32 distance
float eDistance = length(cameraPos-FragPos);
float eCoefficient= 1.0 / (1.0f + 0.14f * eDistance + 0.07f * (eDistance * eDistance));
vec3 emission;
if( texture(material.specular,TexCoord).rgb== vec3(0,0,0) ){
emission= texture(material.emission,TexCoord).rgb;
//fun
emission = texture(material.emission,TexCoord + vec2(0.0,time/2)).rgb;//moving
emission = emission * (sin(time) * 0.5 + 0.5) * 2.0 * eCoefficient;//fading
}
//ambient
vec3 ambient= material.ambient * ambientColor * texture(material.diffuse,TexCoord).rgb;
finalResult += CalcLightDirectional(lightD, uNormal, dirToCamera);
finalResult += CalcLightPoint(lightP0, uNormal, dirToCamera);
finalResult +=emission+ambient;
FragColor=vec4(finalResult,1.0);
}
main文件中
#pragma region Light Declare
//position angle color
LightDirectional lightD (glm::vec3(1.0f, 1.0f, -1.0f),
glm::vec3(glm::radians(45.0f), glm::radians(45.0f),0),
glm::vec3(1.0f, 1.0f, 1.0f));
LightPoint lightP0 (glm::vec3(1.0f, 1.0f, -1.0f),
glm::vec3(1.0f, 1.0f, 1.0f));
#pragma endregion
......
glUniform3f(glGetUniformLocation(myShader->ID, "lightP0.pos"), lightP0.position.x, lightP0.position.y, lightP0.position.z);
glUniform3f(glGetUniformLocation(myShader->ID, "lightP0.color"), lightP0.color.x, lightP0.color.y, lightP0.color.z);
glUniform1f(glGetUniformLocation(myShader->ID, "lightP0.constant"), lightP0.constant);
glUniform1f(glGetUniformLocation(myShader->ID, "lightP0.linear"), lightP0.linear);
glUniform1f(glGetUniformLocation(myShader->ID, "lightP0.quadratic"), lightP0.quadratic);
把之前的平行光注视点,单独看看P0这个点光,完成效果
既然可以有P0,那么自然可以有P1,P2,P3
在main中
......
#pragma region Light Declare
//position angle color
LightDirectional lightD (glm::vec3(1.0f, 1.0f, -1.0f),
glm::vec3(glm::radians(45.0f), glm::radians(45.0f),0),
glm::vec3(1.0f, 1.0f, 1.0f));
LightPoint lightP0 (glm::vec3(1.0f, 0,0),
glm::vec3(1.0f, 0, 0));
LightPoint lightP1 (glm::vec3(0, 1.0f, 0),
glm::vec3(0, 1.0f, 0));
LightPoint lightP2 (glm::vec3(0, 0, 1.0f),
glm::vec3(0, 0, 1.0f));
LightPoint lightP3 (glm::vec3(1.0f, 1.0f, 1.0f),
glm::vec3(1.0f, 0, 1.0f));
#pragma endregion
......
glUniform3f(glGetUniformLocation(myShader->ID, "lightP1.pos"), lightP1.position.x, lightP1.position.y, lightP1.position.z);
glUniform3f(glGetUniformLocation(myShader->ID, "lightP1.color"), lightP1.color.x, lightP1.color.y, lightP1.color.z);
glUniform1f(glGetUniformLocation(myShader->ID, "lightP1.constant"), lightP1.constant);
glUniform1f(glGetUniformLocation(myShader->ID, "lightP1.linear"), lightP1.linear);
glUniform1f(glGetUniformLocation(myShader->ID, "lightP1.quadratic"), lightP1.quadratic);
glUniform3f(glGetUniformLocation(myShader->ID, "lightP2.pos"), lightP2.position.x, lightP2.position.y, lightP2.position.z);
glUniform3f(glGetUniformLocation(myShader->ID, "lightP2.color"), lightP2.color.x, lightP2.color.y, lightP2.color.z);
glUniform1f(glGetUniformLocation(myShader->ID, "lightP2.constant"), lightP2.constant);
glUniform1f(glGetUniformLocation(myShader->ID, "lightP2.linear"), lightP2.linear);
glUniform1f(glGetUniformLocation(myShader->ID, "lightP2.quadratic"), lightP2.quadratic);
glUniform3f(glGetUniformLocation(myShader->ID, "lightP3.pos"), lightP3.position.x, lightP3.position.y, lightP3.position.z);
glUniform3f(glGetUniformLocation(myShader->ID, "lightP3.color"), lightP3.color.x, lightP3.color.y, lightP3.color.z);
glUniform1f(glGetUniformLocation(myShader->ID, "lightP3.constant"), lightP3.constant);
glUniform1f(glGetUniformLocation(myShader->ID, "lightP3.linear"), lightP3.linear);
glUniform1f(glGetUniformLocation(myShader->ID, "lightP3.quadratic"), lightP3.quadratic);
在fragmentSource中
finalResult += CalcLightDirectional(lightD, uNormal, dirToCamera);
finalResult += CalcLightPoint(lightP0, uNormal, dirToCamera);
finalResult += CalcLightPoint(lightP1, uNormal, dirToCamera);
finalResult += CalcLightPoint(lightP2, uNormal, dirToCamera);
finalResult += CalcLightPoint(lightP3, uNormal, dirToCamera);
finalResult +=emission+ambient;
FragColor=vec4(finalResult,1.0);
我们就会得到这样比较多彩的光啦
4 SpotLight
在fragmentSource进行修改,加入聚光的方法
struct LightSpot{
vec3 pos;
vec3 color;
float constant;
float linear;
float quadratic;
vec3 dirToLight;
float cosPhyInner;
float cosPhyOuter;
};
......
vec3 CalcLightSpot(LightSpot light, vec3 uNormal, vec3 dirToCamera){
//attenuation
vec3 dirToLight=light.pos-FragPos;
float dist =length(dirToLight);
float attenuation= 1.0 / (light.constant + light.linear * dist + light.quadratic * (dist * dist));
//diffuse
float diffIntensity = max(dot(uNormal, normalize(dirToLight)), 0.0);
vec3 diffuseColor = diffIntensity * texture(material.diffuse,TexCoord).rgb * light.color;
//Blinn-Phong specular
vec3 halfwarDir = normalize(dirToLight + dirToCamera);
float specularAmount = pow(max(dot(uNormal, halfwarDir), 0.0),material.shininess);
vec3 specularColor = texture(material.specular,TexCoord).rgb * specularAmount * light.color;
//spot
float spotRatio;
float cosTheta = dot( normalize(-1*dirToLight) , -1*light.dirToLight );
if(cosTheta > light.cosPhyInner){
//inside
spotRatio=1;
}else if(cosTheta > light.cosPhyOuter){
//middle
spotRatio=(cosTheta-light.cosPhyOuter)/(light.cosPhyInner-light.cosPhyOuter);
}else{
//outside
spotRatio=0;
}
vec3 result=(diffuseColor+specularColor)*attenuation*spotRatio;
return result;
}
......
void main(){
vec3 finalResult = vec3(0,0,0);
vec3 uNormal = normalize(Normal);
vec3 dirToCamera = normalize(cameraPos - FragPos);
//emission 32 distance
float eDistance = length(cameraPos-FragPos);
float eCoefficient= 1.0 / (1.0f + 0.14f * eDistance + 0.07f * (eDistance * eDistance));
vec3 emission;
if( texture(material.specular,TexCoord).rgb== vec3(0,0,0) ){
emission= texture(material.emission,TexCoord).rgb;
//fun
emission = texture(material.emission,TexCoord + vec2(0.0,time/2)).rgb;//moving
emission = emission * (sin(time) * 0.5 + 0.5) * 2.0 * eCoefficient;//fading
}
//ambient
vec3 ambient= material.ambient * ambientColor * texture(material.diffuse,TexCoord).rgb;
// finalResult += CalcLightDirectional(lightD, uNormal, dirToCamera);
// finalResult += CalcLightPoint(lightP0, uNormal, dirToCamera);
// finalResult += CalcLightPoint(lightP1, uNormal, dirToCamera);
// finalResult += CalcLightPoint(lightP2, uNormal, dirToCamera);
// finalResult += CalcLightPoint(lightP3, uNormal, dirToCamera);
finalResult += CalcLightSpot(lightS, uNormal, dirToCamera);
finalResult += emission+ambient;
FragColor=vec4(finalResult,1.0);
}
main文件中
LightSpot lightS (glm::vec3(0, 3.0f, -1.0f),
glm::vec3(glm::radians(90.0f), 0, 0),
glm::vec3(0, 1.0f, 1.0f));
......
glUniform3f(glGetUniformLocation(myShader->ID, "lightS.pos"), lightS.position.x, lightS.position.y, lightS.position.z);
glUniform3f(glGetUniformLocation(myShader->ID, "lightS.color"), lightS.color.x, lightS.color.y, lightS.color.z);
glUniform3f(glGetUniformLocation(myShader->ID, "lightS.dirToLight"), lightS.direction.x, lightS.direction.y, lightS.direction.z);
glUniform1f(glGetUniformLocation(myShader->ID, "lightS.constant"), lightS.constant);
glUniform1f(glGetUniformLocation(myShader->ID, "lightS.linear"), lightS.linear);
glUniform1f(glGetUniformLocation(myShader->ID, "lightS.quadratic"), lightS.quadratic);
glUniform1f(glGetUniformLocation(myShader->ID, "lightS.cosPhyInner"), lightS.cosPhyInner);
glUniform1f(glGetUniformLocation(myShader->ID, "lightS.cosPhyOuter"), lightS.cosPhyOuter);
是的,我们往聚光中加了衰减的变量,我们对应在聚光的h和cpp文件中,按照点光的写法加上就好了,这里不再展示。
我们注释掉其他光,只留下聚光
5 final
我们把所有的光都放上去,头顶青色聚光,后面的平行光,四周的点光,造成以下的效果。
关于项目代码,我们在下一节复习课进行统一展示