LearnOpenGL学习笔记—光照06:Multiple lights

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

我们把所有的光都放上去,头顶青色聚光,后面的平行光,四周的点光,造成以下的效果。
关于项目代码,我们在下一节复习课进行统一展示
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值