diff options
author | jvech <jmvalenciae@unal.edu.co> | 2022-09-16 16:21:37 -0500 |
---|---|---|
committer | jvech <jmvalenciae@unal.edu.co> | 2022-09-16 16:21:37 -0500 |
commit | fc8d7fed3ccdf0998a7b9809aa825f2d14876b29 (patch) | |
tree | 45d1b4ff6435e79939be1198316e7973ab5695bb | |
parent | 6781af306edc8f6b0928013ed9ec2fa87d63da81 (diff) |
learn: 17. Multiple lights
-rw-r--r-- | shaders/color.fsh | 127 | ||||
-rw-r--r-- | src/main.c | 132 |
2 files changed, 207 insertions, 52 deletions
diff --git a/shaders/color.fsh b/shaders/color.fsh index c2a8dc7..a0958ed 100644 --- a/shaders/color.fsh +++ b/shaders/color.fsh @@ -1,4 +1,5 @@ -# version 330 core +#version 330 core +#define NR_POINT_LIGHTS 4 struct Material { sampler2D diffuse; @@ -6,13 +7,41 @@ struct Material { float shininess; }; -struct Light { +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 FlashLight { + vec3 position; + vec3 direction; + + vec3 ambient; + vec3 diffuse; + vec3 specular; + + float cutOff; + float outerCutOff; + float constant; + float linear; + float quadratic; +}; + in vec3 Normal; in vec3 FragPos; in vec2 TexCoords; @@ -21,24 +50,96 @@ out vec4 FragColor; uniform vec3 viewPos; uniform Material material; -uniform Light light; +uniform DirLight dirLight; +uniform PointLight pointLight[NR_POINT_LIGHTS]; +uniform FlashLight flashLight; -void main() +vec3 calcDirLight(DirLight light, vec3 normal, vec3 viewDir) { - // ambient + vec3 lightDir = normalize(-light.direction); + // diffuse + float diff = max(dot(normal, lightDir), 0.0); + // specular + vec3 reflectDir = reflect(-lightDir, normal); + float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess); + 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); +} + +vec3 calcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir) +{ + vec3 lightDir = normalize(light.position - fragPos); // diffuse - vec3 norm = normalize(Normal); - vec3 lightDir = normalize(light.position - FragPos); - float diff = max(dot(norm, lightDir), 0.0); + float diff = max(dot(normal, lightDir), 0.0); + + //specular + vec3 reflectDir = reflect(-lightDir, normal); + float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess); + + //attenuation + float dist = length(light.position - fragPos); + float attenuation = 1.0 / (light.constant + light.linear * dist + + light.quadratic * (dist * dist)); + + 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; - // specular - vec3 viewDir = normalize(viewPos - FragPos); - vec3 reflectDir = reflect(-lightDir, norm); + ambient *= attenuation; + diffuse *= attenuation; + specular *= attenuation; + + return ambient + diffuse + specular; +} + +vec3 calcFlashLight(FlashLight light, vec3 normal, vec3 fragPos, vec3 viewDir) +{ + vec3 lightDir = normalize(light.position - fragPos); + float theta = dot(lightDir, normalize(-light.direction)); + float epsilon = light.cutOff - light.outerCutOff; + float intensity = clamp((theta - light.outerCutOff) / epsilon, 0.0, 1.0); + + // diffuse + float diff = max(dot(normal, lightDir), 0.0); + + //specular + vec3 reflectDir = reflect(-lightDir, normal); float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess); + + //attenuation + float dist = length(light.position - fragPos); + float attenuation = 1.0 / (light.constant + light.linear * dist + + light.quadratic * (dist * dist)); + + 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; - FragColor = vec4((specular + ambient + diffuse), 1.0f); + diffuse *= attenuation * intensity; + specular *= attenuation * intensity; + + return ambient + diffuse + specular; +} + +void main() +{ + // properties + vec3 norm = normalize(Normal); + vec3 viewDir = normalize(viewPos - FragPos); + + // 1. Directional light + vec3 result = calcDirLight(dirLight, norm, viewDir); + + // 2. Point lights + for (int i = 0; i < NR_POINT_LIGHTS; i++) + result += calcPointLight(pointLight[i], norm, FragPos, viewDir); + + // 3. Spot light + result += calcFlashLight(flashLight, norm, FragPos, viewDir); + + FragColor = vec4(result, 1.0); } @@ -242,11 +242,11 @@ int main() glEnable(GL_DEPTH_TEST); stbi_set_flip_vertically_on_load(1); + unsigned int programColor = shaderCreateProgram("shaders/color.vsh", "shaders/color.fsh"); unsigned int programLight = shaderCreateProgram("shaders/lightsource.vsh", "shaders/lightsource.fsh"); - unsigned int VBO, VAO, lightVAO; int vertexSize = 8; @@ -275,11 +275,32 @@ int main() unsigned int diffuseMap = loadTexture("textures/container2.png"); unsigned int specularMap = loadTexture("textures/container2_specular.png"); - glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); + /*============ Initializations ===============*/ + + Vec3 cubePositions[] = { + linearVec3( 0.5f, 0.0f, 0.0f), + linearVec3( 2.0f, 5.0f, -15.0f), + linearVec3(-1.5f, -2.2f, -2.5f), + linearVec3(-3.8f, -2.0f, -12.3f), + linearVec3( 2.4f, -0.4f, -3.5f), + linearVec3(-1.7f, 3.0f, -7.5f), + linearVec3( 1.3f, -2.0f, -2.5f), + linearVec3( 1.5f, 2.0f, -2.5f), + linearVec3( 1.5f, 0.2f, -1.5f), + linearVec3(-1.3f, 1.0f, -1.5f) + }; + + Vec3 pointLightsPos[4] = { + linearVec3(0.7f, 0.2f, 2.0f), + linearVec3(2.3f, -3.3f, -4.0f), + linearVec3(-4.0f, 2.0f, -12.0f), + linearVec3(0.0f, 0.0f, -3.0f), + }; + struct Camera mainCamera; mainCamera.position = linearVec3(0.0, 0.0, 3.0); mainCamera.front = linearVec3(0.0, 0.0, -1.0); @@ -287,15 +308,18 @@ int main() Mat4 model, view, proj; Mat4 T, S, R; - Vec3 lightPos = linearVec3(0.0, 2.0, -7.0); + Vec3 dirLight = linearVec3(-0.2, -1.0, 0.3); + Vec3 ambient = linearVec3(0.0, 0.0, 0.0); + Vec3 diffuse = linearVec3(0.5, 0.5, 0.5); + Vec3 specular = linearVec3(1.0, 1.0, 1.0); float dt, t, t0; int width, height; t0 = 0; while (!glfwWindowShouldClose(window)) { processInput(window); - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* ------------------- @@ -305,38 +329,55 @@ int main() dt = t - t0; t0 = t; - // World Transformation - // -------------------- - T = linearTranslate(-3.0, 0.0, -2.0); - R = linearRotate(180 * t / M_PI, 0, 1, 0); - S = linearScale(1.0, 1.0, 1.0); - model = linearMat4Muln(3, T, R, S); - // Camera and view transformations - // ------------------------------- view = processCameraInput(window, &mainCamera, dt); glfwGetWindowSize(window, &width, &height); proj = linearPerspective(35, (float)width / height, 0.1, 100); - /* ---------------------------- - * Rendering - * ---------------------------- - */ glUseProgram(programColor); - shaderSetMatrixfv(programColor, "model", model.matrix[0], glUniformMatrix4fv); - shaderSetMatrixfv(programColor, "view", view.matrix[0], glUniformMatrix4fv); - shaderSetMatrixfv(programColor, "proj", proj.matrix[0], glUniformMatrix4fv); - shaderSetMatrixfv(programColor, "rotNormals", R.matrix[0], glUniformMatrix4fv); + float constant = 1.0; + float linear = 0.09; + float quadratic = 0.032f; + + shaderSetfv(programColor, "dirLight.direction", dirLight.vector, glUniform3fv); + shaderSetfv(programColor, "dirLight.ambient", ambient.vector, glUniform3fv); + shaderSetfv(programColor, "dirLight.diffuse", diffuse.vector, glUniform3fv); + shaderSetfv(programColor, "dirLight.specular", vec3(1.0, 1.0, 1.0), glUniform3fv); + + char varNames[7][50]; + for (int i = 0; i < 4; i++) { + sprintf(varNames[0], "pointLight[%d].position", i); + sprintf(varNames[1], "pointLight[%d].ambient", i); + sprintf(varNames[2], "pointLight[%d].diffuse", i); + sprintf(varNames[3], "pointLight[%d].specular", i); + sprintf(varNames[4], "pointLight[%d].constant", i); + sprintf(varNames[5], "pointLight[%d].linear", i); + sprintf(varNames[6], "pointLight[%d].quadratic", i); + + shaderSetfv(programColor, varNames[0], pointLightsPos[i].vector, glUniform3fv); + shaderSetfv(programColor, varNames[1], ambient.vector, glUniform3fv); + shaderSetfv(programColor, varNames[2], diffuse.vector, glUniform3fv); + shaderSetfv(programColor, varNames[3], specular.vector, glUniform3fv); + shaderSet1f(programColor, varNames[4], constant); + shaderSet1f(programColor, varNames[5], linear); + shaderSet1f(programColor, varNames[6], quadratic); + } + + shaderSetfv(programColor, "flashLight.position", mainCamera.position.vector, glUniform3fv); + shaderSetfv(programColor, "flashLight.direction", mainCamera.front.vector, glUniform3fv); + shaderSetfv(programColor, "flashLight.ambient", ambient.vector, glUniform3fv); + shaderSetfv(programColor, "flashLight.diffuse", vec3(0.8, 0.5, 0.5), glUniform3fv); + shaderSetfv(programColor, "flashLight.specular", vec3(1.0, 0.0, 0.0), glUniform3fv); + shaderSet1f(programColor, "flashLight.constant", constant); + shaderSet1f(programColor, "flashLight.linear", linear); + shaderSet1f(programColor, "flashLight.quadratic", quadratic); + shaderSet1f(programColor, "flashLight.cutOff", cosf(12.5f * M_PI / 180)); + shaderSet1f(programColor, "flashLight.outerCutOff", cosf(17.5f * M_PI / 180)); + shaderSetfv(programColor, "viewPos", mainCamera.position.vector, glUniform3fv); shaderSetfv(programColor, "material.specular", vec3(0.5, 0.5, 0.5), glUniform3fv); shaderSet1f(programColor, "material.shininess", 64.0f); - - shaderSetfv(programColor, "light.ambient", vec3(0.2, 0.2, 0.2), glUniform3fv); - shaderSetfv(programColor, "light.diffuse", vec3(0.5, 0.5, 0.5), glUniform3fv); - shaderSetfv(programColor, "light.specular", vec3(1.0, 1.0, 1.0), glUniform3fv); - shaderSetfv(programColor, "light.position", lightPos.vector, glUniform3fv); - shaderSetfv(programColor, "viewPos", mainCamera.position.vector, glUniform3fv); shaderSet1i(programColor, "material.diffuse", 0); shaderSet1i(programColor, "material.specular", 1); @@ -345,23 +386,36 @@ int main() glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, specularMap); - - glBindVertexArray(VAO); - glDrawArrays(GL_TRIANGLES, 0, sizeof(vertices) / sizeof(float)); + shaderSetMatrixfv(programColor, "view", view.matrix[0], glUniformMatrix4fv); + shaderSetMatrixfv(programColor, "proj", proj.matrix[0], glUniformMatrix4fv); + for (int i = 0; i < 10; i++) { + // World Transformation + // -------------------- + T = linearTranslatev(cubePositions[i]); + R = linearRotate(180 * i / M_PI, 1.0, 0.3, 0.5); + S = linearScale(1.0, 1.0, 1.0); + model = linearMat4Muln(3, T, R, S); + shaderSetMatrixfv(programColor, "model", model.matrix[0], glUniformMatrix4fv); + shaderSetMatrixfv(programColor, "rotNormals", R.matrix[0], glUniformMatrix4fv); + + glBindVertexArray(VAO); + glDrawArrays(GL_TRIANGLES, 0, sizeof(vertices) / sizeof(float)); + } /* ----------------- * Light Source * -----------------*/ - model = linearMat4Mul(linearTranslatev(lightPos), linearScale(0.2, 0.2, 0.2)); - - glUseProgram(programLight); - glBindVertexArray(lightVAO); - - shaderSetMatrixfv(programColor, "model", model.matrix[0], glUniformMatrix4fv); - shaderSetMatrixfv(programColor, "view", view.matrix[0], glUniformMatrix4fv); - shaderSetMatrixfv(programColor, "proj", proj.matrix[0], glUniformMatrix4fv); - - glDrawArrays(GL_TRIANGLES, 0, sizeof(vertices) / sizeof(float)); + for (int i = 0; i < 4; i++) { + model = linearMat4Mul(linearTranslatev(pointLightsPos[i]), + linearScale(0.2, 0.2, 0.2)); + glUseProgram(programLight); + glBindVertexArray(lightVAO); + + shaderSetMatrixfv(programColor, "model", model.matrix[0], glUniformMatrix4fv); + shaderSetMatrixfv(programColor, "view", view.matrix[0], glUniformMatrix4fv); + shaderSetMatrixfv(programColor, "proj", proj.matrix[0], glUniformMatrix4fv); + glDrawArrays(GL_TRIANGLES, 0, sizeof(vertices) / sizeof(float)); + } glfwSwapBuffers(window); glfwPollEvents(); |