转自
https://learnopengl-cn.github.io/02%20Lighting/06%20Multiple%20lights/
1,多光源
当我们在场景中使用多个光源时,通常使用以下方法:我们需要有一个单独的颜色向量代表片段的输出颜色。对于每一个光源,它对片段的贡献颜色将会加到片段的输出颜色向量上。所以场景中的每个光源都会计算它们各自对片段的影响,并结合为一个最终的输出颜色。大体的结构会像是这样:
out vec4 FragColor; void main() { // 定义一个输出颜色值 vec3 output; // 将定向光的贡献加到输出中 output += someFunctionToCalculateDirectionalLight(); // 对所有的点光源也做相同的事情 for(int i = 0; i < nr_of_point_lights; i++) output += someFunctionToCalculatePointLight(); // 也加上其它的光源(比如聚光) output += someFunctionToCalculateSpotLight(); FragColor = vec4(output, 1.0); }
实际的代码对每一种实现都可能不同,但大体的结构都是差不多的。我们定义了几个函数,用来计算每个光源的影响,并将最终的结果颜色加到输出颜色向量上。例如,如果两个光源都很靠近一个片段,那么它们所结合的贡献将会形成一个比单个光源照亮时更加明亮的片段。
2, 定向光
我么需要在片段着色器中定义一个函数来计算定向光对相应片段的贡献:它接受一些参数并计算一个定向光照颜色。
首先,我们需要定义一个定向光源最少所需要的变量。我们可以将这些变量储存在一个叫做DirLight的结构体中,并将它定义为一个uniform。需要的变量在上一节中都介绍过:
struct DirLight { vec3 direction; vec3 ambient; vec3 diffuse; vec3 specular; }; uniform DirLight dirLight;
接下来我们可以将dirLight传入一个有着一下原型的函数。
vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir);
你可以看到,这个函数需要一个DirLight结构体和其它两个向量来进行计算。
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); }
3,点光源
和定向光一样,我们也希望定义一个用于计算点光源对相应片段贡献,以及衰减,的函数。同样,我们定义一个包含了点光源所需所有变量的结构体:
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];
你可以看到,我们在GLSL中使用了预处理指令来定义了我们场景中点光源的数量。接着我们使用了这个NR_POINT_LIGHTS常量来创建了一个PointLight结构体的数组。GLSL中的数组和C数组一样,可以使用一对方括号来创建。现在我们有四个待填充数据的PointLight结构体。
我们也可以定义一个大的结构体(而不是为每种类型的光源定义不同的结构体),包含所有不同种光照类型所需的变量,并将这个结构体用到所有的函数中,只需要忽略用不到的变量就行了。然而,我个人觉得当前的方法会更直观一点,不仅能够节省一些代码,而且由于不是所有光照类型都需要所有的变量,这样也能节省一些内存。
点光源函数的原型如下:
vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir);
这个函数从参数中获取所需的所有数据,并返回一个代表该点光源对片段的颜色贡献的vec3
。我们再一次聪明地从之前的教程中复制粘贴代码,完成了下面这样的函数:
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); }
4,合并结果
现在我们已经定义了一个计算定向光的函数和一个计算点光源的函数了,我们可以将它们合并放到main函数中。
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); }
每个光源类型都将它们的贡献加到了最终的输出颜色上,直到所有的光源都处理完了。最终的颜色包含了场景中所有光源的颜色影响所合并的结果。如果你想的话,你也可以实现一个聚光,并将它的效果加到输出颜色中。我们会将CalcSpotLight函数留给读者作为练习。
设置定向光结构体的uniform应该非常熟悉了,但是你可能会在想我们该如何设置点光源的uniform值,因为点光源的uniform现在是一个PointLight的数组了。这并不是我们以前讨论过的话题。
很幸运的是,这并不是很复杂,设置一个结构体数组的uniform和设置一个结构体的uniform是很相似的,但是这一次在访问uniform位置的时候,我们需要定义对应的数组下标值:
lightingShader.setFloat("pointLights[0].constant", 1.0f);
在这里我们索引了pointLights数组中的第一个PointLight,并获取了constant变量的位置。但这也意味着不幸的是我们必须对这四个点光源手动设置uniform值,这让点光源本身就产生了28个uniform调用,非常冗长。你也可以尝试将这些抽象出去一点,定义一个点光源类,让它来为你设置uniform值,但最后你仍然要用这种方式设置所有光源的uniform值。
别忘了,我们还需要为每个点光源定义一个位置向量,所以我们让它们在场景中分散一点。我们会定义另一个glm::vec3
数组来包含点光源的位置:
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) };
5,最后放上所有源代码:
1 #include <glad/glad.h> 2 #include <GLFW/glfw3.h> 3 4 #include <glm/glm.hpp> 5 #include <glm/gtc/matrix_transform.hpp> 6 #include <glm/gtc/type_ptr.hpp> 7 8 #include "stb_image.h" 9 #include "shader_s.h" 10 #include "Camera.h" 11 #include <iostream> 12 //("../res/light/colors.vs", "../res/light/colors.fs") 13 14 void framebuffer_size_callback(GLFWwindow* window, int width, int height); 15 void mouse_callback(GLFWwindow* window, double xpos, double ypos); 16 void scroll_callback(GLFWwindow* window, double xoffset, double yoffset); 17 void processInput(GLFWwindow *window); 18 unsigned int loadTexture(const char *path); 19 20 // settings 21 const unsigned int SCR_WIDTH = 800; 22 const unsigned int SCR_HEIGHT = 600; 23 24 // camera 25 Camera camera(glm::vec3(0.0f, 0.0f, 3.0f)); 26 float lastX = SCR_WIDTH / 2.0f; 27 float lastY = SCR_HEIGHT / 2.0f; 28 bool firstMouse = true; 29 30 // timing 31 float deltaTime = 0.0f; 32 float lastFrame = 0.0f; 33 34 // lighting 35 glm::vec3 lightPos(1.2f, 1.0f, 2.0f); 36 37 int main() 38 { 39 // glfw: initialize and configure 40 // ------------------------------ 41 glfwInit(); 42 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 43 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); 44 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 45 46 #ifdef __APPLE__ 47 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X 48 #endif 49 50 // glfw window creation 51 // -------------------- 52 GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL); 53 if (window == NULL) 54 { 55 std::cout << "Failed to create GLFW window" << std::endl; 56 glfwTerminate(); 57 return -1; 58 } 59 glfwMakeContextCurrent(window); 60 glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); 61 glfwSetCursorPosCallback(window, mouse_callback); 62 glfwSetScrollCallback(window, scroll_callback); 63 64 // tell GLFW to capture our mouse 65 glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); 66 67 // glad: load all OpenGL function pointers 68 // --------------------------------------- 69 if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) 70 { 71 std::cout << "Failed to initialize GLAD" << std::endl; 72 return -1; 73 } 74 75 // configure global opengl state 76 // ----------------------------- 77 glEnable(GL_DEPTH_TEST); 78 79 80 // build and compile our shader zprogram 81 // ("../res/light/colors.vs", "../res/light/colors.fs") 82 Shader lightingShader("../res/light/materials.vs", "../res/light/materials.fs"); 83 Shader lampShader("../res/light/lamp.vs", "../res/light/lamp.fs"); 84 // set up vertex data (and buffer(s)) and configure vertex attributes 85 // ------------------------------------------------------------------ 86 float vertices[] = { 87 // positions // normals // texture coords 88 -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 89 0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 90 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, 91 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, 92 -0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 93 -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 94 95 -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 96 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 97 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 98 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 99 -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 100 -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 101 102 -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 103 -0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 104 -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 105 -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 106 -0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 107 -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 108 109 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 110 0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 111 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 112 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 113 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 114 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 115 116 -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 117 0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f, 118 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 119 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 120 -0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 121 -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 122 123 -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 124 0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 125 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 126 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 127 -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 128 -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f 129 }; 130 // positions all containers 131 glm::vec3 cubePositions[] = { 132 glm::vec3(0.0f, 0.0f, 0.0f), 133 glm::vec3(2.0f, 5.0f, -15.0f), 134 glm::vec3(-1.5f, -2.2f, -2.5f), 135 glm::vec3(-3.8f, -2.0f, -12.3f), 136 glm::vec3(2.4f, -0.4f, -3.5f), 137 glm::vec3(-1.7f, 3.0f, -7.5f), 138 glm::vec3(1.3f, -2.0f, -2.5f), 139 glm::vec3(1.5f, 2.0f, -2.5f), 140 glm::vec3(1.5f, 0.2f, -1.5f), 141 glm::vec3(-1.3f, 1.0f, -1.5f) 142 }; 143 // positions of the point lights 144 glm::vec3 pointLightPositions[] = { 145 glm::vec3(0.7f, 0.2f, 2.0f), 146 glm::vec3(2.3f, -3.3f, -4.0f), 147 glm::vec3(-4.0f, 2.0f, -12.0f), 148 glm::vec3(0.0f, 0.0f, -3.0f) 149 }; 150 // first, configure the cube's VAO (and VBO) 151 unsigned int VBO, cubeVAO; 152 glGenVertexArrays(1, &cubeVAO); 153 glGenBuffers(1, &VBO); 154 155 glBindBuffer(GL_ARRAY_BUFFER, VBO); 156 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); 157 158 glBindVertexArray(cubeVAO); 159 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0); 160 glEnableVertexAttribArray(0); 161 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float))); 162 glEnableVertexAttribArray(1); 163 glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float))); 164 glEnableVertexAttribArray(2); 165 166 // second, configure the light's VAO (VBO stays the same; the vertices are the same for the light object which is also a 3D cube) 167 unsigned int lightVAO; 168 glGenVertexArrays(1, &lightVAO); 169 glBindVertexArray(lightVAO); 170 171 glBindBuffer(GL_ARRAY_BUFFER, VBO); 172 // note that we update the lamp's position attribute's stride to reflect the updated buffer data 173 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0); 174 glEnableVertexAttribArray(0); 175 176 // load textures (we now use a utility function to keep the code more organized) 177 // ----------------------------------------------------------------------------- 178 unsigned int diffuseMap = loadTexture("../res/light/container2.png"); 179 unsigned int specularMap = loadTexture("../res/light/container2_specular.png"); 180 //std::cout << diffuseMap; 181 //unsigned int diffuseMap = loadTexture(FileSystem::getPath("res/light/container2.png").c_str()); 182 183 // shader configuration 184 // -------------------- 185 lightingShader.use(); 186 lightingShader.setInt("material.diffuse", 0); 187 lightingShader.setInt("material.specular", 1); 188 189 190 // render loop 191 // ----------- 192 while (!glfwWindowShouldClose(window)) 193 { 194 // per-frame time logic 195 // -------------------- 196 float currentFrame = glfwGetTime(); 197 deltaTime = currentFrame - lastFrame; 198 lastFrame = currentFrame; 199 200 // input 201 // ----- 202 processInput(window); 203 204 // render 205 // ------ 206 glClearColor(0.1f, 0.1f, 0.1f, 1.0f); 207 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 208 209 // be sure to activate shader when setting uniforms/drawing objects 210 lightingShader.use(); 211 lightingShader.setVec3("viewPos", camera.Position); 212 lightingShader.setFloat("material.shininess", 32.0f); 213 214 /* 215 Here we set all the uniforms for the 5/6 types of lights we have. We have to set them manually and index 216 the proper PointLight struct in the array to set each uniform variable. This can be done more code-friendly 217 by defining light types as classes and set their values in there, or by using a more efficient uniform approach 218 by using 'Uniform buffer objects', but that is something we'll discuss in the 'Advanced GLSL' tutorial. 219 */ 220 // directional light 221 lightingShader.setVec3("dirLight.direction", -0.2f, -1.0f, -0.3f); 222 lightingShader.setVec3("dirLight.ambient", 0.05f, 0.05f, 0.05f); 223 lightingShader.setVec3("dirLight.diffuse", 0.4f, 0.4f, 0.4f); 224 lightingShader.setVec3("dirLight.specular", 0.5f, 0.5f, 0.5f); 225 // point light 1 226 lightingShader.setVec3("pointLights[0].position", pointLightPositions[0]); 227 lightingShader.setVec3("pointLights[0].ambient", 0.05f, 0.05f, 0.05f); 228 lightingShader.setVec3("pointLights[0].diffuse", 0.8f, 0.8f, 0.8f); 229 lightingShader.setVec3("pointLights[0].specular", 1.0f, 1.0f, 1.0f); 230 lightingShader.setFloat("pointLights[0].constant", 1.0f); 231 lightingShader.setFloat("pointLights[0].linear", 0.09); 232 lightingShader.setFloat("pointLights[0].quadratic", 0.032); 233 // point light 2 234 lightingShader.setVec3("pointLights[1].position", pointLightPositions[1]); 235 lightingShader.setVec3("pointLights[1].ambient", 0.05f, 0.05f, 0.05f); 236 lightingShader.setVec3("pointLights[1].diffuse", 0.8f, 0.8f, 0.8f); 237 lightingShader.setVec3("pointLights[1].specular", 1.0f, 1.0f, 1.0f); 238 lightingShader.setFloat("pointLights[1].constant", 1.0f); 239 lightingShader.setFloat("pointLights[1].linear", 0.09); 240 lightingShader.setFloat("pointLights[1].quadratic", 0.032); 241 // point light 3 242 lightingShader.setVec3("pointLights[2].position", pointLightPositions[2]); 243 lightingShader.setVec3("pointLights[2].ambient", 0.05f, 0.05f, 0.05f); 244 lightingShader.setVec3("pointLights[2].diffuse", 0.8f, 0.8f, 0.8f); 245 lightingShader.setVec3("pointLights[2].specular", 1.0f, 1.0f, 1.0f); 246 lightingShader.setFloat("pointLights[2].constant", 1.0f); 247 lightingShader.setFloat("pointLights[2].linear", 0.09); 248 lightingShader.setFloat("pointLights[2].quadratic", 0.032); 249 // point light 4 250 lightingShader.setVec3("pointLights[3].position", pointLightPositions[3]); 251 lightingShader.setVec3("pointLights[3].ambient", 0.05f, 0.05f, 0.05f); 252 lightingShader.setVec3("pointLights[3].diffuse", 0.8f, 0.8f, 0.8f); 253 lightingShader.setVec3("pointLights[3].specular", 1.0f, 1.0f, 1.0f); 254 lightingShader.setFloat("pointLights[3].constant", 1.0f); 255 lightingShader.setFloat("pointLights[3].linear", 0.09); 256 lightingShader.setFloat("pointLights[3].quadratic", 0.032); 257 // spotLight 258 lightingShader.setVec3("spotLight.position", camera.Position); 259 lightingShader.setVec3("spotLight.direction", camera.Front); 260 lightingShader.setVec3("spotLight.ambient", 0.0f, 0.0f, 0.0f); 261 lightingShader.setVec3("spotLight.diffuse", 1.0f, 1.0f, 1.0f); 262 lightingShader.setVec3("spotLight.specular", 1.0f, 1.0f, 1.0f); 263 lightingShader.setFloat("spotLight.constant", 1.0f); 264 lightingShader.setFloat("spotLight.linear", 0.09); 265 lightingShader.setFloat("spotLight.quadratic", 0.032); 266 lightingShader.setFloat("spotLight.cutOff", glm::cos(glm::radians(12.5f))); 267 lightingShader.setFloat("spotLight.outerCutOff", glm::cos(glm::radians(15.0f))); 268 269 // view/projection transformations 270 glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f); 271 glm::mat4 view = camera.GetViewMatrix(); 272 lightingShader.setMat4("projection", projection); 273 lightingShader.setMat4("view", view); 274 275 // world transformation 276 glm::mat4 model = glm::mat4(1.0f); 277 lightingShader.setMat4("model", model); 278 279 // bind diffuse map 280 glActiveTexture(GL_TEXTURE0); 281 glBindTexture(GL_TEXTURE_2D, diffuseMap); 282 // bind specular map 283 glActiveTexture(GL_TEXTURE1); 284 glBindTexture(GL_TEXTURE_2D, specularMap); 285 286 // render containers 287 glBindVertexArray(cubeVAO); 288 for (unsigned int i = 0; i < 10; i++) 289 { 290 // calculate the model matrix for each object and pass it to shader before drawing 291 glm::mat4 model = glm::mat4(1.0f); 292 model = glm::translate(model, cubePositions[i]); 293 float angle = 20.0f * i; 294 model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f)); 295 lightingShader.setMat4("model", model); 296 297 glDrawArrays(GL_TRIANGLES, 0, 36); 298 } 299 300 // also draw the lamp object(s) 301 lampShader.use(); 302 lampShader.setMat4("projection", projection); 303 lampShader.setMat4("view", view); 304 305 // we now draw as many light bulbs as we have point lights. 306 glBindVertexArray(lightVAO); 307 for (unsigned int i = 0; i < 4; i++) 308 { 309 model = glm::mat4(1.0f); 310 model = glm::translate(model, pointLightPositions[i]); 311 model = glm::scale(model, glm::vec3(0.2f)); // Make it a smaller cube 312 lampShader.setMat4("model", model); 313 glDrawArrays(GL_TRIANGLES, 0, 36); 314 } 315 316 317 // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) 318 // ------------------------------------------------------------------------------- 319 glfwSwapBuffers(window); 320 glfwPollEvents(); 321 } 322 323 // optional: de-allocate all resources once they've outlived their purpose: 324 // ------------------------------------------------------------------------ 325 glDeleteVertexArrays(1, &cubeVAO); 326 glDeleteVertexArrays(1, &lightVAO); 327 glDeleteBuffers(1, &VBO); 328 329 // glfw: terminate, clearing all previously allocated GLFW resources. 330 // ------------------------------------------------------------------ 331 glfwTerminate(); 332 return 0; 333 } 334 335 // process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly 336 // --------------------------------------------------------------------------------------------------------- 337 void processInput(GLFWwindow *window) 338 { 339 if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) 340 glfwSetWindowShouldClose(window, true); 341 342 if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) 343 camera.ProcessKeyboard(FORWARD, deltaTime); 344 if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) 345 camera.ProcessKeyboard(BACKWARD, deltaTime); 346 if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) 347 camera.ProcessKeyboard(LEFT, deltaTime); 348 if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) 349 camera.ProcessKeyboard(RIGHT, deltaTime); 350 } 351 352 // glfw: whenever the window size changed (by OS or user resize) this callback function executes 353 // --------------------------------------------------------------------------------------------- 354 void framebuffer_size_callback(GLFWwindow* window, int width, int height) 355 { 356 // make sure the viewport matches the new window dimensions; note that width and 357 // height will be significantly larger than specified on retina displays. 358 glViewport(0, 0, width, height); 359 } 360 361 362 // glfw: whenever the mouse moves, this callback is called 363 // ------------------------------------------------------- 364 void mouse_callback(GLFWwindow* window, double xpos, double ypos) 365 { 366 if (firstMouse) 367 { 368 lastX = xpos; 369 lastY = ypos; 370 firstMouse = false; 371 } 372 373 float xoffset = xpos - lastX; 374 float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top 375 376 lastX = xpos; 377 lastY = ypos; 378 379 camera.ProcessMouseMovement(xoffset, yoffset); 380 } 381 382 // glfw: whenever the mouse scroll wheel scrolls, this callback is called 383 // ---------------------------------------------------------------------- 384 void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) 385 { 386 camera.ProcessMouseScroll(yoffset); 387 } 388 unsigned int loadTexture(char const * path) 389 { 390 unsigned int textureID; 391 glGenTextures(1, &textureID); 392 393 int width, height, nrComponents; 394 unsigned char *data = stbi_load(path, &width, &height, &nrComponents, 0); 395 if (data) 396 { 397 GLenum format; 398 if (nrComponents == 1) 399 format = GL_RED; 400 else if (nrComponents == 3) 401 format = GL_RGB; 402 else if (nrComponents == 4) 403 format = GL_RGBA; 404 405 glBindTexture(GL_TEXTURE_2D, textureID); 406 glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data); 407 glGenerateMipmap(GL_TEXTURE_2D); 408 409 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 410 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 411 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); 412 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 413 414 stbi_image_free(data); 415 } 416 else 417 { 418 std::cout << "Texture failed to load at path: " << path << std::endl; 419 stbi_image_free(data); 420 } 421 422 return textureID; 423 }
1 #version 330 core 2 layout (location = 0) in vec3 aPos; 3 layout (location = 1) in vec3 aNormal; 4 layout (location = 2) in vec2 aTexCoords; 5 6 out vec3 FragPos; 7 out vec3 Normal; 8 out vec2 TexCoords; 9 10 uniform mat4 model; 11 uniform mat4 view; 12 uniform mat4 projection; 13 14 void main() 15 { 16 FragPos = vec3(model * vec4(aPos, 1.0)); 17 Normal = mat3(transpose(inverse(model))) * aNormal; 18 TexCoords = aTexCoords; 19 20 gl_Position = projection * view * vec4(FragPos, 1.0); 21 }
1 #version 330 core 2 out vec4 FragColor; 3 4 struct Material { 5 sampler2D diffuse; 6 sampler2D specular; 7 float shininess; 8 }; 9 10 struct DirLight { 11 vec3 direction; 12 13 vec3 ambient; 14 vec3 diffuse; 15 vec3 specular; 16 }; 17 18 struct PointLight { 19 vec3 position; 20 21 float constant; 22 float linear; 23 float quadratic; 24 25 vec3 ambient; 26 vec3 diffuse; 27 vec3 specular; 28 }; 29 30 struct SpotLight { 31 vec3 position; 32 vec3 direction; 33 float cutOff; 34 float outerCutOff; 35 36 float constant; 37 float linear; 38 float quadratic; 39 40 vec3 ambient; 41 vec3 diffuse; 42 vec3 specular; 43 }; 44 45 #define NR_POINT_LIGHTS 4 46 47 in vec3 FragPos; 48 in vec3 Normal; 49 in vec2 TexCoords; 50 51 uniform vec3 viewPos; 52 uniform DirLight dirLight; 53 uniform PointLight pointLights[NR_POINT_LIGHTS]; 54 uniform SpotLight spotLight; 55 uniform Material material; 56 57 // function prototypes 58 vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir); 59 vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir); 60 vec3 CalcSpotLight(SpotLight light, vec3 normal, vec3 fragPos, vec3 viewDir); 61 62 void main() 63 { 64 // properties 65 vec3 norm = normalize(Normal); 66 vec3 viewDir = normalize(viewPos - FragPos); 67 68 // == ===================================================== 69 // Our lighting is set up in 3 phases: directional, point lights and an optional flashlight 70 // For each phase, a calculate function is defined that calculates the corresponding color 71 // per lamp. In the main() function we take all the calculated colors and sum them up for 72 // this fragment's final color. 73 // == ===================================================== 74 // phase 1: directional lighting 75 vec3 result = CalcDirLight(dirLight, norm, viewDir); 76 // phase 2: point lights 77 for(int i = 0; i < NR_POINT_LIGHTS; i++) 78 result += CalcPointLight(pointLights[i], norm, FragPos, viewDir); 79 // phase 3: spot light 80 result += CalcSpotLight(spotLight, norm, FragPos, viewDir); 81 82 FragColor = vec4(result, 1.0); 83 } 84 85 // calculates the color when using a directional light. 86 vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir) 87 { 88 vec3 lightDir = normalize(-light.direction); 89 // diffuse shading 90 float diff = max(dot(normal, lightDir), 0.0); 91 // specular shading 92 vec3 reflectDir = reflect(-lightDir, normal); 93 float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess); 94 // combine results 95 vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords)); 96 vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords)); 97 vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords)); 98 return (ambient + diffuse + specular); 99 } 100 101 // calculates the color when using a point light. 102 vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir) 103 { 104 vec3 lightDir = normalize(light.position - fragPos); 105 // diffuse shading 106 float diff = max(dot(normal, lightDir), 0.0); 107 // specular shading 108 vec3 reflectDir = reflect(-lightDir, normal); 109 float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess); 110 // attenuation 111 float distance = length(light.position - fragPos); 112 float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance)); 113 // combine results 114 vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords)); 115 vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords)); 116 vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords)); 117 ambient *= attenuation; 118 diffuse *= attenuation; 119 specular *= attenuation; 120 return (ambient + diffuse + specular); 121 } 122 123 // calculates the color when using a spot light. 124 vec3 CalcSpotLight(SpotLight light, vec3 normal, vec3 fragPos, vec3 viewDir) 125 { 126 vec3 lightDir = normalize(light.position - fragPos); 127 // diffuse shading 128 float diff = max(dot(normal, lightDir), 0.0); 129 // specular shading 130 vec3 reflectDir = reflect(-lightDir, normal); 131 float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess); 132 // attenuation 133 float distance = length(light.position - fragPos); 134 float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance)); 135 // spotlight intensity 136 float theta = dot(lightDir, normalize(-light.direction)); 137 float epsilon = light.cutOff - light.outerCutOff; 138 float intensity = clamp((theta - light.outerCutOff) / epsilon, 0.0, 1.0); 139 // combine results 140 vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords)); 141 vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords)); 142 vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords)); 143 ambient *= attenuation * intensity; 144 diffuse *= attenuation * intensity; 145 specular *= attenuation * intensity; 146 return (ambient + diffuse + specular); 147 }
1 #version 330 core 2 layout (location = 0) in vec3 aPos; 3 4 uniform mat4 model; 5 uniform mat4 view; 6 uniform mat4 projection; 7 8 void main() 9 { 10 gl_Position = projection * view * model * vec4(aPos, 1.0); 11 }
1 #version 330 core 2 out vec4 FragColor; 3 4 void main() 5 { 6 FragColor = vec4(1.0); // set alle 4 vector values to 1.0 7 }
container2.png
container2_specular.png