aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjvech <jmvalenciae@unal.edu.co>2022-09-16 16:21:37 -0500
committerjvech <jmvalenciae@unal.edu.co>2022-09-16 16:21:37 -0500
commitfc8d7fed3ccdf0998a7b9809aa825f2d14876b29 (patch)
tree45d1b4ff6435e79939be1198316e7973ab5695bb
parent6781af306edc8f6b0928013ed9ec2fa87d63da81 (diff)
learn: 17. Multiple lights
-rw-r--r--shaders/color.fsh127
-rw-r--r--src/main.c132
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);
}
diff --git a/src/main.c b/src/main.c
index 09df1bb..531a1df 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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();
Feel free to download, copy and edit any repo