文章目录

  • 写在前面
  • 多光源
    • 定向光
    • 点光源
    • 合成结果
  • 总结
  • 练习

写在前面

原文链接。原文应该是github上的一个项目,本文主要用来记录一些知识点和自己遇到的问题。

多光源

我们在前面的教程中已经学习了许多关于OpenGL中光照的知识,其中包括冯氏着色(Phong Shading)、材质(Material)、光照贴图(Lighting Map)以及不同种类的投光物(Light Caster)。在这一节中,我们将结合之前学过的所有知识,创建一个包含六个光源的场景。我们将模拟一个类似太阳的定向光(Directional Light)光源,四个分散在场景中的点光源(Point Light),以及一个手电筒(Flashlight)。

为了在场景中使用多个光源,我们希望将光照计算封装到GLSL函数中。这样做的原因是,每一种光源都需要一种不同的计算方法,而一旦我们想对多个光源进行光照计算时,代码很快就会变得非常复杂。如果我们只在main函数中进行所有的这些计算,代码很快就会变得难以理解。

GLSL中的函数和C函数很相似,它有一个函数名、一个返回值类型,如果函数不是在main函数之前声明的,我们还必须在代码文件顶部声明一个原型。我们对每个光照类型都创建一个不同的函数:定向光、点光源和聚光。

当我们在场景中使用多个光源时,通常使用以下方法:我们需要有一个单独的颜色向量代表片段的输出颜色。对于每一个光源,它对片段的贡献颜色将会加到片段的输出颜色向量上。所以场景中的每个光源都会计算它们各自对片段的影响,并结合为一个最终的输出颜色。大体的结构会像是这样:

实际的代码对每一种实现都可能不同,但大体的结构都是差不多的。我们定义了几个函数,用来计算每个光源的影响,并将最终的结果颜色加到输出颜色向量上。例如,如果两个光源都很靠近一个片段,那么它们所结合的贡献将会形成一个比单个光源照亮时更加明亮的片段。

定向光

我么需要在片段着色器中定义一个函数来计算定向光对相应片段的贡献:它接受一些参数并计算一个定向光照颜色。

首先,我们需要定义一个定向光源最少所需要的变量。我们可以将这些变量储存在一个叫做DirLight的结构体中,并将它定义为一个uniform。需要的变量在上一节中都介绍过:

接下来我们可以将dirLight传入一个有着以下原型的函数。


你可以看到,这个函数需要一个DirLight结构体和其它两个向量来进行计算。如果你认真完成了上一节的话,这个函数的内容应该理解起来很容易:

我们基本上只是从上一节中复制了代码,并使用函数参数的两个向量来计算定向光的贡献向量。最终环境光、漫反射和镜面光的贡献将会合并为单个颜色向量返回。

点光源

和定向光一样,我们也希望定义一个用于计算点光源对相应片段贡献,以及衰减,的函数。同样,我们定义一个包含了点光源所需所有变量的结构体:

你可以看到,我们在GLSL中使用了预处理指令来定义了我们场景中点光源的数量。接着我们使用了这个NR_POINT_LIGHTS常量来创建了一个PointLight结构体的数组。GLSL中的数组和C数组一样,可以使用一对方括号来创建。现在我们有四个待填充数据的PointLight结构体。

点光源函数的原型如下:

这个函数从参数中获取所需的所有数据,并返回一个代表该点光源对片段的颜色贡献的vec3。我们再一次聪明地从之前的教程中复制粘贴代码,完成了下面这样的函数:

将这些功能抽象到这样一个函数中的优点是,我们能够不用重复的代码而很容易地计算多个点光源的光照了。在main函数中,我们只需要创建一个循环,遍历整个点光源数组,对每个点光源调用CalcPointLight就可以了。

合成结果

现在我们已经定义了一个计算定向光的函数和一个计算点光源的函数了,我们可以将它们合并放到main函数中。

每个光源类型都将它们的贡献加到了最终的输出颜色上,直到所有的光源都处理完了。最终的颜色包含了场景中所有光源的颜色影响所合并的结果。如果你想的话,你也可以实现一个聚光,并将它的效果加到输出颜色中。我们会将CalcSpotLight函数留给读者作为练习。

这里贴一下我写的代码吧:

// 计算某个聚光灯源对该片段颜色的贡献
vec3 CalSpotLight(SpotLight 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 dis = length(light.position - fragPos);// 衰减float attenuation = 1.0 /(light.constant + light.linear * dis + light.quadratic * dis * dis);// 内外光切角插值 实现平滑过度效果float cosTheta = dot(lightDir, normalize(-light.direction));float epsilon = light.cutOff - light.outerCutOff;float intensity = clamp((cosTheta  - light.outerCutOff) / epsilon, 0.0, 1.0);// 合并vec3 ambient = light.ambient * texture(material.diffuse, TexCoords).rgb;vec3 diffuse = light.diffuse * diff * texture(material.diffuse, TexCoords).rgb;vec3 specular = light.specular * spec * texture(material.specular, TexCoords).rgb;return (ambient + diffuse + specular) * attenuation * intensity;
}

设置定向光结构体的uniform应该非常熟悉了,但是你可能会在想我们该如何设置点光源的uniform值,因为点光源的uniform现在是一个PointLight的数组了。这并不是我们以前讨论过的话题。

很幸运的是,这并不是很复杂,设置一个结构体数组的uniform和设置一个结构体的uniform是很相似的,但是这一次在访问uniform位置的时候,我们需要定义对应的数组下标值

在这里我们索引了pointLights数组中的第一个PointLight,并获取了constant变量的位置。但这也意味着不幸的是我们必须对这四个点光源手动设置uniform值,这让点光源本身就产生了28个uniform调用,非常冗长。你也可以尝试将这些抽象出去一点,定义一个点光源类,让它来为你设置uniform值,但最后你仍然要用这种方式设置所有光源的uniform值。

别忘了,我们还需要为每个点光源定义一个位置向量,所以我们让它们在场景中分散一点。我们会定义另一个glm::vec3数组来包含点光源的位置:

接下来我们从pointLights数组中索引对应的PointLight,将它的position值设置为刚刚定义的位置值数组中的其中一个。同时我们还要保证现在绘制的是四个灯立方体而不是仅仅一个。只要对每个灯物体创建一个不同的模型矩阵就可以了,和我们之前对箱子的处理类似。

如果你还使用了手电筒的话,所有光源组合的效果将看起来和下图差不多:

你可以看到,很显然天空中有一个全局照明(像一个太阳),我们有四个光源分散在场景中,以及玩家视角的手电筒。看起来是不是非常不错?

你可以在这里找到最终程序的源代码。

上面图片中的所有光源都是使用上一节中所使用的默认属性,但如果你愿意实验这些数值的话,你能够得到很多有意思的结果。艺术家和关卡设计师通常都在编辑器中不断的调整这些光照参数,保证光照与环境相匹配。在我们刚刚创建的简单光照环境中,你可以简单地调整一下光源的属性,创建很多有意思的视觉效果:

我们也改变了清屏的颜色来更好地反应光照。你可以看到,只需要简单地调整一些光照参数,你就能创建完全不同的氛围。

相信你现在已经对OpenGL的光照有很好的理解了。有了目前所学的这些知识,我们已经可以创建出丰富有趣的环境和氛围了。尝试实验一下不同的值,创建出你自己的氛围吧。

我简单的封装了一下光照,感觉也不是很好用……
light.h:light.h:light.h:

#pragma once
#ifndef LIGHT_H
#define LIGHT_H#include <glad/glad.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <string>
#include "shader.h"
using std::string;class BaseLight
{public:glm::vec3 ambient;glm::vec3 diffuse;glm::vec3 specular;BaseLight(const glm::vec3& ambient, const glm::vec3& diffuse, const glm::vec3& specular) :ambient(ambient), diffuse(diffuse), specular(specular) {}BaseLight(float ambient_r = 0, float ambient_g = 0, float ambient_b = 0, float diffuse_r = 0, float diffuse_g = 0, float diffuse_b = 0,float specular_r = 0, float specular_g = 0, float specular_b = 0) :ambient(ambient_r, ambient_g, ambient_b),diffuse(diffuse_r, diffuse_g, diffuse_b), specular(specular_r, specular_g, specular_b) {}
};class AttenuationLight :public BaseLight
{public:float constant;float linear;float quadratic;AttenuationLight(const glm::vec3& ambient, const glm::vec3& diffuse, const glm::vec3& specular,float constant = 1.0f, float linear = 0.09f, float quadratic = 0.032f) :BaseLight(ambient, diffuse, specular), constant(constant), linear(linear), quadratic(quadratic) {}
};class DirLight :public BaseLight
{public:glm::vec3 direction;DirLight(const glm::vec3& direction, const glm::vec3& ambient, const glm::vec3& diffuse, const glm::vec3& specular) :BaseLight(ambient, diffuse, specular), direction(direction) {}
};class PointLight :public AttenuationLight
{public:glm::vec3 position;PointLight(const glm::vec3& position, const glm::vec3& ambient, const glm::vec3& diffuse, const glm::vec3& specular,float constant = 1.0f, float linear = 0.09f, float quadratic = 0.032f) :AttenuationLight(ambient, diffuse, specular, constant, linear, quadratic), position(position) {}
};class SpotLight :public AttenuationLight
{public:glm::vec3 position;glm::vec3 direction;float cutOff;float outerCutOff;SpotLight(const glm::vec3& position, const glm::vec3& direction, const glm::vec3& ambient, const glm::vec3& diffuse, const glm::vec3& specular,float constant = 1.0f, float linear = 0.09f, float quadratic = 0.032f, float cutOff = cos(glm::radians(12.5f)), float outerCutOff = cos(glm::radians(17.5f))) :AttenuationLight(ambient, diffuse, specular, constant, linear, quadratic), position(position), direction(direction), cutOff(cutOff), outerCutOff(outerCutOff) {}
};void setLightAllAttribute(const Shader& shader, const string& uniformName, const DirLight* dirLights, int len = 1);
void setLightAllAttribute(const Shader& shader, const string& uniformName, const PointLight* pointLights, int len = 1);
void setLightAllAttribute(const Shader& shader, const string& uniformName, const SpotLight* spotLights, int len = 1);#endif

light.cpp:light.cpp:light.cpp:

#include "light.h"
using std::string;
using std::to_string;void setLightAllAttribute(const Shader& shader, const string& uniformName, const DirLight* dirLights, int len)
{if (len == 1){shader.setVec3(uniformName + ".direction", dirLights->direction);shader.setVec3(uniformName + ".ambient", dirLights->ambient);shader.setVec3(uniformName + ".diffuse", dirLights->diffuse);shader.setVec3(uniformName + ".specular", dirLights->specular);}else{for (int i = 0; i < len; i++){shader.setVec3(uniformName + "[" + to_string(i) + "].direction", dirLights[i].direction);shader.setVec3(uniformName + "[" + to_string(i) + "].ambient", dirLights[i].ambient);shader.setVec3(uniformName + "[" + to_string(i) + "].diffuse", dirLights[i].diffuse);shader.setVec3(uniformName + "[" + to_string(i) + "].specular", dirLights[i].specular);}}
}void setLightAllAttribute(const Shader& shader, const string& uniformName, const PointLight* pointLights, int len)
{if (len == 1){shader.setVec3(uniformName + ".position", pointLights->position);shader.setVec3(uniformName + ".ambient", pointLights->ambient);shader.setVec3(uniformName + ".diffuse", pointLights->diffuse);shader.setVec3(uniformName + ".specular", pointLights->specular);shader.setFloat(uniformName + ".constant", pointLights->constant);shader.setFloat(uniformName + ".linear", pointLights->linear);shader.setFloat(uniformName + ".quadratic", pointLights->quadratic);}else{for (int i = 0; i < len; i++){shader.setVec3(uniformName + "[" + to_string(i) + "].position", pointLights[i].position);shader.setVec3(uniformName + "[" + to_string(i) + "].ambient", pointLights[i].ambient);shader.setVec3(uniformName + "[" + to_string(i) + "].diffuse", pointLights[i].diffuse);shader.setVec3(uniformName + "[" + to_string(i) + "].specular", pointLights[i].specular);shader.setFloat(uniformName + "[" + to_string(i) + "].constant", pointLights->constant);shader.setFloat(uniformName + "[" + to_string(i) + "].linear", pointLights->linear);shader.setFloat(uniformName + "[" + to_string(i) + "].quadratic", pointLights->quadratic);}}
}void setLightAllAttribute(const Shader& shader, const string& uniformName, const SpotLight* spotLights, int len)
{if (len == 1){shader.setVec3(uniformName + ".position", spotLights->position);shader.setVec3(uniformName + ".direction", spotLights->direction);shader.setVec3(uniformName + ".ambient", spotLights->ambient);shader.setVec3(uniformName + ".diffuse", spotLights->diffuse);shader.setVec3(uniformName + ".specular", spotLights->specular);shader.setFloat(uniformName + ".constant", spotLights->constant);shader.setFloat(uniformName + ".linear", spotLights->linear);shader.setFloat(uniformName + ".quadratic", spotLights->quadratic);shader.setFloat(uniformName + ".cutOff", spotLights->cutOff);shader.setFloat(uniformName + ".outerCutOff", spotLights->outerCutOff);}else{for (int i = 0; i < len; i++){shader.setVec3(uniformName + "[" + to_string(i) + "].position", spotLights[i].position);shader.setVec3(uniformName + "[" + to_string(i) + "].direction", spotLights[i].direction);shader.setVec3(uniformName + "[" + to_string(i) + "].ambient", spotLights[i].ambient);shader.setVec3(uniformName + "[" + to_string(i) + "].diffuse", spotLights[i].diffuse);shader.setVec3(uniformName + "[" + to_string(i) + "].specular", spotLights[i].specular);shader.setFloat(uniformName + "[" + to_string(i) + "].constant", spotLights->constant);shader.setFloat(uniformName + "[" + to_string(i) + "].linear", spotLights->linear);shader.setFloat(uniformName + "[" + to_string(i) + "].quadratic", spotLights->quadratic);shader.setFloat(uniformName + "[" + to_string(i) + "].cutOff", spotLights->cutOff);shader.setFloat(uniformName + "[" + to_string(i) + "].outerCutOff", spotLights->outerCutOff);}}
}

main.cpp:main.cpp:main.cpp:

#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>
#include "shader.h"
#include "stb_image.h"
#include "camera.h"
#include "texture.h"
#include "light.h"
using std::cout;//窗口回调函数
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{//绘图视口 3D坐标到2D坐标的转换(映射)和这些参数(宽高)有关glViewport(0, 0, width, height);
}//键盘回调
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);//鼠标回调
void mouse_callback(GLFWwindow* window, double xpos, double ypos);//滚轮回调
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);//窗口初始大小
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;//物体着色器
const char* vShaderPath = "ShaderFiles/shader.vert";
const char* fShaderPath = "ShaderFiles/shader.frag";
//光源着色器
const char* lightvShaderPath = "ShaderFiles/light_shader.vert";
const char* lightfShaderPath = "ShaderFiles/light_shader.frag";//混合颜色的插值
float mixValue = 0.2f;
//记录鼠标坐标
float lastX, lastY;
bool firstMouse = true;//摄像机
Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));//光源位置
glm::vec3 lightPos(1.2f, 1.0f, 2.0f);int main()
{//glfw初始化glfwInit();//告诉glfw我们所使用的opengl版本 此处为3.3glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);//创建窗口GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);if (window == NULL){cout << "Failed to create GLFW window\n";glfwTerminate();return -1;}glfwMakeContextCurrent(window);glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);//设置窗口回调函数glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);//键盘回调函数glfwSetKeyCallback(window, key_callback);//鼠标回调glfwSetCursorPosCallback(window, mouse_callback);//滚轮回调glfwSetScrollCallback(window, scroll_callback);if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){cout << "Failed to initialize GLAD\n";return -1;}//开启深度测试glEnable(GL_DEPTH_TEST);//着色器对象Shader objectShaderProgram = Shader(vShaderPath, fShaderPath);Shader lightShaderProgram = Shader(lightvShaderPath, lightfShaderPath);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};// 10个箱子的位置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)};// 4个点光源的位置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)};//顶点缓冲对象 VBO//顶点数组对象 VAOunsigned int VBO, VAO;//渲染物体glGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);glBindVertexArray(VAO);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 lightVAO;glGenVertexArrays(1, &lightVAO);glBindVertexArray(lightVAO);glBindBuffer(GL_ARRAY_BUFFER, VBO);glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);glEnableVertexAttribArray(0);//漫反射贴图Texture diffuseTexture("diffuseTexture", "Images/container2_diffuse.png");//镜面光贴图Texture specularTexture("specuTexture", "Images/container2_specular.png");//Texture specularTexture("specuTexture", "Images/lighting_maps_specular_color.png");//放射光贴图//Texture emissionTexture("emissionTexture", "Images/emission_map.jpg");//线框模式//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);//方向光 依次传入的参数是 direction ambient diffuse specularDirLight dirLight(glm::vec3(-0.2f, -1.0f, -0.3f), glm::vec3(0.05f, 0.05f, 0.05f), glm::vec3(0.4f, 0.4f, 0.4f), glm::vec3(0.5f, 0.5f, 0.5f));//点光源 传入的参数一次是 position ambient diffuse specular constant linear quadratic 后三个浮点值有默认值PointLight pointLights[] = {PointLight(pointLightPositions[0],glm::vec3(0.05f,0.05f,0.05f),glm::vec3(0.8f,0.8f,0.8f),glm::vec3(1.0f,1.0f,1.0f)),PointLight(pointLightPositions[1],glm::vec3(0.05f,0.05f,0.05f),glm::vec3(0.8f,0.8f,0.8f),glm::vec3(1.0f,1.0f,1.0f)),PointLight(pointLightPositions[2],glm::vec3(0.05f,0.05f,0.05f),glm::vec3(0.8f,0.8f,0.8f),glm::vec3(1.0f,1.0f,1.0f)),PointLight(pointLightPositions[3],glm::vec3(0.05f,0.05f,0.05f),glm::vec3(0.8f,0.8f,0.8f),glm::vec3(1.0f,1.0f,1.0f))};//聚光 传入的参数依次是 position direction ambient diffuse specular constant linear quadratic cutOff outerCutOff 后五个浮点值有默认值SpotLight spotLight(camera.Position, camera.Front, glm::vec3(0.2f, 0.2f, 0.2f), glm::vec3(0.5f, 0.5f, 0.5f), glm::vec3(1.0f, 1.0f, 1.0f));//这些uniform不会更新 可以放到循环外面objectShaderProgram.use();objectShaderProgram.setInt("material.diffuse", diffuseTexture.getTextureUnitID());objectShaderProgram.setInt("material.specular", specularTexture.getTextureUnitID());objectShaderProgram.setFloat("material.shininess", 32.0f);while (!glfwWindowShouldClose(window)){glClearColor(0.1f, 0.1f, 0.1f, 0.1f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//矩阵运算glm::mat4 view = camera.GetViewMatrix();glm::mat4 projection = glm::perspective(glm::radians(camera.Fov), SCR_WIDTH * 1.0f / SCR_HEIGHT, 0.1f, 100.0f);//激活着色器objectShaderProgram.use();objectShaderProgram.setVec3("viewPos", camera.Position);objectShaderProgram.setMat4("view", view);objectShaderProgram.setMat4("projection", projection);//把光源的属性值传给着色器setLightAllAttribute(objectShaderProgram, "dirLight", &dirLight);setLightAllAttribute(objectShaderProgram, "pointLights", pointLights, 4);spotLight.position = camera.Position;spotLight.direction = camera.Front;setLightAllAttribute(objectShaderProgram, "spotLight", &spotLight);//贴图diffuseTexture.use();specularTexture.use();glBindVertexArray(VAO);// 10个立方体for (unsigned int i = 0; i < 10; i++){glm::mat4 objectModel(1.0f);objectModel = glm::translate(objectModel, cubePositions[i]);float angle = 20.0f * i;objectModel = glm::rotate(objectModel, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));objectShaderProgram.setMat4("model", objectModel);glDrawArrays(GL_TRIANGLES, 0, 36);}//光源着色器lightShaderProgram.use();lightShaderProgram.setMat4("view", view);lightShaderProgram.setMat4("projection", projection);glBindVertexArray(lightVAO);// 4个点光源for (unsigned int i = 0; i < 4; i++){glm::mat4 lightModel(1.0f);lightModel = glm::translate(lightModel, pointLightPositions[i]);lightModel = glm::scale(lightModel, glm::vec3(0.2f));lightShaderProgram.setMat4("model", lightModel);glDrawArrays(GL_TRIANGLES, 0, 36);}glfwSwapBuffers(window);glfwPollEvents();}//这一步是可选的glDeleteVertexArrays(1, &VAO);glDeleteBuffers(1, &VBO);//glDeleteBuffers(1, &EBO);//释放资源glfwTerminate();return 0;
}void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{if (action == GLFW_REPEAT || action == GLFW_PRESS){if (key == GLFW_KEY_ESCAPE){glfwSetWindowShouldClose(window, GL_TRUE);return;}switch (key){case GLFW_KEY_UP:mixValue += 0.1f;if (mixValue >= 1.0f)mixValue = 1.0f;break;case GLFW_KEY_DOWN:mixValue -= 0.1f;if (mixValue <= 0.0f)mixValue = 0.0f;break;case GLFW_KEY_W:camera.ProcessKeyboard(FORWARD);break;case GLFW_KEY_S:camera.ProcessKeyboard(BACKWARD);break;case GLFW_KEY_A:camera.ProcessKeyboard(LEFT);break;case GLFW_KEY_D:camera.ProcessKeyboard(RIGHT);break;default:break;}}
}void mouse_callback(GLFWwindow* window, double xpos, double ypos)
{if (firstMouse){firstMouse = false;lastX = xpos, lastY = ypos;}camera.ProcessMouseMovement(xpos - lastX, lastY - ypos);lastX = xpos;lastY = ypos;
}void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{camera.ProcessMouseScroll(yoffset);
}

总结

这一节就是把上一节学习的所有光源结合到一起了,感觉没啥好多说的……可以提一下数组类型uniformuniformuniform变量的设置,需要加上对应的下标:

练习

你能通过调节光照属性变量,(大概地)重现最后一张图片上不同的氛围吗?

试了一下factory的效果,其他的可以看答案自己设置。

注意这里修改了四个光源的颜色,所以也要修改光源的片段着色器:

#version 330 core
out vec4 FragColor;uniform vec3 lightColor;void main()
{FragColor = vec4(lightColor,1.0);
}

LearnOpenGL 光照—多光源相关推荐

  1. LearnOpenGL 光照—材质

    文章目录 写在前面 材质 设置材质 光的属性 不同的光源颜色 总结 练习 写在前面 原文链接.原文应该是github上的一个项目,本文主要用来记录一些知识点和自己遇到的问题. 材质 在现实世界里,每个 ...

  2. LearnOpenGL 光照—光照贴图

    文章目录 写在前面 光照贴图 漫反射贴图 镜面光贴图 采样镜面光贴图 总结 写在前面 原文链接.原文应该是github上的一个项目,本文主要用来记录一些知识点和自己遇到的问题. 光照贴图 在上一节中, ...

  3. LearnOpenGL 光照—光照贴图—练习(放射光贴图)

    文章目录 初始代码 练习一 练习二 练习三 练习四 初始代码 l i g h t s h a d e r : light\ shader: light shader: #version 330 cor ...

  4. 【OpenGL】二十二、OpenGL 光照效果 ( 模型准备 | 光照设置 | 启用光照 | 启用光源 | 设置光源位置 | 设置光照参数 | 设置环境光 | 设置反射材质 | 设置法线 )

    文章目录 一.模型准备 二.光照设置 1.启用光照设置 2.启用光源 3.设置光照参数 4.设置环境光 5.设置反射材质 三.光照法线设置 1.设置光源位置 2.设置法线 3.代码示例及运行效果 四. ...

  5. LearnOpenGL学习笔记—PBR:IBL

    LearnOpenGL学习笔记-PBR:IBL 0 引入 1 渲染方程的求解 2 hdr文件转成cubemap 3 预计算漫反射积分 4 预计算镜面反射积分 4.1 预滤波HDR环境贴图 4.1.1 ...

  6. OpenGL进阶(十三) - GLSL光照(Lighting)

    提要 在上一篇文章中,我们介绍了简单的Shading,同时提出了一个光照模型,模拟了一个点光源,但是,关于光的故事还没有结束... 今天要学习的是方向光源(Directional Light),聚光灯 ...

  7. Unity Shader入门精要学习笔记 - 第6章 开始 Unity 中的基础光照

    转自冯乐乐的<Unity Shader入门精要> 通常来讲,我们要模拟真实的光照环境来生成一张图像,需要考虑3种物理现象. 首先,光线从光源中被发射出来. 然后,光线和场景中的一些物体相交 ...

  8. VTK修炼之道7_三维场景基本要素:光照

    1.VTK中的光照长得什么样? 剧场里有各式各样的灯光,三维渲染场景中也一样,可以有多个光照存在.光照和相机是三维渲染场景必备的因素,如果没有指定,vtkRenderer会自动地创建默认的光照和相机. ...

  9. GPU Gems1 - 10 电影级的光照

    本章中介绍了一个的简化的uberlight(可理解为"全能光照")实现,此光照shader根据Ronen Barzel(1997,1999)提出的照明模型编写而成.而该模型的超集已 ...

最新文章

  1. javascript柱状统计图表
  2. Android OpenGL ES 2.0绘制简单三角形
  3. 七夕节福利,一套java架构师资源等你拿
  4. php并发访问排队_PHP高并发处理方案
  5. Boost.Signals2 的多槽 hello world 示例
  6. windows 2008 R2 如何更新SID
  7. 中国人工智能学会通讯——人工智能在各医学亚专科的发展现状及趋势 1.6 结束语...
  8. 浏览器下载2014正式版官方免费下载
  9. 手机数据恢复软件哪个好用?
  10. php的优秀案例,单页Web设计优秀案例_php
  11. 设计自制编程语言Monkey编译器:使用普拉特解析法解析复杂的算术表达式
  12. 【历史上的今天】3 月 16 日:开源精神奠基人诞生;技术先驱为女儿发明拍照手机;Minix 开发者出生
  13. MSP432蓝牙遥控小车
  14. P4848 崂山白花蛇草水
  15. seek()函数与tell()函数
  16. redis实现计时器
  17. 马伯骞、法老助力,realme真我5G旗舰发布
  18. API服务平台,服务管理与发布平台
  19. Threejs从入门到。。。。。。。还是入门
  20. xuetr使用注意笔记

热门文章

  1. redis mysql qps_测算Redis处理实际生产请求的QPS/TPS
  2. VB中Byval和byref的区别
  3. 树莓派计算器c语言,树莓派与Python实验9——Tkinter计算器实验
  4. 折腾黑群晖之域名直接访问群晖
  5. 实现点击选择按钮时候选中对应选中的行,当点击某一行单元格时候就清除其他选中行然后选中对应点击的那一行
  6. 我已经可以想象,疫情结束后全国男生会……
  7. 路由器端口映射以及远程连接
  8. DCDC--Burst Mode和Pulse Skipping Mode
  9. ARC059 E - Children and Candies(dp)
  10. 今天,我和C开始交往了