learnOpenGL-Light object

Directional light: Each ray of light from a wirelessly distant light source is nearly parallel.
It is necessary to define the direction starting from the light source. But the calculation uses the direction from the fragment to the light source.

Point light: diffuses light in all directions from one location.
The attenuation of light needs to be calculated based on distance. To define constant, linear, and quadratic, set three parameters as parameters of the attenuation formula. And the position of the light source

Spotlight: A light source located somewhere in the environment that shines in only one direction. For example, flashlights and street lights
need to define the position of the light source, the direction of the light, and the lighting angle cutOff. Calculate LightDir based on this: the direction in which the fragment points to the light source, the direction in which SpotDir condenses the light, the cutting angle of the Phiϕ focusing radius, the angle between the Thetaθ focusing direction SpotDir and the fragment and the light source direction LightDir. Only when θ is smaller than φ will it be illuminated by spotlight.
The cut-off angle will be divided into the internal cut-off angle cutOff and the external cut-off angle outerCutOff. Calculate the brightness using a formula to smooth the edges of the spotlight.

main.cpp

#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include "shader.h"
#include "stb_image.h"
#include <glm.hpp>
#include <gtc/matrix_transform.hpp>
#include <gtc/type_ptr.hpp>
#include "Camera.h"

GLfloat vertices[] = {
    
    
	// positions          // normals           // texture coords
   -0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  0.0f, 0.0f,
	0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  1.0f, 0.0f,
	0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  1.0f, 1.0f,
	0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  1.0f, 1.0f,
   -0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  0.0f, 1.0f,
   -0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  0.0f, 0.0f,

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

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

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

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

   -0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,  0.0f, 1.0f,
	0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,  1.0f, 1.0f,
	0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,  1.0f, 0.0f,
	0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,  1.0f, 0.0f,
   -0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,  0.0f, 0.0f,
   -0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,  0.0f, 1.0f
};

Camera* myCamera = new Camera(glm::vec3(0.0f, 0.0f, 3.0f), glm::vec3(0.0f, 0.0f, -1.0f), glm::vec3(0.0f, 1.0f, 0.0f));

void mouse_callback(GLFWwindow* window, double xpos, double ypos) {
    
    
	myCamera->mouseCb(xpos, ypos);
};

void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{
    
    
	myCamera->scrollCb(xoffset, yoffset);
}

GLfloat deltaTime = 0.0f;
GLfloat lastFrame = 0.0f;

void processInput(GLFWwindow* window) {
    
    
	GLfloat currentFrame = glfwGetTime();
	deltaTime = currentFrame - lastFrame;
	lastFrame = currentFrame;
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
		glfwSetWindowShouldClose(window, true);
	if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) {
    
    
		myCamera->pressKeyW(deltaTime);
	}
	if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) {
    
    
		myCamera->pressKeyS(deltaTime);
	}
	if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) {
    
    
		myCamera->pressKeyA(deltaTime);
	}
	if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) {
    
    
		myCamera->pressKeyD(deltaTime);
	}
}

glm::vec3 cubePositions[] = {
    
    
  glm::vec3(0.0f,  0.0f,  0.0f),
  glm::vec3(2.0f,  5.0f, -15.0f),
  glm::vec3(-1.5f, -2.2f, -2.5f),
  glm::vec3(-3.8f, -2.0f, -12.3f),
  glm::vec3(2.4f, -0.4f, -3.5f),
  glm::vec3(-1.7f,  3.0f, -7.5f),
  glm::vec3(1.3f, -2.0f, -2.5f),
  glm::vec3(1.5f,  2.0f, -2.5f),
  glm::vec3(1.5f,  0.2f, -1.5f),
  glm::vec3(-1.3f,  1.0f, -1.5f)
};


glm::vec3 lightPos(1.2f, 1.0f, 2.0f);//声明全局变量表示光源在场景的坐标

int main()
{
    
    
	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);

	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

	GLFWwindow* window = glfwCreateWindow(800, 600, "test", nullptr, nullptr);
	if (window == nullptr)
	{
    
    
		std::cout << "Failed to create GLFW window" << std::endl;
		glfwTerminate();
		return -1;
	}
	glfwMakeContextCurrent(window);

	//glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);

	glfwSetCursorPosCallback(window, mouse_callback);
	glfwSetScrollCallback(window, scroll_callback);

	glewExperimental = GL_TRUE;
	if (glewInit() != GLEW_OK)
	{
    
    
		std::cout << "Failed to initialize GLEW" << std::endl;
		glfwTerminate();
		return -1;
	}

	glViewport(0, 0, 800, 600);

	GLuint VAO;
	glGenVertexArrays(1, &VAO);
	glBindVertexArray(VAO);

	GLuint VBO;
	glGenBuffers(1, &VBO);
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0);
	glEnableVertexAttribArray(0);
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3* sizeof(GLfloat)));
	glEnableVertexAttribArray(1);
	glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat)));
	glEnableVertexAttribArray(2);

	GLuint lightVAO;
	glGenVertexArrays(1, &lightVAO);
	glBindVertexArray(lightVAO);
	// 只需要绑定VBO不用再次设置VBO的数据,因为容器(物体)的VBO数据中已经包含了正确的立方体顶点数据
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0);
	glEnableVertexAttribArray(0);

	glBindVertexArray(0);

	int width, height;
	unsigned char* image = stbi_load("container2.png", &width, &height, 0, 0);
	GLuint tex;
	glGenTextures(1, &tex);
	glBindTexture(GL_TEXTURE_2D, tex);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
	glGenerateMipmap(GL_TEXTURE_2D);

	unsigned char* image1 = stbi_load("container2_specular.png", &width, &height, 0, 0);
	GLuint tex1;
	glGenTextures(1, &tex1);
	glActiveTexture(GL_TEXTURE1);
	glBindTexture(GL_TEXTURE_2D, tex1);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image1);
	glGenerateMipmap(GL_TEXTURE_2D);

	glm::mat4 model;
	glm::mat4 view;
	glm::mat4 projection;

	glEnable(GL_DEPTH_TEST);

	Shader* testShader = new Shader("test.vert", "test.frag");

	glm::vec3 lightColor(0.33f, 0.42f, 0.18f);
	glm::vec3 toyColor(1.0f, 0.5f, 0.31f);
	glm::vec3 result = lightColor * toyColor; // = (0.33f, 0.21f, 0.06f);

	//保持灯不受其他光照影响一直明亮,创建另外一套着色器。
	Shader* lightShader = new Shader("test.vert", "light.frag");

	while (!glfwWindowShouldClose(window))
	{
    
    
		processInput(window);
		glfwPollEvents();

		glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT);

		testShader->Use();

		glActiveTexture(GL_TEXTURE0);
		glBindTexture(GL_TEXTURE_2D, tex);
		glUniform1i(glGetUniformLocation(testShader->getProgram(), "material.diffuse"), 0);

		glActiveTexture(GL_TEXTURE1);
		glBindTexture(GL_TEXTURE_2D, tex1);
		glUniform1i(glGetUniformLocation(testShader->getProgram(), "material.specular"), 1);
		glUniform1f(glGetUniformLocation(testShader->getProgram(), "material.shininess"), 32.0f);

		glUniform3f(glGetUniformLocation(testShader->getProgram(), "objectColor"), 1.0f, 0.5f, 0.31f);// 设置物体颜色珊瑚红
		glUniform3f(glGetUniformLocation(testShader->getProgram(), "lightColor"), 1.0f, 1.0f, 1.0f); // 把光源设置为白色

		view = myCamera->getViewMat4();
		glUniformMatrix4fv(glGetUniformLocation(testShader->getProgram(), "view"), 1, GL_FALSE, glm::value_ptr(view));

		projection = glm::perspective(glm::radians(myCamera->getFov()), 800.0f / 600.0f, 0.1f, 100.0f);
		glUniformMatrix4fv(glGetUniformLocation(testShader->getProgram(), "projection"), 1, GL_FALSE, glm::value_ptr(projection));

		//定向光
		//glUniform3f(glGetUniformLocation(testShader->getProgram(), "light.direction"), -0.2f, -1.0f, -0.3f);
		//点光源
		/*glUniform1f(glGetUniformLocation(testShader->getProgram(), "light.constant"), 1.0f);
		glUniform1f(glGetUniformLocation(testShader->getProgram(), "light.linear"), 0.09);
		glUniform1f(glGetUniformLocation(testShader->getProgram(), "light.quadratic"), 0.032);*/
		//聚光
		glm::vec3 cameraFront = myCamera->getCameraPos();
		glUniform3f(glGetUniformLocation(testShader->getProgram(), "light.direction"), cameraFront.x, cameraFront.y, cameraFront.z);
		glUniform1f(glGetUniformLocation(testShader->getProgram(), "light.cutOff"), glm::cos(glm::radians(12.5f)));
		glUniform1f(glGetUniformLocation(testShader->getProgram(), "light.outerCutOff"), glm::cos(glm::radians(17.5f)));

		glUniform3f(glGetUniformLocation(testShader->getProgram(), "light.position"), lightPos.x, lightPos.y, lightPos.z);

		glUniform3f(glGetUniformLocation(testShader->getProgram(), "light.ambient"), 0.1f, 0.1f, 0.1f);
		glUniform3f(glGetUniformLocation(testShader->getProgram(), "light.diffuse"), 0.8f, 0.8f, 0.8f);
		glUniform3f(glGetUniformLocation(testShader->getProgram(), "light.specular"), 1.0f, 1.0f, 1.0f);

		glUniform1f(glGetUniformLocation(testShader->getProgram(), "light.constant"), 1.0f);
		glUniform1f(glGetUniformLocation(testShader->getProgram(), "light.linear"), 0.09);
		glUniform1f(glGetUniformLocation(testShader->getProgram(), "light.quadratic"), 0.032);

		glm::vec3 viewPos = myCamera->getCameraPos();
		glUniform3f(glGetUniformLocation(testShader->getProgram(), "viewPos"), viewPos.x, viewPos.y, viewPos.z);

		glBindVertexArray(VAO);
		for (GLuint i = 0; i < 10; i++)
		{
    
    
			model = glm::mat4();
			model = glm::translate(model, cubePositions[i]);
			GLfloat angle = 20.0f * i;
			model = glm::rotate(model, angle, glm::vec3(1.0f, 0.3f, 0.5f));
			glUniformMatrix4fv(glGetUniformLocation(testShader->getProgram(), "model"), 1, GL_FALSE, glm::value_ptr(model));
			glDrawArrays(GL_TRIANGLES, 0, 36);
		}

		glBindVertexArray(lightVAO);

		//平移灯源位置到lightPos
		model = glm::mat4();
		model = glm::translate(model, lightPos);
		model = glm::scale(model, glm::vec3(0.2f));
		lightShader->Use();
		glUniformMatrix4fv(glGetUniformLocation(lightShader->getProgram(), "model"), 1, GL_FALSE, glm::value_ptr(model));
		glUniformMatrix4fv(glGetUniformLocation(lightShader->getProgram(), "view"), 1, GL_FALSE, glm::value_ptr(view));
		glUniformMatrix4fv(glGetUniformLocation(lightShader->getProgram(), "projection"), 1, GL_FALSE, glm::value_ptr(projection));
		// 绘制灯立方体对象
		glDrawArrays(GL_TRIANGLES, 0, 36);


		glBindVertexArray(0);

		glfwSwapBuffers(window);
	}


	glfwTerminate();
	return 0;
}

vertex shader

#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal; //面的法向量
layout (location = 2) in vec2 texCoords;

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

out vec3 Normal;
out vec3 FragPos; //片段位置
out vec2 TexCoords;

void main()
{
    
    
    gl_Position = projection * view * model * vec4(position, 1.0);
    FragPos = vec3(model * vec4(position, 1.0f));
    Normal = mat3(transpose(inverse(model))) * normal;
    TexCoords = texCoords;
}

fragment shader

#version 330 core
out vec4 color;

in vec3 Normal;
in vec3 FragPos;

uniform vec3 objectColor;
uniform vec3 lightColor;

//物体的材质属性
struct Material
{
    
    
    sampler2D diffuse; 
    sampler2D specular;
    float shininess;
};

uniform Material material;
uniform vec3 viewPos;

in vec2 TexCoords;

/* 定向光
//光的属性
struct Light
{
    //vec3 position; //投光不需要光的位置,因为光的位置无线远,所有光线当作平行线处理
    vec3 direction; //定向光,以光源为起点的向量
    vec3 ambient;
    vec3 diffuse; 
    vec3 specular;
};*/

/* 
//点光源,定向衰减
struct Light
{
    vec3 position;
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
    float constant;
    float linear;
    float quadratic;
}; */

//聚光,位于环境某处的光源,不向所有方向照射,只朝某个方向,只有一定照射方向的确定半径内的物品才被照亮。(路灯/手电筒)
struct Light
{
    
    
    vec3 position;
    vec3 direction;
    float cutOff; //切光角
    float outerCutOff; //外切角
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
    float constant;
    float linear;
    float quadratic;
};

uniform Light light;

void main()
{
    
    
    //vec3 lightDir = normalize(-light.direction); 定向光
    vec3 lightDir = normalize(light.position - FragPos);

    float theta = dot(lightDir, normalize(light.direction));

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

    /*if(theta > light.cutOff) //90°以内,cos余弦值越大,夹角越小
    {
        // 执行光照计算

        vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords));

        vec3 norm = normalize(Normal);
        
        float diff = max(dot(norm, lightDir), 0.0);
        vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords));

        vec3 viewDir = normalize(viewPos - FragPos);
        vec3 reflectDir = reflect(-lightDir, norm);  
        float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
        vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords));  

        float distance = length(light.position - FragPos);//光源的距离
        float attenuation = 1.0f / (light.constant + light.linear*distance +light.quadratic*(distance*distance));

        //多个光源的时候,ambient会开始叠加,这时一般也要衰减,看具体效果
        //vec3 result = ambient + diffuse + specular;
        //result = result * attenuation;

        diffuse  *= attenuation;
        specular *= attenuation;   
                
        color = vec4(ambient + diffuse + specular, 1.0f);
    }
    else // 否则使用环境光,使得场景不至于完全黑暗
        color = vec4(light.ambient*vec3(texture(material.diffuse,TexCoords)), 1.0f);*/

    vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords));

    vec3 norm = normalize(Normal);
        
    float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords));

    vec3 viewDir = normalize(viewPos - FragPos);
    vec3 reflectDir = reflect(-lightDir, norm);  
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
    vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords));  

    float distance = length(light.position - FragPos);//光源的距离
    float attenuation = 1.0f / (light.constant + light.linear*distance +light.quadratic*(distance*distance));

    //多个光源的时候,ambient会开始叠加,这时一般也要衰减,看具体效果
    //vec3 result = ambient + diffuse + specular;
    //result = result * attenuation;

    diffuse  *= attenuation;
    specular *= attenuation;
    diffuse  *= intensity;
    specular *= intensity;
                
    color = vec4(ambient + diffuse + specular, 1.0f);
}

Guess you like

Origin blog.csdn.net/Mhypnos/article/details/130724346