基于C++的OpenGL 12 之多光源
2022/8/16 14:53:32
本文主要是介绍基于C++的OpenGL 12 之多光源,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
1. 引言
本文基于C++语言,描述OpenGL的多光源
前置知识可参考:
- 基于C++的OpenGL 11 之投光物 - 当时明月在曾照彩云归 - 博客园 (cnblogs.com)
笔者这里不过多描述每个名词、函数和细节,更详细的文档可以参考:
- 多光源 - LearnOpenGL CN (learnopengl-cn.github.io)
2. 概述
生活中,光源往往是不止一个的,通常是多个光源同时出现
3. 编码
使用多个光源时,将光照计算代码全写在片段着色器的main
函数里,不利于代码的编写与阅读
在这里,将多个光照封装为GLSL中的函数
平行光照函数:
struct DirLight { vec3 direction; vec3 ambient; vec3 diffuse; vec3 specular; }; uniform DirLight dirLight; vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir); void main() { ... } 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); }
点光照函数:
struct PointLight { vec3 position; float constant; float linear; float quadratic; vec3 ambient; vec3 diffuse; vec3 specular; }; #define NR_POINT_LIGHTS 4 uniform PointLight pointLights[NR_POINT_LIGHTS]; // 定义四个点光源 vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir); void main() { ... } 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); }
合并光照:
void main() { // 属性 vec3 norm = normalize(Normal); vec3 viewDir = normalize(viewPos - FragPos); // 第一阶段:定向光照 vec3 result = CalcDirLight(dirLight, norm, viewDir); // 第二阶段:点光源 for(int i = 0; i < NR_POINT_LIGHTS; i++) result += CalcPointLight(pointLights[i], norm, FragPos, viewDir); // 第三阶段:聚光 //result += CalcSpotLight(spotLight, norm, FragPos, viewDir); FragColor = vec4(result, 1.0); }
向GPU传输数据:
// positions of the point lights 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) }; ... // directional light lightingShader.setVec3("dirLight.direction", -0.2f, -1.0f, -0.3f); lightingShader.setVec3("dirLight.ambient", 0.05f, 0.05f, 0.05f); lightingShader.setVec3("dirLight.diffuse", 0.4f, 0.4f, 0.4f); lightingShader.setVec3("dirLight.specular", 0.5f, 0.5f, 0.5f); // point light 1 lightingShader.setVec3("pointLights[0].position", pointLightPositions[0]); lightingShader.setVec3("pointLights[0].ambient", 0.05f, 0.05f, 0.05f); lightingShader.setVec3("pointLights[0].diffuse", 0.8f, 0.8f, 0.8f); lightingShader.setVec3("pointLights[0].specular", 1.0f, 1.0f, 1.0f); lightingShader.setFloat("pointLights[0].constant", 1.0f); lightingShader.setFloat("pointLights[0].linear", 0.09f); lightingShader.setFloat("pointLights[0].quadratic", 0.032f); // point light 2 lightingShader.setVec3("pointLights[1].position", pointLightPositions[1]); lightingShader.setVec3("pointLights[1].ambient", 0.05f, 0.05f, 0.05f); lightingShader.setVec3("pointLights[1].diffuse", 0.8f, 0.8f, 0.8f); lightingShader.setVec3("pointLights[1].specular", 1.0f, 1.0f, 1.0f); lightingShader.setFloat("pointLights[1].constant", 1.0f); lightingShader.setFloat("pointLights[1].linear", 0.09f); lightingShader.setFloat("pointLights[1].quadratic", 0.032f); // point light 3 lightingShader.setVec3("pointLights[2].position", pointLightPositions[2]); lightingShader.setVec3("pointLights[2].ambient", 0.05f, 0.05f, 0.05f); lightingShader.setVec3("pointLights[2].diffuse", 0.8f, 0.8f, 0.8f); lightingShader.setVec3("pointLights[2].specular", 1.0f, 1.0f, 1.0f); lightingShader.setFloat("pointLights[2].constant", 1.0f); lightingShader.setFloat("pointLights[2].linear", 0.09f); lightingShader.setFloat("pointLights[2].quadratic", 0.032f); // point light 4 lightingShader.setVec3("pointLights[3].position", pointLightPositions[3]); lightingShader.setVec3("pointLights[3].ambient", 0.05f, 0.05f, 0.05f); lightingShader.setVec3("pointLights[3].diffuse", 0.8f, 0.8f, 0.8f); lightingShader.setVec3("pointLights[3].specular", 1.0f, 1.0f, 1.0f); lightingShader.setFloat("pointLights[3].constant", 1.0f); lightingShader.setFloat("pointLights[3].linear", 0.09f); lightingShader.setFloat("pointLights[3].quadratic", 0.032f); // spotLight lightingShader.setVec3("spotLight.position", camera.Position); lightingShader.setVec3("spotLight.direction", camera.Front); lightingShader.setVec3("spotLight.ambient", 0.0f, 0.0f, 0.0f); lightingShader.setVec3("spotLight.diffuse", 1.0f, 1.0f, 1.0f); lightingShader.setVec3("spotLight.specular", 1.0f, 1.0f, 1.0f); lightingShader.setFloat("spotLight.constant", 1.0f); lightingShader.setFloat("spotLight.linear", 0.09f); lightingShader.setFloat("spotLight.quadratic", 0.032f); lightingShader.setFloat("spotLight.cutOff", glm::cos(glm::radians(12.5f))); lightingShader.setFloat("spotLight.outerCutOff", glm::cos(glm::radians(15.0f)));
结果图如下:
4. 完整代码
主要文件MultipleLights.cpp
:
#include <glad/glad.h> #include <GLFW/glfw3.h> #include <iostream> #include <math.h> #include "Shader.hpp" #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" #include <glm/glm.hpp> #include <glm/ext/matrix_transform.hpp> // glm::translate, glm::rotate, glm::scale #include <glm/ext/matrix_clip_space.hpp> // glm::perspective #include <glm/gtc/type_ptr.hpp> //全局变量 glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 10.0f); glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f); glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f); glm::vec3 lightPos(0.8f, 1.0f, 2.0f); // 函数声明 void framebuffer_size_callback(GLFWwindow *window, int width, int height); void process_input(GLFWwindow *window); int main() { glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); GLFWwindow *window = glfwCreateWindow(800, 600, "MultipleLights", nullptr, nullptr); if (window == nullptr) { std::cout << "Faild to create window" << std::endl; glfwTerminate(); } glfwMakeContextCurrent(window); if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { std::cout << "Faild to initialize glad" << std::endl; return -1; } glad_glViewport(0, 0, 800, 600); glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); //配置项 glEnable(GL_DEPTH_TEST); Shader lightCubeShader("../light_cube.vs.glsl", "../light_cube.fs.glsl"); Shader lightingShader("../cube.vs.glsl", "../cube.fs.glsl"); unsigned int cubeVAO; glGenVertexArrays(1, &cubeVAO); glBindVertexArray(cubeVAO); 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 }; unsigned int 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(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 texture; glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); // 为当前绑定的纹理对象设置环绕、过滤方式 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // 加载并生成纹理 int width, height, nrChannels; unsigned char *data = stbi_load("../container2.png", &width, &height, &nrChannels, 0); if (data) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 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); lightingShader.setInt("material.diffuse", 0); // 镜面反射纹理 unsigned int texture1; glGenTextures(1, &texture1); glBindTexture(GL_TEXTURE_2D, texture1); // 为当前绑定的纹理对象设置环绕、过滤方式 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // 加载并生成纹理 data = stbi_load("../container2_specular.png", &width, &height, &nrChannels, 0); if (data) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 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); lightingShader.setInt("material.diffuse", 1); unsigned int lightCubeVAO; glGenVertexArrays(1, &lightCubeVAO); glBindVertexArray(lightCubeVAO); // 只需要绑定VBO不用再次设置VBO的数据,因为箱子的VBO数据中已经包含了正确的立方体顶点数据 glBindBuffer(GL_ARRAY_BUFFER, VBO); // 设置灯立方体的顶点属性(对我们的灯来说仅仅只有位置数据) glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); // positions all containers 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) }; // positions of the point lights 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) }; while (!glfwWindowShouldClose(window)) { process_input(window); glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, texture1); lightingShader.use(); lightingShader.setVec3("objectColor", 1.0f, 0.5f, 0.31f); lightingShader.setVec3("lightColor", 1.0f, 1.0f, 1.0f); lightingShader.setVec3("lightPos", lightPos); lightingShader.setVec3("viewPos", cameraPos); lightingShader.setFloat("material.shininess", 32.0f); // directional light lightingShader.setVec3("dirLight.direction", -0.2f, -1.0f, -0.3f); lightingShader.setVec3("dirLight.ambient", 0.05f, 0.05f, 0.05f); lightingShader.setVec3("dirLight.diffuse", 0.4f, 0.4f, 0.4f); lightingShader.setVec3("dirLight.specular", 0.5f, 0.5f, 0.5f); // point light 1 lightingShader.setVec3("pointLights[0].position", pointLightPositions[0]); lightingShader.setVec3("pointLights[0].ambient", 0.05f, 0.05f, 0.05f); lightingShader.setVec3("pointLights[0].diffuse", 0.8f, 0.8f, 0.8f); lightingShader.setVec3("pointLights[0].specular", 1.0f, 1.0f, 1.0f); lightingShader.setFloat("pointLights[0].constant", 1.0f); lightingShader.setFloat("pointLights[0].linear", 0.09f); lightingShader.setFloat("pointLights[0].quadratic", 0.032f); // point light 2 lightingShader.setVec3("pointLights[1].position", pointLightPositions[1]); lightingShader.setVec3("pointLights[1].ambient", 0.05f, 0.05f, 0.05f); lightingShader.setVec3("pointLights[1].diffuse", 0.8f, 0.8f, 0.8f); lightingShader.setVec3("pointLights[1].specular", 1.0f, 1.0f, 1.0f); lightingShader.setFloat("pointLights[1].constant", 1.0f); lightingShader.setFloat("pointLights[1].linear", 0.09f); lightingShader.setFloat("pointLights[1].quadratic", 0.032f); // point light 3 lightingShader.setVec3("pointLights[2].position", pointLightPositions[2]); lightingShader.setVec3("pointLights[2].ambient", 0.05f, 0.05f, 0.05f); lightingShader.setVec3("pointLights[2].diffuse", 0.8f, 0.8f, 0.8f); lightingShader.setVec3("pointLights[2].specular", 1.0f, 1.0f, 1.0f); lightingShader.setFloat("pointLights[2].constant", 1.0f); lightingShader.setFloat("pointLights[2].linear", 0.09f); lightingShader.setFloat("pointLights[2].quadratic", 0.032f); // point light 4 lightingShader.setVec3("pointLights[3].position", pointLightPositions[3]); lightingShader.setVec3("pointLights[3].ambient", 0.05f, 0.05f, 0.05f); lightingShader.setVec3("pointLights[3].diffuse", 0.8f, 0.8f, 0.8f); lightingShader.setVec3("pointLights[3].specular", 1.0f, 1.0f, 1.0f); lightingShader.setFloat("pointLights[3].constant", 1.0f); lightingShader.setFloat("pointLights[3].linear", 0.09f); lightingShader.setFloat("pointLights[3].quadratic", 0.032f); // spotLight lightingShader.setVec3("spotLight.position", cameraPos); lightingShader.setVec3("spotLight.direction", cameraFront); lightingShader.setVec3("spotLight.ambient", 0.0f, 0.0f, 0.0f); lightingShader.setVec3("spotLight.diffuse", 1.0f, 1.0f, 1.0f); lightingShader.setVec3("spotLight.specular", 1.0f, 1.0f, 1.0f); lightingShader.setFloat("spotLight.constant", 1.0f); lightingShader.setFloat("spotLight.linear", 0.09f); lightingShader.setFloat("spotLight.quadratic", 0.032f); lightingShader.setFloat("spotLight.cutOff", glm::cos(glm::radians(12.5f))); lightingShader.setFloat("spotLight.outerCutOff", glm::cos(glm::radians(15.0f))); glm::mat4 model = glm::mat4(1.0f); model = glm::rotate(model, glm::radians(-55.0f), glm::vec3(1.0f, 0.0f, 0.0f)); glm::mat4 view = glm::mat4(1.0f); // view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f)); view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp); glm::mat4 projection = glm::mat4(1.0f); projection = glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f); // 模型矩阵 int modelLoc = glGetUniformLocation(lightingShader.ID, "model"); glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); // 观察矩阵和投影矩阵与之类似 int viewLoc = glGetUniformLocation(lightingShader.ID, "view"); glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view)); int projectionLoc = glGetUniformLocation(lightingShader.ID, "projection"); glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection)); // render the cube glBindVertexArray(cubeVAO); // glDrawArrays(GL_TRIANGLES, 0, 36); for (unsigned int i = 0; i < 10; i++) { // calculate the model matrix for each object and pass it to shader before drawing glm::mat4 model = glm::mat4(1.0f); 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)); lightingShader.setMat4("model", model); glDrawArrays(GL_TRIANGLES, 0, 36); } // also draw the lamp object // lightCubeShader.use(); // lightCubeShader.setMat4("projection", projection); // lightCubeShader.setMat4("view", view); // model = glm::mat4(1.0f); // model = glm::translate(model, lightPos); // model = glm::scale(model, glm::vec3(0.2f)); // a smaller cube // lightCubeShader.setMat4("model", model); // glBindVertexArray(lightCubeVAO); // glDrawArrays(GL_TRIANGLES, 0, 36); // also draw the lamp object(s) lightCubeShader.use(); lightCubeShader.setMat4("projection", projection); lightCubeShader.setMat4("view", view); // we now draw as many light bulbs as we have point lights. glBindVertexArray(lightCubeVAO); 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 cube lightCubeShader.setMat4("model", model); glDrawArrays(GL_TRIANGLES, 0, 36); } glfwSwapBuffers(window); glfwPollEvents(); } glfwTerminate(); return 0; } void framebuffer_size_callback(GLFWwindow *window, int width, int height) { glViewport(0, 0, width, height); } void process_input(GLFWwindow *window) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { glfwSetWindowShouldClose(window, true); } float cameraSpeed = 0.05f; // adjust accordingly if (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; }
立方体顶点着色器GLSLcube.vs.glsl
:
#version 330 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 aNormal; layout (location = 2) in vec2 aTexCoords; out vec3 Normal; out vec3 FragPos; out vec2 TexCoords; uniform mat4 model; uniform mat4 view; uniform mat4 projection; void main() { gl_Position = projection * view * model * vec4(aPos, 1.0); FragPos = vec3(model * vec4(aPos, 1.0)); Normal = aNormal; TexCoords = aTexCoords; }
立方体片段着色器GLSLcube.fs.glsl
:
#version 330 core struct Material { sampler2D diffuse; sampler2D specular; float shininess; }; struct DirLight { vec3 direction; vec3 ambient; vec3 diffuse; vec3 specular; }; uniform DirLight dirLight; vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir); struct PointLight { vec3 position; float constant; float linear; float quadratic; vec3 ambient; vec3 diffuse; vec3 specular; }; #define NR_POINT_LIGHTS 4 uniform PointLight pointLights[NR_POINT_LIGHTS]; // 定义四个点光源 vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir); in vec3 Normal; in vec3 FragPos; in vec2 TexCoords; out vec4 FragColor; uniform vec3 objectColor; uniform vec3 lightColor; uniform vec3 lightPos; uniform vec3 viewPos; uniform Material material; void main() { // 属性 vec3 norm = normalize(Normal); vec3 viewDir = normalize(viewPos - FragPos); // 第一阶段:定向光照 vec3 result = CalcDirLight(dirLight, norm, viewDir); // 第二阶段:点光源 for(int i = 0; i < NR_POINT_LIGHTS; i++) result += CalcPointLight(pointLights[i], norm, FragPos, viewDir); // 第三阶段:聚光 //result += 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); }
着色器Shader.hpp
、光源顶点着色器GLSLlight_cube.vs.glsl
、光源片段着色器GLSLlight_cube.fs.glsl
见:
- 基于C++的OpenGL 07 之颜色 - 当时明月在曾照彩云归 - 博客园 (cnblogs.com)
5. 参考资料
[1]多光源 - LearnOpenGL CN (learnopengl-cn.github.io)
这篇关于基于C++的OpenGL 12 之多光源的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23增量更新怎么做?-icode9专业技术文章分享
- 2024-11-23压缩包加密方案有哪些?-icode9专业技术文章分享
- 2024-11-23用shell怎么写一个开机时自动同步远程仓库的代码?-icode9专业技术文章分享
- 2024-11-23webman可以同步自己的仓库吗?-icode9专业技术文章分享
- 2024-11-23在 Webman 中怎么判断是否有某命令进程正在运行?-icode9专业技术文章分享
- 2024-11-23如何重置new Swiper?-icode9专业技术文章分享
- 2024-11-23oss直传有什么好处?-icode9专业技术文章分享
- 2024-11-23如何将oss直传封装成一个组件在其他页面调用时都可以使用?-icode9专业技术文章分享
- 2024-11-23怎么使用laravel 11在代码里获取路由列表?-icode9专业技术文章分享
- 2024-11-22怎么实现ansible playbook 备份代码中命名包含时间戳功能?-icode9专业技术文章分享