Computer Graphics (5): OpenGL Lighting

reference

Introduction
Lighting in the real world is extremely complex and difficult to calculate, so OpenGL's lighting uses a simplified model, one of which is called the Phong Lighting Model.

The main structure of the Phong lighting model consists of three components:

Ambient Lighting
Diffuse Lighting
Specular Lighting

ambient light

One of the characteristics of light is that it can diverge and bounce in many directions, so there is usually some light around the real environment, and the corresponding objects usually reflect some faint light.
calculate:

Multiply the color of the light by a very small component, and finally the color of the object

diffuse lighting

Diffuse lighting makes the fragments closer to the object and the light direction get more brightness from the light source.

image.png

If the light is perpendicular to the surface of the object, the impact of the light on the object will be maximized (Annotation: brighter).

can be roughly understood as

Diffuse lighting of the fragment = (the angle between the vector from the light source coordinates to the fragment coordinates and the normal vector of the fragment) * light source color

Note that both vectors must be normalized first.
In order to calculate diffuse lighting we need to know these values:

The normal vector of the face of the fragment
The world coordinates of the light source
The world coordinates of the fragment
Finally, the current color of the fragment is: (ambient light value + diffuse light value) * the color of the fragment itself

specular lighting

Specular lighting depends on the reflective properties of the surface. If we think of the surface of an object as a mirror, then the place where the specular light is strongest is where we see light reflected from the surface. As shown below:

image.png

For this we also need an observer coordinate (i.e. the camera). The smaller the angle between the light reflection vector and the viewing direction, the stronger the specular lighting effect.

Final effect:
insert image description here
insert image description here
main code:

std::vector<float> sphereVertices;
	std::vector<int> sphereIndices;


	// 生成球的顶点
	for (int y = 0; y <= Y_SEGMENTS; y++)
	{
    
    
		for (int x = 0; x <= X_SEGMENTS; x++)
		{
    
    
			float xSegment = (float)x / (float)X_SEGMENTS;
			float ySegment = (float)y / (float)Y_SEGMENTS;
			float xPos = std::cos(xSegment * 2.0f * PI) * std::sin(ySegment * PI);
			float yPos = std::cos(ySegment * PI);
			float zPos = std::sin(xSegment * 2.0f * PI) * std::sin(ySegment * PI);


			sphereVertices.push_back(xPos);
			sphereVertices.push_back(yPos);
			sphereVertices.push_back(zPos);
		}
	}

	// 生成球的Indices
	for (int i = 0; i < Y_SEGMENTS; i++)
	{
    
    
		for (int j = 0; j < X_SEGMENTS; j++)
		{
    
    

			sphereIndices.push_back(i * (X_SEGMENTS + 1) + j);
			sphereIndices.push_back((i + 1) * (X_SEGMENTS + 1) + j);
			sphereIndices.push_back((i + 1) * (X_SEGMENTS + 1) + j + 1);

			sphereIndices.push_back(i * (X_SEGMENTS + 1) + j);
			sphereIndices.push_back((i + 1) * (X_SEGMENTS + 1) + j + 1);
			sphereIndices.push_back(i * (X_SEGMENTS + 1) + j + 1);
		}
	}

	float cube[] = {
    
    
		-0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,
		 0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,
		 0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,
		 0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,
		-0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,
		-0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,

		-0.5f, -0.5f,  0.5f,  0.0f,  0.0f,  1.0f,
		 0.5f, -0.5f,  0.5f,  0.0f,  0.0f,  1.0f,
		 0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,
		 0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,
		-0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,
		-0.5f, -0.5f,  0.5f,  0.0f,  0.0f,  1.0f,

		-0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,
		-0.5f,  0.5f, -0.5f, -1.0f,  0.0f,  0.0f,
		-0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,
		-0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,
		-0.5f, -0.5f,  0.5f, -1.0f,  0.0f,  0.0f,
		-0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,

		 0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,
		 0.5f,  0.5f, -0.5f,  1.0f,  0.0f,  0.0f,
		 0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,
		 0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,
		 0.5f, -0.5f,  0.5f,  1.0f,  0.0f,  0.0f,
		 0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,

		-0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,
		 0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,
		 0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,
		 0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,
		-0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,
		-0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,

		-0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,
		 0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,
		 0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,
		 0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,
		-0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,
		-0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f
	};
	//sphere---light
	glBindVertexArray(VAO[2]);
	glBindBuffer(GL_ARRAY_BUFFER, VBO[2]);
	glBufferData(GL_ARRAY_BUFFER, sphereVertices.size() * sizeof(float), &sphereVertices[0], GL_STATIC_DRAW);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); 
	glEnableVertexAttribArray(0);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO[2]);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sphereIndices.size() * sizeof(int), &sphereIndices[0], GL_STATIC_DRAW);

	//cube
	glBindVertexArray(VAO[3]);
	glBindBuffer(GL_ARRAY_BUFFER, VBO[3]);
	glBufferData(GL_ARRAY_BUFFER, sizeof(cube), cube, GL_STATIC_DRAW);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(0);
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
	glEnableVertexAttribArray(1);

Bind information every time you render:

//让光源绕原点旋转
	float distance = 2.0f;
	float lightY = sin(glfwGetTime()) * distance;
	float lightZ = -(cos(glfwGetTime()) * distance);
	float lightX = sin(glfwGetTime()) * distance;
	//lightPos.x = lightX; lightPos.y = 1; lightPos.z = 1.2;						//直线移动
	lightPos.x = lightX; lightPos.y = lightY; lightPos.z = lightZ;			//环绕移动

	shader.use();
	model = glm::mat4(1.0f);
	shader.setMat4("model", model);
	shader.setMat4("projection", projection);
	shader.setMat4("view", view);
	shader.setVec3("objectColor", 1.0f, 0.5f, 0.31f);
	shader.setVec3("lightColor", 1.0f, 1.0f, 1.0f);
	shader.setVec3("lightPos", lightPos);
	shader.setVec3("viewPos", camera.position);
	glBindVertexArray(VAO[3]);
	glDrawArrays(GL_TRIANGLES, 0, 36);
	glBindVertexArray(0);


	light_shader.use();
	model = glm::mat4(1.0f);
	model = glm::translate(model, lightPos);
	model = glm::scale(model, glm::vec3(0.1f));
	light_shader.setMat4("model", model);
	light_shader.setMat4("projection", projection);
	light_shader.setMat4("view", view);
	glBindVertexArray(VAO[2]);
	glDrawElements(GL_TRIANGLES, X_SEGMENTS * Y_SEGMENTS * 6, GL_UNSIGNED_INT, 0);
	//glDrawArrays(GL_TRIANGLES, 0, 36);
	glBindVertexArray(0);

Vertex shader:

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;

out vec3 FragPos;
out vec3 Normal;

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

void main()
{
    
    
    FragPos = vec3(model * vec4(aPos, 1.0));
    mat3 normalMatrix = mat3(transpose(inverse(model)));
	Normal = normalMatrix * aNormal; // 计算法向量经过模型变换后值

    
    gl_Position = projection * view * vec4(FragPos, 1.0);
}

Fragment shader:

#version 330 core
out vec4 FragColor;

in vec3 Normal;  
in vec3 FragPos;  
  
uniform vec3 lightPos; 
uniform vec3 lightColor;
uniform vec3 objectColor;
uniform vec3 viewPos; 

void main()
{
    
    
    // ambient
    float ambientStrength = 0.1;
    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;

    // specular
    float specularStrength = 0.5;
    vec3 viewDir = normalize(viewPos - FragPos);
    vec3 reflectDir = reflect(-lightDir, norm);  
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
    vec3 specular = specularStrength * spec * lightColor; 
    
    //距离影响光照强度,暂时是我自己想的
	float enableDistance = 4.0f;	//有效光照距离
	vec3 light2fragVec = lightPos - vec3(FragPos);
	float distan = min(sqrt(light2fragVec.x * light2fragVec.x + light2fragVec.y * light2fragVec.y + light2fragVec.z * light2fragVec.z), enableDistance);
	float strength = 1 - distan / enableDistance;
            
    //光照远近先不影响环境光照了
    vec3 result = ambient*objectColor+(diffuse + specular) * objectColor*strength;
    FragColor = vec4(result, 1.0);
} 

Vertex shader for the light source:

#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);
}

The fragment shader for the light source:

#version 330 core
out vec4 FragColor;

void main()
{
    
    
    FragColor = vec4(1.0); // set all 4 vector values to 1.0
}

Guess you like

Origin blog.csdn.net/qq_51684393/article/details/130250981