summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--res/shaders/colors.fs137
-rw-r--r--src/cubes.odin7
-rw-r--r--src/main.odin77
3 files changed, 173 insertions, 48 deletions
diff --git a/res/shaders/colors.fs b/res/shaders/colors.fs
index 228f555..d10e45a 100644
--- a/res/shaders/colors.fs
+++ b/res/shaders/colors.fs
@@ -14,6 +14,7 @@ struct Light {
   vec3 direction;
 
   float cutOff;
+  float outerCutOff;
 
   vec3 ambient;
   vec3 diffuse;
@@ -32,37 +33,127 @@ uniform vec3 view_position;
 uniform Material material;
 uniform Light light;
 
-void main() {
-  vec3 light_dir = normalize(light.position - FragPos);
 
-  float theta = dot(light_dir, normalize(-light.direction));
+struct DirLight {
+  vec3 direction;
 
-  if (theta > light.cutOff) {
-    // ambient
-    vec3 ambient = light.ambient * texture(material.diffuse, TexCoords).rgb;
+  vec3 ambient;
+  vec3 diffuse;
+  vec3 specular;
+};
+uniform DirLight dirLight;
 
-    // diffuse
-    vec3 norm = normalize(Normal);
-    float diff = max(dot(norm, light_dir), 0.0);
-    vec3 diffuse = light.diffuse * diff * texture(material.diffuse, TexCoords).rgb;
+struct PointLight {
+  vec3 position;
 
-    // specular
-    vec3 view_dir = normalize(view_position - FragPos);
-    vec3 reflect_dir = reflect(-light_dir, norm);
-    float spec = pow(max(dot(view_dir, reflect_dir), 0.0), material.shininess);
-    vec3 specular = light.specular * spec * texture(material.specular, TexCoords).rgb;
+  float constant;
+  float linear;
+  float quadratic;
 
-    float distance = length(light.position - FragPos);
-    float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));
+  vec3 ambient;
+  vec3 diffuse;
+  vec3 specular;
+};
+#define NR_POINT_LIGHTS 4
+uniform PointLight pointLights[NR_POINT_LIGHTS];
 
-    diffuse *= attenuation;
-    specular *= attenuation;
+struct SpotLight {
+  vec3 position;
+  vec3 direction;
+
+  float cutOff;
+  float outerCutOff;
+
+  float constant;
+  float linear;
+  float quadratic;
+
+  vec3 ambient;
+  vec3 diffuse;
+  vec3 specular;
+};
+uniform SpotLight spotLight;
+
+vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir);
+vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir);
+vec3 CalcSpotLight(SpotLight light, vec3 normal, vec3 fragPos, vec3 viewDir);
+
+void main()
+{
+  vec3 norm = normalize(Normal);
+  vec3 viewDir = normalize(view_position - FragPos);
+
+  vec3 result = CalcDirLight(dirLight, norm, viewDir);
 
-    vec3 result = ambient + diffuse + specular;
-    FragColor = vec4(result, 1.0);
-  } else {
-    FragColor = vec4(light.ambient * texture(material.diffuse, TexCoords).rgb, 1.0);
+  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);
+}
+
+// calculates the color when using a directional light.
+vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir)
+{
+    vec3 lightDir = normalize(-light.direction);
+    // diffuse shading
+    float diff = max(dot(normal, lightDir), 0.0);
+    // specular shading
+    vec3 reflectDir = reflect(-lightDir, normal);
+    float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
+    // combine results
+    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);
+}
+
+// calculates the color when using a point light.
+vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir)
+{
+    vec3 lightDir = normalize(light.position - fragPos);
+    // diffuse shading
+    float diff = max(dot(normal, lightDir), 0.0);
+    // specular shading
+    vec3 reflectDir = reflect(-lightDir, normal);
+    float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
+    // attenuation
+    float distance = length(light.position - fragPos);
+    float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));
+    // combine results
+    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);
+}
+
+// calculates the color when using a spot light.
+vec3 CalcSpotLight(SpotLight light, vec3 normal, vec3 fragPos, vec3 viewDir)
+{
+    vec3 lightDir = normalize(light.position - fragPos);
+    // diffuse shading
+    float diff = max(dot(normal, lightDir), 0.0);
+    // specular shading
+    vec3 reflectDir = reflect(-lightDir, normal);
+    float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
+    // attenuation
+    float distance = length(light.position - fragPos);
+    float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));
+    // spotlight intensity
+    float theta = dot(lightDir, normalize(-light.direction));
+    float epsilon = light.cutOff - light.outerCutOff;
+    float intensity = clamp((theta - light.outerCutOff) / epsilon, 0.0, 1.0);
+    // combine results
+    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 * intensity;
+    diffuse *= attenuation * intensity;
+    specular *= attenuation * intensity;
+    return (ambient + diffuse + specular);
 }
diff --git a/src/cubes.odin b/src/cubes.odin
index b6bcd1c..d96bbc3 100644
--- a/src/cubes.odin
+++ b/src/cubes.odin
@@ -56,3 +56,10 @@ cube_positions : []Vec3 : {
   Vec3{ 1.5,  0.2, -1.5},
   Vec3{-1.3,  1.0, -1.5}
 }
+
+point_light_positions : []Vec3 : {
+  Vec3{0.7, 0.2, 2.0},
+  Vec3{2.3, -3.3, -4.0},
+  Vec3{-4.0, 2.0, -12.0},
+  Vec3{0.0, 0.0, -3.0}
+}
diff --git a/src/main.odin b/src/main.odin
index 997aeb2..d518e93 100644
--- a/src/main.odin
+++ b/src/main.odin
@@ -187,28 +187,55 @@ main :: proc() {
 
 		shader_use(lighting_shader)
 
+		shader_set_vec3(lighting_shader, cstring("view_position"), &camera.position)
+		shader_set_f32(lighting_shader, cstring("material.shininess"), 32.0)
+
+    // directional light
+    shader_set_vec3(lighting_shader, "dirLight.direction", &Vec3{-0.2, -1.0, -0.3})
+    shader_set_vec3(lighting_shader, "dirLight.ambient", &Vec3{0.05, 0.05, 0.05})
+    shader_set_vec3(lighting_shader, "dirLight.diffuse", &Vec3{0.04, 0.04, 0.04})
+    shader_set_vec3(lighting_shader, "dirLight.specular", &Vec3{0.5, 0.5, 0.5})
+
+    // point lights
+    for &pos, i in point_light_positions {
+      positon_key := fmt.caprintf("pointLights[%i].position", i)
+      ambient_key := fmt.caprintf("pointLights[%i].ambient", i)
+      diffuse_key := fmt.caprintf("pointLights[%i].diffuse", i)
+      specular_key := fmt.caprintf("pointLights[%i].specular", i)
+      constant_key := fmt.caprintf("pointLights[%i].constant", i)
+      linear_key := fmt.caprintf("pointLights[%i].linear", i)
+      quadratic_key := fmt.caprintf("pointLights[%i].quadratic", i)
+
+
 
-		light_ambient := Vec3{0.2, 0.2, 0.2}
-		light_diffuse := Vec3{0.5, 0.5, 0.05}
-		light_specular := Vec3{1.0, 1.0, 1.0}
+      shader_set_vec3(lighting_shader, positon_key, &pos)
+      shader_set_vec3(lighting_shader, ambient_key, &Vec3{0.05, 0.05, 0.05})
+      shader_set_vec3(lighting_shader, diffuse_key, &Vec3{0.8, 0.8, 0.8})
+      shader_set_vec3(lighting_shader, specular_key, &Vec3{1.0, 1.0, 1.0})
 
-		shader_set_vec3(lighting_shader, cstring("light.ambient"), &light_ambient)
-		shader_set_vec3(lighting_shader, cstring("light.diffuse"), &light_diffuse)
-		shader_set_vec3(lighting_shader, cstring("light.specular"), &light_specular)
+      shader_set_f32(lighting_shader, constant_key, 1.0)
+      shader_set_f32(lighting_shader, linear_key, 0.09)
+      shader_set_f32(lighting_shader, quadratic_key, 0.032)
+    }
 
-		shader_set_vec3(lighting_shader, cstring("light.position"), &camera.position)
-		shader_set_vec3(lighting_shader, cstring("light.direction"), &camera.front)
 
+    // spot
     cutoff_angle : f32 = math.cos(linalg.to_radians(f32(12.5)))
-    shader_set_f32(lighting_shader, "light.cutOff", cutoff_angle)
+    outer_cutoff_angle : f32 = math.cos(linalg.to_radians(f32(15.0)))
 
-		shader_set_vec3(lighting_shader, cstring("view_position"), &camera.position)
+    shader_set_vec3(lighting_shader, "spotLight.position", &camera.position)
+    shader_set_vec3(lighting_shader, "spotLight.direction", &camera.front)
+    shader_set_vec3(lighting_shader, "spotLight.ambient", &Vec3{0.0, 0.0, 0.0})
+    shader_set_vec3(lighting_shader, "spotLight.diffuse", &Vec3{1.0, 1.0, 1.0})
+    shader_set_vec3(lighting_shader, "spotLight.specular", &Vec3{1.0, 1.0, 1.0})
 
-    shader_set_f32(lighting_shader, "light.constant", 1.0)
-    shader_set_f32(lighting_shader, "light.linear", 0.09)
-    shader_set_f32(lighting_shader, "light.qudratic", 0.032)
+    shader_set_f32(lighting_shader, "spotLight.constant", 1.0)
+    shader_set_f32(lighting_shader, "spotLight.linear", 0.09)
+    shader_set_f32(lighting_shader, "spotLight.quadratic", 0.032)
 
-		shader_set_f32(lighting_shader, cstring("material.shininess"), 32.0)
+
+    shader_set_f32(lighting_shader, "spotLight.cutOff", cutoff_angle)
+    shader_set_f32(lighting_shader, "spotLight.outerCutOff", outer_cutoff_angle)
 
 		aspect: f32 = 800.0 / 600.0
 		projection := linalg.matrix4_perspective_f32(
@@ -236,7 +263,6 @@ main :: proc() {
 		gl.BindTexture(gl.TEXTURE_2D, specular_map)
 
 		gl.BindVertexArray(cube_vao)
-		// gl.DrawArrays(gl.TRIANGLES, 0, 36)
 		for position, i in cube_positions {
 			model = linalg.MATRIX4F32_IDENTITY
 			model *= linalg.matrix4_translate_f32(position)
@@ -244,20 +270,21 @@ main :: proc() {
 			model *= linalg.matrix4_rotate_f32(angle, Vec3{1.0, 0.3, 0.5})
 
 			shader_set_mat4(lighting_shader, "model", &model)
-			gl.DrawArrays(gl.TRIANGLES, 0, 36)
+			gl.DrawArrays(gl.TRIANGLES, 0, 36);
 		}
 
-		// lamp cube object drawing
-		shader_use(light_cube_shader)
-		shader_set_mat4(light_cube_shader, cstring("projection"), &projection)
-		shader_set_mat4(light_cube_shader, cstring("view"), &view)
-
-		model = linalg.matrix4_translate_f32(light_pos)
-		model *= linalg.matrix4_scale_f32(Vec3{0.2, 0.2, 0.2})
-		shader_set_mat4(light_cube_shader, cstring("model"), &model)
+    shader_use(light_cube_shader)
+    shader_set_mat4(light_cube_shader, "projection", &projection)
+    shader_set_mat4(light_cube_shader, "view", &view)
 
 		gl.BindVertexArray(light_cube_vao)
-		gl.DrawArrays(gl.TRIANGLES, 0, 36)
+    for pos, i in point_light_positions {
+			model = linalg.MATRIX4F32_IDENTITY
+			model *= linalg.matrix4_translate_f32(pos)
+		  model *= linalg.matrix4_scale_f32(Vec3{0.2, 0.2, 0.2})
+		  shader_set_mat4(light_cube_shader, cstring("model"), &model)
+		  gl.DrawArrays(gl.TRIANGLES, 0, 36)
+    }
 
 		glfw.SwapBuffers(window)
 		glfw.PollEvents()