OpenGL-02 光照

一、颜色

  • 对光源和物体写不同的shader
    • 物体:反射颜色是自身反射率与光源颜色的乘积
#version 330 core
layout(location = 0) in vec3 aPos;
layout(location = 1) in vec3 aColor;
layout(location = 2) in vec2 aTexCoord;

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

void main()
{
	gl_Position = projection * view * model * vec4(aPos, 1.0);
};

#version 330 core

out vec4 fragColor;


uniform vec4 vexColor;
uniform sampler2D texture1;
uniform sampler2D texture2;

uniform vec3 lightColor;
uniform vec3 objectColor;


void main()
{
	fragColor = vec4(lightColor*objectColor,1.0f);
}
  • 光源:自身颜色
#version 330 core
layout(location = 0) in vec3 aPos;

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

void main()
{
	gl_Position = projection * view * model * vec4(aPos, 1.0);
};
#version 330 core

out vec4 fragColor;

void main()
{
	fragColor = vec4(1.0,1.0,1.0,1.0);
}
  • 因为shader不同,所以需要对这两部分分别做shader以及program的操作,在本文中便是定义两个不同的Shader对象。
Shader ourShader("res/shader/cubeVertex.shader", "res/shader/cubeFragment.shader");
Shader lightShader("res/shader/lightVertex.shader", "res/shader/lightFragment.shader");
  • 两个部分都是使用立方体,所以VBO与EBO可以共享,但是VAO需要分别设置,因为VAO包含着节点指针函数,这与shader的输入变量相关。对于VBO与EBO的数据,自然也是只需要一次传输。
unsigned int VBO;
	glGenBuffers(1, &VBO);
	unsigned int EBO;
	glGenBuffers(1, &EBO);
	unsigned int lightVAO;
	glGenVertexArrays(1, &lightVAO);
	unsigned int VAO;
	glGenVertexArrays(1, &VAO);

	glBindVertexArray(VAO);
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(0);
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
	glEnableVertexAttribArray(1);
	glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
	glEnableVertexAttribArray(2);

	glBindVertexArray(lightVAO);
	glBindBuffer(GL_ARRAY_BUFFER,VBO);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,EBO);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(0);
  • 在绘制的时候,对这两个物体需要进行两次流程,相应的program、VAO、以及绘制图形(比如节点数量等)均不同,需要按照自己的需求来设置。
  • 相应的,对program的uniform操作也各不相同。
  • 此外,另一个重要的地方是,二者的view matrix和projection matri是一样的,因此只需要定义一次而公用,但是model matrix显然是不一样的。
ourShader.use();
ourShader.setVec3("objectColor", 1.0f, 0.5f, 0.31f);
ourShader.setVec3("lightColor", 1.0f, 1.0f, 1.0f);
		
glBindVertexArray(VAO);

glm::mat4 view = camera.ViewMatrix();
ourShader.setMat4("view", glm::value_ptr(view));
glm::mat4 projection = glm::perspective(glm::radians(camera.Fov), (float)SCR_WIDTH/(float)SCR_HEIGHT, 0.1f, 100.0f);
ourShader.setMat4("projection", glm::value_ptr(projection));
for (int i = 0; i != 10; i++)
{
	glm::mat4 model;
	model = glm::translate(model, cubePositions[i]);
	float angle = 20.0f * (i+1);
	model = glm::rotate(model, (float)glfwGetTime() * glm::radians(angle), glm::vec3(0.0f, 1.0f, 1.0f));
	ourShader.setMat4("model", glm::value_ptr(model));
	glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
		}

lightShader.use();
glBindVertexArray(lightVAO);
glm::vec3 lightPos = glm::vec3(0.0f, 1.0f, 0.0f);
glm::mat4 lightModel;
lightModel = glm::translate(lightModel, lightPos);
lightModel = glm::scale(lightModel, glm::vec3(0.2f, 0.2f, 0.2f));
lightShader.setMat4("model", glm::value_ptr(lightModel));
lightShader.setMat4("view", glm::value_ptr(view));
lightShader.setMat4("projection", glm::value_ptr(projection));
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

二、基础光照

1. 冯氏光照模型

  • 环境光+漫反射+镜面反射
  • 对物体的颜色观察结果,是光照与物体的反射率相乘的结果,因此,此处对三种颜色成分的表示实则是对三种光照成分的表示,然后作用在物体反射率上。

2. 环境光照

  • 环境光照是除了直接反射和自发光之外的间接光照的组合,即全局光照,在Phong mpdel中,环境光照被假设为一个常量。这不是一个合理的假设,却是向着全局光照发展的第一步。
  • 此处将环境光表示为一个ambient强度与光源光照的乘积。这个只是为了不要让环境光太强,而不符合现实观感。但是,从能量守恒的角度,这也许是在表示光源中有这样比例的一部分最终以环境光的成分作用,而非全部。
  • 当然,即便如此,环境光是个常量还是不符合实际。

3.漫反射光照

  • 此处认为漫反射在所有出射方向都是一样的,即各向同性。而反射点的能量取决于入射光在此处的radiance,因此,需要将入射光方向与法线方向做内积获得余弦值,然后作用在光照颜色上。
  • 同样的,这也是一个非常简化的表示形式,可见,这个只能描述出入射光对面积的功率分摊现象。
  • 一个需要注意的点是,法向量是节点的属性;此外,法向量不应该发生位移,只会发生旋转和缩放,但是物体model matrix的不对称缩放会破坏法向量,所以,法向量的model matrix需要在物体的model matrix基础上变换得到,具体方法是:先对其求逆,然后求转置,最后只取3x3部分作用在法向量上。

4. 镜面反射

  • 考虑到镜面反射的出射方向相对集中,因此通过反射光与观察方向的余弦来衡量镜面反射的强度。然后,对该余弦项取指数,这是为了让余弦函数快速衰减,避免光晕太大,当然,指数可以调节来达到预期的效果。此外,也给予他一个specularStrength,作为菲涅尔项,尽量保持能量守恒。

5. phong model

#version 330 core

out vec4 fragColor;

in vec3 fragPos;
in vec3 normal;

uniform vec3 lightColor;
uniform vec3 objectColor;
uniform vec3 lightPos;
uniform vec3 viewPos;


void main()
{
	//ambient
	float ambientStrength = 0.1;
	vec3 ambient = ambientStrength*lightColor;
	//diffuse
	vec3 lightDir = normalize(lightPos - fragPos);
	float diff = max(dot(normal,lightDir),0.0);
	vec3 diffuse = diff * lightColor;
	//specular
	float specularStrength = 0.5;
	vec3 reflectDir = normalize(reflect(-lightDir, normal));
	vec3 viewDir = normalize(viewPos - fragPos);
	float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
	vec3 specular = specularStrength*spec*lightColor;

	vec3 result = (ambient + diffuse + specular) * objectColor;
	fragColor = vec4(result,1.0f);
}
#version 330 core
layout(location = 0) in vec3 aPos;
layout(location = 1) in vec3 aColor;
layout(location = 2) in vec2 aCoord;
layout(location = 3) in vec3 aNorm;

out vec3 fragPos;
out vec3 normal;

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

void main()
{
	gl_Position = projection * view * model * vec4(aPos, 1.0f);
	fragPos = vec3(model * vec4(aPos, 1.0f));
	normal = normalize(mat3(normModel) * aNorm);
}
//drawlight
		lightShader.use();

		glBindVertexArray(lightVAO);
		
		glm::vec3 lightPos = glm::vec3(0.0f, 1.0f, 0.0f);
		glm::mat4 lightModel;
		lightModel = glm::translate(lightModel, lightPos);
		lightModel = glm::scale(lightModel, glm::vec3(0.2f, 0.2f, 0.2f));
		lightShader.setMat4("model", glm::value_ptr(lightModel));

		glm::mat4 view = camera.ViewMatrix();
		lightShader.setMat4("view", glm::value_ptr(view));

		glm::mat4 projection = glm::perspective(glm::radians(camera.Fov), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
		lightShader.setMat4("projection", glm::value_ptr(projection));

		glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);

		//drawobject
		cubeShader.use();

		//ourShader.setInt("texture1", 0);
		//ourShader.setInt("texture2", 1);

		cubeShader.setVec3("objectColor", 1.0f, 0.5f, 0.31f);
		cubeShader.setVec3("lightColor", 1.0f, 1.0f, 1.0f);
		cubeShader.setVec3("lightPos", lightPos.x, lightPos.y, lightPos.z);
		cubeShader.setVec3("viewPos", camera.Position.x, camera.Position.y, camera.Position.z);

		glBindVertexArray(VAO);

		float timeValue = (float)glfwGetTime();
		float lightValue = sin(timeValue) / 2.0f + 0.5f;
		cubeShader.setVec4("vexColor", lightValue, lightValue, lightValue, 1.0f);	

		cubeShader.setMat4("view", glm::value_ptr(view));
		cubeShader.setMat4("projection", glm::value_ptr(projection));

		
		for (int i = 0; i != 10; i++)
		{
			glm::mat4 model;
			model = glm::translate(model, cubePositions[i]);
			float angle = 20.0f * (i+1);
			model = glm::rotate(model, (float)glfwGetTime() * glm::radians(angle), glm::vec3(0.0f, 1.0f, 1.0f));
			cubeShader.setMat4("model", glm::value_ptr(model));

			glm::mat4 normModel;
			normModel = glm::transpose(glm::inverse(model));
			cubeShader.setMat4("normModel", glm::value_ptr(normModel));
			
			glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
		}

6.Gouraud Shading

  • 显然的是,一般来说,片段数量要比顶点数量多很多,因此,如果能够将计算量较大的shading部分放在顶点着色器中,计算性能会更好。
  • 但是,如果使用Gouraud Shading,那么片段颜色就是通过顶点颜色插值得到的,那么效果就不会很好。如下。
#version 330 core
layout(location = 0) in vec3 aPos;
layout(location = 1) in vec3 aColor;
layout(location = 2) in vec2 aCoord;
layout(location = 3) in vec3 aNorm;

out vec3 vexColor;

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

uniform vec3 lightColor;
uniform vec3 objectColor;
uniform vec3 lightPos;
uniform vec3 viewPos;

void main()
{
	gl_Position = projection * view * model * vec4(aPos, 1.0f);
	vec3 fragPos = vec3(model * vec4(aPos, 1.0f));
	vec3 normal = normalize(mat3(normModel) * aNorm);

	//ambient
	float ambientStrength = 0.1;
	vec3 ambient = ambientStrength * lightColor;
	//diffuse
	vec3 lightDir = normalize(lightPos - fragPos);
	float diff = max(dot(normal, lightDir), 0.0);
	vec3 diffuse = diff * lightColor;
	//specular
	float specularStrength = 0.5;
	vec3 reflectDir = normalize(reflect(-lightDir, normal));
	vec3 viewDir = normalize(viewPos - fragPos);
	float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
	vec3 specular = specularStrength * spec * lightColor;

	vexColor = (ambient + diffuse + specular) * objectColor;
}
#version 330 core

out vec4 fragColor;

in vec3 vexColor;

void main()
{
	fragColor = vec4(vexColor, 1.0f);
}

三、材质

1. Material Class

  • 之前的模型将三种成分的光照都作用在同一个物体反射率objectColor上,事实上可以将不同光照成分的反射率做区分,来达到更好的材质表达,作为材质的属性,这样可以在不同的通道上做不同的划分,管理更加细粒化。此外,将镜面反射的指数也作为参数。这样一来,就可以用于描述一系列的材质。
  • 使用Material类来将这几个属性组合在一起。相应的,在shader中需要定义该类的uniform变量,并且使用点运算符来访问成员。
  • 在glUniform函数中,需要对每一个成员分别传输,此外,变量的名字也需要使用点运算符获取。

2. Light Class

  • 之前的phong model是将光源颜色直接的交给三种成分,并通过两个strength参数调节不同成分的比重。为了更方便的描述,可以将三种成分的光照表示成不同的vec3,并组成Light类,此外,将shader中用到的LightPos也加入其中。
  • 因此,可以定义一个光源颜色,然后基于此按比例划分不同成分对应的光照,来获得比较好的效果。这样一来,可以改变光照颜色,而三种成分的光照也会自行改变。
#version 330 core

out vec4 fragColor;

in vec3 fragPos;
in vec3 normal;

uniform vec3 objectColor;
uniform vec3 viewPos;

struct Material {
	vec3 ambient;
	vec3 diffuse;
	vec3 specular;
	float shininess;
};
uniform Material material;

struct Light {
	vec3 position;

	vec3 ambient;
	vec3 diffuse;
	vec3 specular;
};
uniform Light light;
  
void main()
{
	//ambient
	vec3 ambient = material.ambient * light.ambient;
	//diffuse
	vec3 lightDir = normalize(light.position - fragPos);
	float diff = max(dot(normal,lightDir),0.0);
	vec3 diffuse = diff * material.diffuse * light.diffuse;
	//specular
	vec3 reflectDir = normalize(reflect(-lightDir, normal));
	vec3 viewDir = normalize(viewPos - fragPos);
	float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
	vec3 specular = spec * material.specular * light.specular;

	vec3 result = (ambient + diffuse + specular) * objectColor;
	fragColor = vec4(result,1.0f);
}

四、光照贴图

  • 之前的材质类型是使用三个分量对应的vec3常量来描述的,那么对于一个物体而言,其整体材质必然缺乏多样性,因此,使用纹理贴图来将材质记录在纹理中。
  • 相应的,需要diffuse与specuar纹理,甚至可以定义ambient纹理,但是必要性不大,直接使用diffuse纹理就可以了,这是将全局光照视作是漫反射的。
  • 因此,修改Material类,将vec3修改为sampler2D,并加入纹理查询。
  • 此外,当然需要加入纹理相关的操作。
#version 330 core

out vec4 fragColor;

in vec3 fragPos;
in vec3 normal;
in vec2 texCoord;

uniform vec3 objectColor;
uniform vec3 viewPos;

struct Material {
	//vec3 ambient;
	sampler2D diffuse;
	sampler2D specular;
	float shininess;
};
uniform Material material;

struct Light {
	vec3 position;

	vec3 ambient;
	vec3 diffuse;
	vec3 specular;
};
uniform Light light;

void main()
{
	//ambient
	vec3 ambient = light.ambient * vec3(texture(material.diffuse, texCoord));
	//diffuse
	vec3 lightDir = normalize(light.position - fragPos);
	float diff = max(dot(normal,lightDir),0.0);
	vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, texCoord));
	//specular
	vec3 reflectDir = normalize(reflect(-lightDir, normal));
	vec3 viewDir = normalize(viewPos - fragPos);
	float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
	vec3 specular = light.specular * spec * vec3(texture(material.specular, texCoord));

	vec3 result = ambient + diffuse + specular;
	fragColor = vec4(result,1.0f);
}
cubeShader.use();
cubeShader.setInt("material.diffuse", 0);
cubeShader.setInt("material.specular", 1);
cubeShader.setFloat("material.shininess", 32.0f);

五、投光物

  • 之前模拟的是点光源,在本文中介绍了定向光、点光源、聚光三种光照。

1. 定向光

  • 定向光没有位置position,但是存在方向direction,因此可以将定向光描述为:
struct DirLight{
  vec3 direction;

  vec3 ambient;
  vec3 diffuse;
  vec3 specular;
};
  • 相应的,在光照计算中,原本的光照方向就不需要计算可以直接得到,当然需要注意光源的direction与反射点的lightDir是相反的。
vec3 calcDirLight(DirLight light, vec3 normal, vec3 viewPos, vec3 fragPos)
{
	//ambient
	vec3 ambient = light.ambient * vec3(texture(material.diffuse, texCoord));
	//diffuse
	vec3 lightDir = normalize(-light.direction);
	float diff = max(dot(normal, lightDir), 0.0);
	vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, texCoord));
	//specular
	vec3 reflectDir = normalize(reflect(-lightDir, normal));
	vec3 viewDir = normalize(viewPos - fragPos);
	float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
	vec3 specular = light.specular * spec * vec3(texture(material.specular, texCoord));

	return  ambient + diffuse + specular;
}

2. 点光源

  • 之前的shader就是点光源的计算,但是有一个位置需要调整,即衰减。实际上,这个衰减指的是intendity的衰减,这是从光源的角度来分析。如果从着色点的角度来看,就是该光源距离着色点越远,那么其占据的立体角就越小,那么光照的贡献就越小,可以看出如果采取采样的方法,即蒙特卡洛积分,那么就不需要计算衰减了。另一方面,可以得到,立体角随着距离变化是平方倍衰减的,所以一般衰减系数也是平方反比的。在此处,额外加入了常数项与一次项。常数项一般取1.0,是为了保证衰减系数attenuation不会大于1.

  • 因此,在之前的基础上,在点光源的类中加入这三个参数。

struct PointLight {
	vec3 position;

	vec3 ambient;
	vec3 diffuse;
	vec3 specular;

	float constant;
	float linear;
	float quadratic;
};

3. 聚光

  • 聚光的特点是只在光源direction方向的一定角度内的圆锥中会被照亮,因此,聚光需要定义direction以及一个边界cutOff,因为计算角度需要先由俩个矢量计算余弦,然后转化,所以直接将其表示为余弦形式,不做转化,恰好余弦是单调的。但是,如果只定义一个边界,那么光照边缘会很锐利,因此再定义一个外边界outerCutOff,在内外边界之中的光照亮度会从(1.0,1.0,1.0)到(0.0,0.0,0.0)做线性插值,并作clamp保持在0~1。
  • 此外,聚光实际上是点光源,因此其应当包含点光源的一切属性,包括衰减:
struct SpotLight {
	vec3 direction;
	vec3 position;

	vec3 ambient;
	vec3 diffuse;
	vec3 specular;

	float cutOff;
	float outerCutOff;
	float constant;
	float linear;
	float quadratic;
};
  • 而在计算方面,只需要在点光源基础上加上一个额外的衰减intensity就可以了。
vec3 calcSpotLight(SpotLight light, vec3 normal, vec3 viewPos, vec3 fragPos)
{

	//ambient
	vec3 ambient = light.ambient * vec3(texture(material.diffuse, texCoord));
	//diffuse
	vec3 lightDir = normalize(light.position - fragPos);
	float diff = max(dot(normal, lightDir), 0.0);
	vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, texCoord));
	//specular
	vec3 reflectDir = normalize(reflect(-lightDir, normal));
	vec3 viewDir = normalize(viewPos - fragPos);
	float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
	vec3 specular = light.specular * spec * vec3(texture(material.specular, texCoord));

	float theta = dot(-lightDir, normalize(light.direction));
	float epsilon = light.cutOff - light.outerCutOff;
	float intensity = clamp((theta - light.outerCutOff) / epsilon, 0.0, 1.0);

	float distance = length(light.position - fragPos);
	float attenuation = 1.0f / (light.constant + light.linear * distance + light.quadratic * distance * distance);

	return (ambient + diffuse + specular) * intensity * attenuation;
}

4. 集成所有光源

#version 330 core

out vec4 fragColor;

in vec3 fragPos;
in vec3 normal;
in vec2 texCoord;

uniform vec3 objectColor;
uniform vec3 viewPos;

struct Material {
	//vec3 ambient;
	sampler2D diffuse;
	sampler2D specular;
	float shininess;
};
uniform Material material;

struct DirLight {
	vec3 direction;

	vec3 ambient;
	vec3 diffuse;
	vec3 specular;
};
uniform DirLight dirlight;

struct PointLight {
	vec3 position;

	vec3 ambient;
	vec3 diffuse;
	vec3 specular;

	float constant;
	float linear;
	float quadratic;
};
#define NR_POINT_LIGHTS 4
uniform PointLight pointlights[NR_POINT_LIGHTS];

struct SpotLight {
	vec3 direction;
	vec3 position;

	vec3 ambient;
	vec3 diffuse;
	vec3 specular;

	float cutOff;
	float outerCutOff;
	float constant;
	float linear;
	float quadratic;
};
uniform SpotLight spotlight;

vec3 calcDirLight(DirLight light, vec3 normal, vec3 viewPos, vec3 fragPos);
vec3 calcSpotLight(SpotLight light, vec3 normal, vec3 viewPos, vec3 fragPos);
vec3 calcPointLight(PointLight light, vec3 normal, vec3 viewPos, vec3 fragPos);

void main()
{
	vec3 result = calcDirLight(dirlight, normal, viewPos, fragPos);
	
	for (int i = 0; i != NR_POINT_LIGHTS; i++)
	{
		result += calcPointLight(pointlights[i], normal, viewPos, fragPos);
	}
	
	result += calcSpotLight(spotlight,  normal, viewPos, fragPos);
	
	fragColor = vec4(result,1.0f);
}

vec3 calcDirLight(DirLight light, vec3 normal, vec3 viewPos, vec3 fragPos)
{
	//ambient
	vec3 ambient = light.ambient * vec3(texture(material.diffuse, texCoord));
	//diffuse
	vec3 lightDir = normalize(-light.direction);
	float diff = max(dot(normal, lightDir), 0.0);
	vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, texCoord));
	//specular
	vec3 reflectDir = normalize(reflect(-lightDir, normal));
	vec3 viewDir = normalize(viewPos - fragPos);
	float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
	vec3 specular = light.specular * spec * vec3(texture(material.specular, texCoord));

	return  ambient + diffuse + specular;
}

vec3 calcPointLight(PointLight light, vec3 normal, vec3 viewPos, vec3 fragPos)
{
	float distance = length(light.position - fragPos);
	float attenuation = 1.0f / (light.constant + light.linear * distance + light.quadratic * distance * distance);
	//ambient
	vec3 ambient = light.ambient * vec3(texture(material.diffuse, texCoord));
	//diffuse
	vec3 lightDir = normalize(light.position - fragPos);
	float diff = max(dot(normal, lightDir), 0.0);
	vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, texCoord));
	//specular
	vec3 reflectDir = normalize(reflect(-lightDir, normal));
	vec3 viewDir = normalize(viewPos - fragPos);
	float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
	vec3 specular = light.specular * spec * vec3(texture(material.specular, texCoord));

	return (ambient + diffuse + specular) * attenuation;
}

vec3 calcSpotLight(SpotLight light, vec3 normal, vec3 viewPos, vec3 fragPos)
{

	//ambient
	vec3 ambient = light.ambient * vec3(texture(material.diffuse, texCoord));
	//diffuse
	vec3 lightDir = normalize(light.position - fragPos);
	float diff = max(dot(normal, lightDir), 0.0);
	vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, texCoord));
	//specular
	vec3 reflectDir = normalize(reflect(-lightDir, normal));
	vec3 viewDir = normalize(viewPos - fragPos);
	float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
	vec3 specular = light.specular * spec * vec3(texture(material.specular, texCoord));

	float theta = dot(-lightDir, normalize(light.direction));
	float epsilon = light.cutOff - light.outerCutOff;
	float intensity = clamp((theta - light.outerCutOff) / epsilon, 0.0, 1.0);

	float distance = length(light.position - fragPos);
	float attenuation = 1.0f / (light.constant + light.linear * distance + light.quadratic * distance * distance);

	return (ambient + diffuse + specular) * intensity * attenuation;
}
		lightShader.use();

		glBindVertexArray(lightVAO);
		
		glm::vec3 lightColor;
		lightColor.x = sin((float)glfwGetTime() * 2.0f);
		lightColor.y = sin((float)glfwGetTime() * 0.7f);
		lightColor.z = sin((float)glfwGetTime() * 1.3f);
		lightShader.setVec3("lightColor", lightColor);

		glm::mat4 view = camera.ViewMatrix();
		lightShader.setMat4("view", glm::value_ptr(view));

		glm::mat4 projection = glm::perspective(glm::radians(camera.Fov), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
		lightShader.setMat4("projection", glm::value_ptr(projection));

		for (int i = 0; i != 4; i++)
		{
			glm::mat4 lightModel;
			lightModel = glm::translate(lightModel, pointLightPositions[i]);
			lightModel = glm::scale(lightModel, glm::vec3(0.2f, 0.2f, 0.2f));
			lightShader.setMat4("model", glm::value_ptr(lightModel));

			glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
		}
		

		//drawobject
		cubeShader.use();

		cubeShader.setInt("material.diffuse", 0);
		cubeShader.setInt("material.specular", 1);
		cubeShader.setFloat("material.shininess", 32.0f);

		cubeShader.setVec3("objectColor", 1.0f, 0.5f, 0.31f);
		cubeShader.setVec3("viewPos", camera.Position);

		glm::vec3 diffuseColor = lightColor * glm::vec3(0.5f); // 降低影响
		glm::vec3 ambientColor = diffuseColor * glm::vec3(0.2f); // 很低的影响
		glm::vec3 specularColor = glm::vec3(1.0f, 1.0f, 1.0f);

		cubeShader.setVec3("dirlight.ambient", 0.05f, 0.05f, 0.05f);
		cubeShader.setVec3("dirlight.diffuse", 0.4f, 0.4f, 0.4f);
		cubeShader.setVec3("dirlight.specular", 0.5f, 0.5f, 0.5f);
		cubeShader.setVec3("dirlight.direction", -0.2f, -1.0f, -0.3f);
		cubeShader.setVec3("pointlights[0].ambient", ambientColor);
		cubeShader.setVec3("pointlights[0].diffuse", diffuseColor);
		cubeShader.setVec3("pointlights[0].specular", specularColor);
		cubeShader.setVec3("pointlights[0].position", pointLightPositions[0]);
		cubeShader.setFloat("pointlights[0].constant", 1.0f);
		cubeShader.setFloat("pointlights[0].linear", 0.09f);
		cubeShader.setFloat("pointlights[0].quadratic", 0.032f);
		cubeShader.setVec3("pointlights[1].ambient", ambientColor);
		cubeShader.setVec3("pointlights[1].diffuse", diffuseColor);
		cubeShader.setVec3("pointlights[1].specular", specularColor);
		cubeShader.setVec3("pointlights[1].position", pointLightPositions[1]);
		cubeShader.setFloat("pointlights[1].constant", 1.0f);
		cubeShader.setFloat("pointlights[1].linear", 0.09f);
		cubeShader.setFloat("pointlights[1].quadratic", 0.032f);
		cubeShader.setVec3("pointlights[2].ambient", ambientColor);
		cubeShader.setVec3("pointlights[2].diffuse", diffuseColor);
		cubeShader.setVec3("pointlights[2].specular", specularColor);
		cubeShader.setVec3("pointlights[2].position", pointLightPositions[2]);
		cubeShader.setFloat("pointlights[2].constant", 1.0f);
		cubeShader.setFloat("pointlights[2].linear", 0.09f);
		cubeShader.setFloat("pointlights[2].quadratic", 0.032f);
		cubeShader.setVec3("pointlights[3].ambient", ambientColor);
		cubeShader.setVec3("pointlights[3].diffuse", diffuseColor);
		cubeShader.setVec3("pointlights[3].specular", specularColor);
		cubeShader.setVec3("pointlights[3].position", pointLightPositions[3]);
		cubeShader.setFloat("pointlights[3].constant", 1.0f);
		cubeShader.setFloat("pointlights[3].linear", 0.09f);
		cubeShader.setFloat("pointlights[3].quadratic", 0.032f);
		cubeShader.setVec3("spotlight.ambient", 0.0f, 0.0f, 0.0f);
		cubeShader.setVec3("spotlight.diffuse", 1.0f, 1.0f, 1.0f);
		cubeShader.setVec3("spotlight.specular", 1.0f, 1.0f, 1.0f);
		cubeShader.setVec3("spotlight.direction", camera.Front);
		cubeShader.setVec3("spotlight.position", camera.Position);
		cubeShader.setFloat("spotlight.cutOff", glm::cos(glm::radians(12.5f)));
		cubeShader.setFloat("spotlight.outerCutOff", glm::cos(glm::radians(15.0f)));
		cubeShader.setFloat("spotlight.constant", 1.0f);
		cubeShader.setFloat("spotlight.linear", 0.09f);
		cubeShader.setFloat("spotlight.quadratic", 0.032f);

		glBindVertexArray(VAO);

		float timeValue = (float)glfwGetTime();
		float lightValue = sin(timeValue) / 2.0f + 0.5f;
		cubeShader.setVec4("vexColor", lightValue, lightValue, lightValue, 1.0f);	

		cubeShader.setMat4("view", glm::value_ptr(view));
		cubeShader.setMat4("projection", glm::value_ptr(projection));

		
		for (int i = 0; i != 10; i++)
		{
			glm::mat4 model;
			model = glm::translate(model, cubePositions[i]);
			float angle = 20.0f * (i+1);
			model = glm::rotate(model, (float)glfwGetTime() * glm::radians(angle), glm::vec3(0.0f, 1.0f, 1.0f));
			cubeShader.setMat4("model", glm::value_ptr(model));

			glm::mat4 normModel;
			normModel = glm::transpose(glm::inverse(model));
			cubeShader.setMat4("normModel", glm::value_ptr(normModel));
			
			glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
		}
  • 画一下:
posted @   ETHERovo  阅读(24)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示