这一章是对前面所学光线的总结

//MultipleLights
#include "Shader.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <iostream>void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void processInput(GLFWwindow* window);
glm::vec3 camera(glm::vec3(0.0f, 0.0f, 3.0f));
// settings
const unsigned int SCR_WIDTH = 800; //定义屏幕空间的大小
const unsigned int SCR_HEIGHT = 600;// camera
glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f);
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);bool firstMouse = true;
float yaw = -90.0f;    // 偏航初始化为-90.0度,因为偏航为0.0会导致指向右边的方向向量,所以我们最初向左旋转了一点。
float pitch = 0.0f; //初始化俯仰角
float lastX = 800.0f / 2.0;//为了把初始位置设置为屏幕中心所以取屏幕空间大小的一半
float lastY = 600.0 / 2.0;
float fov = 45.0f;//初始的视场角// timing
float deltaTime = 0.0f;    // time between current frame and last frame
float lastFrame = 0.0f;
glm::vec3 lightPos(1.2f, 1.0f, 2.0f);
//glm::vec3 lightPos(1.2f, 1.0f, 2.0f);void processInput(GLFWwindow* window);glm::vec3 pointLightPositions[] = {glm::vec3(0.7f,  0.2f,  2.0f),glm::vec3(2.3f, -3.3f, -4.0f),glm::vec3(-4.0f,  2.0f, -12.0f),glm::vec3(0.0f,  0.0f, -3.0f)
};float 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
};
//定义一个vec3类型的数组来存位移矩阵
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),};
int main()
{//Glfw:初始化和配置// ------------------------------glfwInit();glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);#ifdef __APPLE__glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif//glfw窗口创建// --------------------GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);//使用定义的屏幕空间的大小if (window == NULL){std::cout << "Failed to create GLFW window" << std::endl;glfwTerminate();return -1;}glfwMakeContextCurrent(window);glfwSetCursorPosCallback(window, mouse_callback);glfwSetScrollCallback(window, scroll_callback);//首先我们要告诉GLFW,它应该隐藏光标,并捕捉(Capture)它。glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);//加载所有OpenGL函数指针// ---------------------------------------if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){std::cout << "Failed to initialize GLAD" << std::endl;return -1;}// 配置全局opengl状态// -----------------------------glEnable(GL_DEPTH_TEST);// 构建并编译我们的shader程序// ------------------------------------Shader ourShader("shaderSampler.vs", "shaderSampler.fs");Shader modelShader("MultipleLights.vs", "MultipleLights.fs");Shader lightShader("lightShader.vs", "lightShader.fs");//建立和编译顶点数据(和缓冲区),配置顶点属性  // ------------------------------------------------------------------unsigned int VBO, VAO, VAO2;glGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);glBindBuffer(GL_ARRAY_BUFFER, VBO);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);glBindVertexArray(VAO);//位置属性glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);glEnableVertexAttribArray(0);//之后在顶点着色器layout (location = 1) in vec3 aNormal;//告诉GPU位置1的属性glGenVertexArrays(1, &VAO2);glBindVertexArray(VAO2);//glBindBuffer(GL_ARRAY_BUFFER, VBO);//位置属性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, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));glEnableVertexAttribArray(2);// 加载并创建一个纹理// -------------------------unsigned int texture1, texture2;// texture 1// ---------glGenTextures(1, &texture1);glBindTexture(GL_TEXTURE_2D, texture1);// 设置纹理wrapping参数 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);// 设置纹理filtering参数 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);//加载图像,创建纹理和生成mipmaps  //多级原理纹理int width, height, nrChannels;stbi_set_flip_vertically_on_load(true); // 告诉stb_image.h在y轴上翻转已加载的纹理。//为什么需要翻转Y轴是因为纹理图片开始位置是右上而我们顶点的坐标(0,0)点是左下unsigned char* data = stbi_load("container2.png", &width, &height, &nrChannels, 0);if (data){glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);glGenerateMipmap(GL_TEXTURE_2D);}else{std::cout << "Failed to load texture" << std::endl;}stbi_image_free(data);// texture 2// ---------glGenTextures(1, &texture2);glBindTexture(GL_TEXTURE_2D, texture2);// 设置纹理wrapping参数glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);// 设置纹理filtering参数 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);// load image, create texture and generate mipmaps//data = stbi_load(("aotu.jpg"), &width, &height, &nrChannels, 0);//data = stbi_load(("shanshui.jpg"), &width, &height, &nrChannels, 0);data = stbi_load(("container2_specular.png"), &width, &height, &nrChannels, 0);if (data){//如果没有贴图请优先注意这个RGBA中的alpha(A)通道 如果你的贴图有alpha通道请务必使用RGBA模式否则无法显示贴图      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);glGenerateMipmap(GL_TEXTURE_2D);}else{std::cout << "Failed to load texture" << std::endl;}stbi_image_free(data);// 为每个采样器告诉opengl它属于哪个纹理单元(只需要做一次)  // -------------------------------------------------------------------------------------------modelShader.use();modelShader.setInt("material.diffuse", 0);modelShader.setInt("material.specular", 1);// ourShader.setVec3("lightPos", lightPos);//渲染循环// -----------while (!glfwWindowShouldClose(window)){float currentFrame = glfwGetTime();deltaTime = currentFrame - lastFrame;lastFrame = currentFrame;// -----processInput(window);// 渲染// ------glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清除上一帧的颜色缓冲 以及 深度测试缓冲//激活着色器float angle = 20.0f * 0 * (float)glfwGetTime();//给一个glfwGetTime让模型旋转起来glm::mat4 projection = glm::mat4(1.0f);glm::mat4 view = glm::mat4(1.0f);glm::mat4 model = glm::mat4(1.0f);//glm::vec3 lightPos = glm::vec3(cubePositions[10]);//光源位置projection = glm::perspective(glm::radians(fov), 800.0f / 600.0f, 0.1f, 100.0f);//投影矩阵 参数:视口大小,屏幕宽高比,以及near和farview = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);//lookAt矩阵  参数:摄像机位置 ,观察目标的位置 ,竖直向上的方向model = glm::translate(model, cubePositions[0]);//把数组传进去给每一个新建的模型在世界坐标下有不同的位移model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));lightShader.use();lightShader.setMat4("model", model);//设置模型变换矩阵lightShader.setMat4("projection", projection);//设置投影变化矩阵lightShader.setMat4("view", view);//设置视图变化矩阵for (unsigned int i = 0; i < 4; i++){model = glm::mat4(1.0f);model = glm::translate(model, pointLightPositions[i]);model = glm::scale(model, glm::vec3(0.2f)); // Make it a smaller cubelightShader.setMat4("model", model);glBindVertexArray(VAO);glDrawArrays(GL_TRIANGLES, 0, 36);}modelShader.use();//modelShader.use();//lightPos.x = 1.0f + sin(glfwGetTime()) * 2.0f;//lightPos.y = sin(glfwGetTime() / 2.0f) * 1.0f;model = glm::mat4(1.0f);model = glm::translate(model, cubePositions[0]);//把数组传进去给每一个新建的模型在世界坐标下有不同的位移angle = 20.0f * 1 * (float)glfwGetTime();//给一个glfwGetTime让模型旋转起来model = glm::rotate(model, glm::radians(angle) * 0, glm::vec3(1.0f, 0.5f, 0.5f));//rotate 模型位置 旋转角 旋转轴modelShader.setMat4("model", model);//设置模型变换矩阵modelShader.setMat4("projection", projection);//设置投影变化矩阵modelShader.setMat4("view", view);//设置视图变化矩阵modelShader.setVec3("objectColor", 1, 0.5, 0.5);//设置物体的颜色modelShader.setVec3("lightColor", 0.3, 1, 0.52);//设置光源的颜色当然也可以设置一个uniform来设置变量进行设置//modelShader.setVec3("lightPos", lightPos);//设置光源位置modelShader.setVec3("viewPos", cameraPos);//将相机的位置设置为观察位置//设置材质的每个uniform分量modelShader.setFloat("material.shininess", 32.0f);modelShader.setVec3("dirLight.direction", -0.2f, -1.0f, -0.3f);modelShader.setVec3("dirLight.ambient", 0.05f, 0.05f, 0.05f);modelShader.setVec3("dirLight.diffuse", 0.4f, 0.4f, 0.4f);modelShader.setVec3("dirLight.specular", 0.5f, 0.5f, 0.5f);// point light 1modelShader.setVec3("pointLights[0].position", pointLightPositions[0]);modelShader.setVec3("pointLights[0].ambient", 0.05f, 0.05f, 0.05f);modelShader.setVec3("pointLights[0].diffuse", 0.8f, 0.8f, 0.8f);modelShader.setVec3("pointLights[0].specular", 1.0f, 1.0f, 1.0f);modelShader.setFloat("pointLights[0].constant", 1.0f);modelShader.setFloat("pointLights[0].linear", 0.09f);modelShader.setFloat("pointLights[0].quadratic", 0.032f);// point light 2modelShader.setVec3("pointLights[1].position", pointLightPositions[1]);modelShader.setVec3("pointLights[1].ambient", 0.05f, 0.05f, 0.05f);modelShader.setVec3("pointLights[1].diffuse", 0.8f, 0.8f, 0.8f);modelShader.setVec3("pointLights[1].specular", 1.0f, 1.0f, 1.0f);modelShader.setFloat("pointLights[1].constant", 1.0f);modelShader.setFloat("pointLights[1].linear", 0.09f);modelShader.setFloat("pointLights[1].quadratic", 0.032f);// point light 3modelShader.setVec3("pointLights[2].position", pointLightPositions[2]);modelShader.setVec3("pointLights[2].ambient", 0.05f, 0.05f, 0.05f);modelShader.setVec3("pointLights[2].diffuse", 0.8f, 0.8f, 0.8f);modelShader.setVec3("pointLights[2].specular", 1.0f, 1.0f, 1.0f);modelShader.setFloat("pointLights[2].constant", 1.0f);modelShader.setFloat("pointLights[2].linear", 0.09f);modelShader.setFloat("pointLights[2].quadratic", 0.032f);// point light 4modelShader.setVec3("pointLights[3].position", pointLightPositions[3]);modelShader.setVec3("pointLights[3].ambient", 0.05f, 0.05f, 0.05f);modelShader.setVec3("pointLights[3].diffuse", 0.8f, 0.8f, 0.8f);modelShader.setVec3("pointLights[3].specular", 1.0f, 1.0f, 1.0f);modelShader.setFloat("pointLights[3].constant", 1.0f);modelShader.setFloat("pointLights[3].linear", 0.09f);modelShader.setFloat("pointLights[3].quadratic", 0.032f);modelShader.setVec3("spotLight.position", 0.0f, 0.0f, -1.0f);modelShader.setVec3("spotLight.direction", 0.0f, 0.0f, 5.0f);modelShader.setVec3("spotLight.ambient", 0.0f, 0.0f, 0.0f);modelShader.setVec3("spotLight.diffuse", 1.0f, 1.0f, 1.0f);modelShader.setVec3("spotLight.specular", 1.0f, 1.0f, 1.0f);modelShader.setFloat("spotLight.constant", 1.0f);modelShader.setFloat("spotLight.linear", 0.09f);modelShader.setFloat("spotLight.quadratic", 0.032f);modelShader.setFloat("spotLight.cutOff", glm::cos(glm::radians(12.5f)));modelShader.setFloat("spotLight.outerCutOff", glm::cos(glm::radians(15.0f)));//激活纹理glActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_2D, texture1);glActiveTexture(GL_TEXTURE1);glBindTexture(GL_TEXTURE_2D, texture2);for (unsigned int i = 0; i < 10; i++){glm::mat4 model;model = glm::translate(model, cubePositions[i]);float angle = 20.0f * i;model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));modelShader.setMat4("model", model);glBindVertexArray(VAO2);glDrawArrays(GL_TRIANGLES, 0, 36);}glfwSwapBuffers(window);glfwPollEvents();}glDeleteVertexArrays(1, &VAO);glDeleteBuffers(1, &VBO);glfwTerminate();return 0;
}void processInput(GLFWwindow* window)
{if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)glfwSetWindowShouldClose(window, true);float cameraSpeed = 5.5f * deltaTime;; // adjust accordinglyif (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)cameraPos += cameraSpeed * cameraFront;if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)cameraPos -= cameraSpeed * cameraFront;if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)cameraPos -= glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)cameraPos += glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS)//这里给了一个空格键使我们可以在Y轴上移动cameraPos += cameraUp * cameraSpeed;//cameraPos.y = 0.0f;//可以通过把Y方向上的向量设置为0来使他成为一个FPS类型的摄像机只能在XZ平面上移动}void mouse_callback(GLFWwindow* window, double xposIn, double yposIn)
{float xpos = static_cast<float>(xposIn);float ypos = static_cast<float>(yposIn);// 这个bool变量初始时是设定为true的//我们在一开始的时候需要把他设为屏幕的中心点//如果不这样干 程序一开始就会调用回调函数指向你鼠标进去的时候所在屏幕的位置//这样就离中心点很远了if (firstMouse){lastX = xpos;lastY = ypos;firstMouse = false;}//然后在鼠标的回调函数中我们计算当前帧和上一帧鼠标位置的偏移量:float xoffset = xpos - lastX;float yoffset = lastY - ypos; // y坐标是从下到上  lastX = xpos;lastY = ypos;float sensitivity = 0.1f; // sensitivity这个值可以随便设置xoffset *= sensitivity;yoffset *= sensitivity;yaw += xoffset;pitch += yoffset;// 为了保证摄像机不会整个翻车if (pitch > 89.0f)pitch = 89.0f;if (pitch < -89.0f)pitch = -89.0f;//在xz平面上看向Y轴//这里我们只更新了y值,仔细观察x和z分量也被影响了。从三角形中我们可以看到它们的值等于://direction.x = cos(glm::radians(pitch));//direction.y = sin(glm::radians(pitch)); // 注意我们先把角度转为弧度//direction.z = cos(glm::radians(pitch));//这里Y轴更新确实会影响到Z轴但是不是很懂为什么直接等于cos(pitch)// //////这里我们只更新了y值,仔细观察x和z分量也被影响了。从三角形中我们可以看到它们的值等于://direction.x = cos(glm::radians(yaw));//direction.y =1 // Y不变//direction.z = sin(glm::radians(yaw));// //下面的等式相当于是先俯仰角的旋转变换完成之后再乘以这个偏航角//把上面两步合起来glm::vec3 front;front.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch));front.y = sin(glm::radians(pitch));front.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch));cameraFront = glm::normalize(front);
}// glfw: whenever the mouse scroll wheel scrolls, this callback is called
// ----------------------------------------------------------------------
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{//yoffset就是我们滚轮竖直滚动的方向if (fov >= 1.0f && fov <= 45.0f)fov -= yoffset;//为他设定一个边界 在1到45之间if (fov < 1.0f)fov = 1.0f;if (fov > 45.0f)fov = 45.0f;
}
//MultipleLights.fs
#version 330 core
out vec4 FragColor;struct Material {sampler2D diffuse;sampler2D specular;float shininess;
}; struct DirLight {vec3 direction;vec3 ambient;vec3 diffuse;vec3 specular;
};struct PointLight {vec3 position;float constant;float linear;float quadratic;vec3 ambient;vec3 diffuse;vec3 specular;
};struct SpotLight {vec3 position;vec3 direction;float cutOff;float outerCutOff;float constant;float linear;float quadratic;vec3 ambient;vec3 diffuse;vec3 specular;
};#define NR_POINT_LIGHTS 4in vec3 FragPos;
in vec3 Normal;
in vec2 TexCoords;uniform vec3 viewPos;
uniform DirLight dirLight;
uniform PointLight pointLights[NR_POINT_LIGHTS];
uniform SpotLight spotLight;
uniform Material material;// function prototypes
vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir);
vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir);
vec3 CalcSpotLight(SpotLight light, vec3 normal, vec3 fragPos, vec3 viewDir);
void main()
{vec3 norm = normalize(Normal);vec3 viewDir = normalize(viewPos - FragPos);// == =====================================================// Our lighting is set up in 3 phases: directional, point lights and an optional flashlight// For each phase, a calculate function is defined that calculates the corresponding color// per lamp. In the main() function we take all the calculated colors and sum them up for// this fragment's final color.// == =====================================================// phase 1: directional lightingvec3 result = CalcDirLight(dirLight, norm, viewDir);// phase 2: point lightsfor(int i = 0; i < NR_POINT_LIGHTS; i++)result += CalcPointLight(pointLights[i], norm, FragPos, viewDir);    // phase 3: spot lightresult += CalcSpotLight(spotLight, norm, FragPos, viewDir);    FragColor = vec4(result, 1.0);
}vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir)
{vec3 lightDir = normalize(-light.direction);// 漫反射着色float diff = max(dot(normal, lightDir), 0.0);// 镜面光着色vec3 reflectDir = reflect(-lightDir, normal);float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);// 合并结果vec3 ambient  = light.ambient  * vec3(texture(material.diffuse, TexCoords));vec3 diffuse  = light.diffuse  * diff * vec3(texture(material.diffuse, TexCoords));vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords));return (ambient + diffuse + specular);
}
vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir)
{vec3 lightDir = normalize(light.position - fragPos);// 漫反射着色float diff = max(dot(normal, lightDir), 0.0);// 镜面光着色vec3 reflectDir = reflect(-lightDir, normal);float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);// 衰减float distance    = length(light.position - fragPos);float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));    // 合并结果vec3 ambient  = light.ambient  * vec3(texture(material.diffuse, TexCoords));vec3 diffuse  = light.diffuse  * diff * vec3(texture(material.diffuse, TexCoords));vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords));ambient  *= attenuation;diffuse  *= attenuation;specular *= attenuation;return (ambient + diffuse + specular);
}
vec3 CalcSpotLight(SpotLight light, vec3 normal, vec3 fragPos, vec3 viewDir)
{vec3 lightDir = normalize(light.position - fragPos);// diffuse shadingfloat diff = max(dot(normal, lightDir), 0.0);// specular shadingvec3 reflectDir = reflect(-lightDir, normal);float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);// attenuationfloat distance = length(light.position - fragPos);float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));    // spotlight intensityfloat theta = dot(lightDir, normalize(-light.direction)); float epsilon = light.cutOff - light.outerCutOff;float intensity = clamp((theta - light.outerCutOff) / epsilon, 0.0, 1.0);// combine resultsvec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords));vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords));vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords));ambient *= attenuation * intensity;diffuse *= attenuation * intensity;specular *= attenuation * intensity;return (ambient + diffuse + specular);
}
//MultipleLights.vs
#version 330 core
layout (location = 0) in vec3 aPos;//初始位置为0的属性为顶点位置
layout (location = 1) in vec3 aNormal;//初始位置为1的属性为法线位置
layout (location = 2) in vec2 aTexCoords;//初始位置为2的属性为贴图坐标out vec3 FragPos;//输出物体的位置
out vec3 Normal;//输出法线
out vec2 TexCoords;//输出贴图uniform mat4 model;//定义全局变量model 在主函数中设置
uniform mat4 view;//定义全局变量view 在主函数中设置
uniform mat4 projection;//定义全局变量projection 在主函数中设置void main()
{FragPos = vec3(model * vec4(aPos, 1.0));//物体经过模型变换后在世界坐标的位置Normal = mat3(transpose(inverse(model))) * aNormal;//法线变换矩阵=逆矩阵的转置*法线矩阵TexCoords = aTexCoords;//贴图坐标gl_Position = projection * view * vec4(FragPos, 1.0);//最后在视锥里面你看到的位置
}
//lightShader.fs
#version 330 core
out vec4 FragColor;void main()
{FragColor = vec4(1.0);}
//lightShader.vs
#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);
}

OpenGL第十一章 多光源相关推荐

  1. OpenGL超级宝典(第7版)之第十一章高级数据管理

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 OpenGL超级宝典(第7版)之第十一章高级数据管理 前言 一.取消绑定 二.稀疏纹理 三.压缩纹理 四.压缩数据格式 五.高质量纹理 ...

  2. Box2D v2.3.0 用户指南(第十一章)

     第十一章零碎资料(loose ends) 11.1用户数据(user data) b2Fixture,b2Body,以及b2Joint类允许你通过一个通用指针(void pointer)来附加一 ...

  3. [swift 进阶]读书笔记-第十一章:互用性 C11P1 实践:封装 CommonMark

    第十一章:互用性 Interoperability 前言: swift 的最大优点就是与C 或者 OC 混编的时候稳的一匹 本章主要讲了swift和C之间的一些知识点. 11.1 实践:封装 Comm ...

  4. 【译】 WebSocket 协议第十一章——IANA 注意事项(IANA Considerations)

    概述 本文为 WebSocket 协议的第十一章,本文翻译的主要内容为 WebSocket 的 IANA 相关注意事项. IANA 注意事项(协议正文) 11.1 注册新 URI 协议 11.1.1 ...

  5. java语言仅支持单重继承_java语言程序设计基础篇习题_复习题_第十一章

    java语言程序设计基础篇习题_复习题_第十一章 11.1 下面说法是真是假?一个子类是父类的子集. 11.2 使用什么关键字来定义一个子类 11.3 什么是单一继承?什么是多重继承?java支持多重 ...

  6. 《javascript设计模式》笔记之第十章 和 第十一章:门面模式和适配器模式

    第十章:门面模式 一:门面模式的作用 简化已有的api,使其更加容易使用 解决浏览器的兼容问题 二:门面模式的本质 门面模式的本质就是包装已有的api来简化操作   三:门面模式的两个简单例子 下面这 ...

  7. 计算机网络离不开光缆,九年级物理全册 第二十一章 第四节 越来越宽的信息之路习题课件 新人教版.ppt...

    九年级物理全册 第二十一章 第四节 越来越宽的信息之路习题课件 新人教版.ppt 第二十一章信息的传递,第四节越来越宽的信息之路,1微波的性质更接近光波,大致沿_______传播,需要每隔_____k ...

  8. 开发日记-20190915 关键词 汇编语言王爽版 第十一章

    第十一章 标志寄存器 CPU内部的寄存器中,有一种特殊的寄存器(对于不同的处理器,个数和结构都可能不同)具有以下三种作用. (1)用来存储相关的指令的某些执行结果 (2)用来为CPU执行相关的指令提供 ...

  9. 羊皮卷的实践-第二十一章

    第二十一章 高山滑雪是人与环境以及时间的竞赛.每当我看到输赢之间只差极短的时间时,我就不禁摇头同情那些输家. 第一名的时间是一分三十七秒二二. 第二名的时间是一分二十七秒二五. 也就是说,冠军与平庸之 ...

最新文章

  1. 开源 免费 java CMS - FreeCMS1.5-建站向导
  2. NO.7:别让异常逃离析构函数
  3. HDOJ---1257 最少拦截系统[线性DP]+NYOJ---拦截导弹[输出最长单调子序列的长度]
  4. MAC下《暗黑世界》客户端版本编译说明!!
  5. PMCAFF | 别学东学西了,先建立自己的知识体系吧
  6. win下配置的ES中的数据在哪里可以看到?三种方式你看那种更加高大上!!!(win_Elasticsearch)
  7. .NET Core WEB API中接口参数的模型绑定的理解
  8. 7-1 输出全排列 (20 分)(全排列+递归+图解)Come Baby
  9. watir6.0 -selenium3新时代的watir-webdriver
  10. 宏观经济学gdp计算方法_宏观经济学考研的重要考点
  11. tkinter使用cefpython库_Python3.7 tkinter中嵌入网页(WebView),需要引入cefpython3
  12. hive 强转为string_Hive的条件函数与日期函数全面汇总解析
  13. 记录 PHP 缓存区ob
  14. 小米手机-解BL锁+开ROOT权限
  15. BLDC无刷直流电机驱动程序
  16. 神武3进不去 服务器响应,windows7系统玩神武2卡机的解决方法
  17. 基于Java毕业设计养老院信息管理源码+系统+mysql+lw文档+部署软件
  18. mysql 内存大_MySQL数据库之MySQL大内存配置方案
  19. Arch Linux 指南 02——安装图形界面
  20. 一位ACMer过来人的心得 (2011-08-04 20:44:18)

热门文章

  1. 如何将linux虚拟机上的文件弄到Windows上?
  2. 名画89 刘松年《画卷两幅》
  3. 缺陷是软件开发中最大的浪费
  4. html5 头部阴影,兼容各种主流浏览器的CSS阴影效果
  5. 手表运动状态识别(静止/走路/跑步)_v2(使用传统处理方法)
  6. 提起2013,我所领悟到的
  7. u盘运行linux失败,u盘安装linux失败的解决方法
  8. php 高校党员培训管理系统-计算机毕设 附源码56161
  9. 股票期货量化数据引入
  10. 每日学术速递5.21