diff --git a/shaders/frag.glsl b/shaders/frag.glsl index 2750366..f433323 100644 --- a/shaders/frag.glsl +++ b/shaders/frag.glsl @@ -1,12 +1,31 @@ #version 330 core +#define POINT_LIGHT_COUNT 4 + struct Material { sampler2D diffuse; sampler2D specular; float shininess; }; -struct Light { +struct DirLight { + vec3 direction; + vec3 ambient; + vec3 diffuse; + vec3 specular; +}; + +struct PointLight { + vec3 position; + vec3 ambient; + vec3 diffuse; + vec3 specular; + float constant; + float linear; + float quadratic; +}; + +struct SpotLight { vec3 position; vec3 direction; vec3 ambient; @@ -23,19 +42,64 @@ in vec2 uv_coords; out vec4 color; uniform Material material; -uniform Light light; +uniform DirLight directional_light; +uniform PointLight point_lights[POINT_LIGHT_COUNT]; +uniform SpotLight spot_light; uniform vec3 camera_position; +vec3 calc_dir_light(DirLight light, vec3 normal, vec3 view_direction); +vec3 calc_point_light(PointLight light, vec3 normal, vec3 frag_position, vec3 view_direction); +vec3 calc_spot_light(SpotLight light, vec3 normal, vec3 frag_position, vec3 view_direction); + void main() { - float ambient_strength = 0.15; - float specular_strength = 0.5; - vec3 normal = normalize(vert_normal); + vec3 normal = normalize(vert_normal); + vec3 view_direction = normalize(camera_position - frag_position); + + vec3 result = calc_dir_light(directional_light, normal, view_direction); + + for (int i = 0; i < POINT_LIGHT_COUNT; ++i) { + result += calc_point_light(point_lights[i], normal, frag_position, view_direction); + } + + result += calc_spot_light(spot_light, normal, frag_position, view_direction); + + color = vec4(result, 1.0); +}; + +vec3 calc_dir_light(DirLight light, vec3 normal, vec3 view_direction) { + vec3 light_direction = normalize(-light.direction); + vec3 reflect_direction = reflect(-light_direction, normal); + float diff = max(dot(normal, light_direction), 0.0); + vec3 diff_tex = vec3(texture(material.diffuse, uv_coords)); + float spec = pow(max(dot(reflect_direction, view_direction), 0.0), material.shininess); + vec3 ambient = light.ambient * diff_tex; + vec3 diffuse = light.diffuse * (diff * diff_tex); + vec3 specular = light.specular * (spec * vec3(texture(material.specular, uv_coords))); + + return ambient + diffuse + specular; +} + +vec3 calc_point_light(PointLight light, vec3 normal, vec3 frag_position, vec3 view_direction) { vec3 light_direction = normalize(light.position - frag_position); + vec3 reflect_direction = reflect(-light_direction, normal); + float distance = length(light.position - frag_position); + float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance)); + float diff = max(dot(normal, light_direction), 0.0); + vec3 diff_tex = vec3(texture(material.diffuse, uv_coords)); + float spec = pow(max(dot(reflect_direction, view_direction), 0.0), material.shininess); + vec3 ambient = light.ambient * diff_tex * attenuation; + vec3 diffuse = light.diffuse * (diff * diff_tex) * attenuation; + vec3 specular = light.specular * (spec * vec3(texture(material.specular, uv_coords))) * attenuation; + + return ambient + diffuse + specular; +} + +vec3 calc_spot_light(SpotLight light, vec3 normal, vec3 frag_position, vec3 view_direction) { + vec3 light_direction = normalize(light.position - frag_position); + vec3 reflect_direction = reflect(-light_direction, normal); float theta = dot(light_direction, normalize(-light.direction)); float epsilon = light.cutoff - light.outer_cutoff; float intensity = clamp((theta - light.outer_cutoff) / epsilon, 0.0, 1.0); - vec3 view_direction = normalize(camera_position - frag_position); - vec3 reflect_direction = reflect(-light_direction, normal); float diff = max(dot(normal, light_direction), 0.0); float spec = pow(max(dot(reflect_direction, view_direction), 0.0), material.shininess); vec3 diff_tex = vec3(texture(material.diffuse, uv_coords)); @@ -43,5 +107,5 @@ void main() { vec3 diffuse = light.diffuse * (diff * diff_tex) * intensity; vec3 specular = light.specular * (spec * vec3(texture(material.specular, uv_coords))) * intensity; - color = vec4(ambient + diffuse + specular, 1.0); -}; + return ambient + diffuse + specular; +} diff --git a/src/main.cc b/src/main.cc index 598230e..edf01fb 100644 --- a/src/main.cc +++ b/src/main.cc @@ -205,8 +205,9 @@ int main() { glm::vec3 camera_position = glm::vec3(-2.0f, 0.0f, 6.0f); glm::vec3 camera_forward = glm::vec3(0.0f); glm::vec3 world_up = glm::vec3(0.0f, 1.0f, 0.0f); - glm::vec3 light_pos_dir = glm::vec3(1.0f, 0.5f, 0.0f); + glm::vec3 light_ambient = glm::vec3(0.2f, 0.2f, 0.2f); glm::vec3 light_diffuse = glm::vec3(0.75f, 0.75f, 0.75f); + glm::vec3 light_specular = glm::vec3(1.0f, 1.0f, 1.0f); float yaw = -70.0f; float pitch = 0.0f; @@ -219,12 +220,7 @@ int main() { main_shader.set_mat4 ("projection", projection); main_shader.set_vec3 ("material.specular", glm::vec3(0.5f, 0.5f, 0.5f)); main_shader.set_float("material.shininess", 32.0f); - main_shader.set_vec3 ("light.ambient", glm::vec3(0.2f, 0.2f, 0.2f)); - main_shader.set_vec3 ("light.diffuse", light_diffuse); - main_shader.set_vec3 ("light.specular", glm::vec3(1.0f, 1.0f, 1.0f)); - main_shader.set_float("light.constant", 1.0f); - main_shader.set_float("light.linear", 0.07f); - main_shader.set_float("light.quadratic", 0.017f); + light_shader.set_mat4("projection", projection); std::vector cube_positions = { @@ -240,7 +236,60 @@ int main() { glm::vec3(-3.3f, 2.0f, -1.5f) }; - const float light_radius = 6.0f; + std::vector point_light_positions = { + 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) + }; + + // Setup lights + main_shader.set_vec3("directional_light.direction", glm::vec3(-0.2f, -1.0f, -0.3f)); + main_shader.set_vec3("directional_light.ambient", light_ambient); + main_shader.set_vec3("directional_light.diffuse", light_diffuse); + main_shader.set_vec3("directional_light.specular", light_specular); + + main_shader.set_vec3("spot_light.ambient", light_ambient); + main_shader.set_vec3("spot_light.diffuse", light_diffuse); + main_shader.set_vec3("spot_light.specular", light_specular); + + for (int i = 0; i < point_light_positions.size(); ++i) { + char base[256] = {0}; + char position[512] = {0}; + char ambient[512] = {0}; + char diffuse[512] = {0}; + char specular[512] = {0}; + char constant[512] = {0}; + char linear[512] = {0}; + char quadratic[512] = {0}; + + snprintf(base, sizeof(base) - 1, "point_lights[%d]", i); + snprintf(position, sizeof(position) - 1, "%s.position", base); + snprintf(ambient, sizeof(ambient) - 1, "%s.ambient", base); + snprintf(diffuse, sizeof(diffuse) - 1, "%s.diffuse", base); + snprintf(specular, sizeof(specular) - 1, "%s.specular", base); + snprintf(constant, sizeof(constant) - 1, "%s.constant", base); + snprintf(linear, sizeof(linear) - 1, "%s.linear", base); + snprintf(quadratic, sizeof(quadratic) - 1, "%s.quadratic", base); + + main_shader.set_vec3(position, point_light_positions[i]); + main_shader.set_vec3(ambient, light_ambient); + main_shader.set_vec3(diffuse, light_diffuse); + main_shader.set_vec3(specular, light_specular); + main_shader.set_float(constant, 1.0f); + main_shader.set_float(linear, 0.09f); + main_shader.set_float(quadratic, 0.032f); + + memset(base, 0, sizeof(base)); + memset(position, 0, sizeof(position)); + memset(ambient, 0, sizeof(ambient)); + memset(diffuse, 0, sizeof(diffuse)); + memset(specular, 0, sizeof(specular)); + memset(constant, 0, sizeof(constant)); + memset(linear, 0, sizeof(linear)); + memset(quadratic, 0, sizeof(quadratic)); + } + const float sensitivity = 0.1f; int last_mouse_x = WINDOW_HALF_WIDTH; int last_mouse_y = WINDOW_HALF_HEIGHT; @@ -251,9 +300,7 @@ int main() { while (running) { uint32_t ticks = SDL_GetTicks(); - float seconds = ticks * 0.001f; delta = (ticks - last_frame) * 0.001f; - light_pos_dir = glm::vec3(sin(seconds) * light_radius, light_pos_dir.y, cos(seconds) * light_radius); last_frame = ticks; while (SDL_PollEvent(&event)) { @@ -318,10 +365,10 @@ int main() { view = glm::lookAt(camera_position, camera_position + camera_forward, world_up); main_shader.set_vec3("camera_position", camera_position); - main_shader.set_vec3("light.position", camera_position); - main_shader.set_vec3("light.direction", camera_forward); - main_shader.set_float("light.cutoff", glm::cos(glm::radians(12.5))); - main_shader.set_float("light.outer_cutoff", glm::cos(glm::radians(17.5))); + main_shader.set_vec3("spot_light.position", camera_position); + main_shader.set_vec3("spot_light.direction", camera_forward); + main_shader.set_float("spot_light.cutoff", glm::cos(glm::radians(12.5))); + main_shader.set_float("spot_light.outer_cutoff", glm::cos(glm::radians(17.5))); main_shader.set_mat4("view", view); light_shader.set_mat4("view", view); @@ -333,8 +380,6 @@ int main() { model = glm::rotate(model, glm::radians(10.0f * i), glm::vec3(1.0f, 0.3f, 0.5f)); normal_mat = glm::transpose(glm::inverse(model)); main_shader.activate(); - main_shader.set_vec4("light.pos_dir", glm::vec4(light_pos_dir, 1.0f)); - main_shader.set_vec3("light.diffuse", light_diffuse); main_shader.set_mat4("model", model); main_shader.set_mat3("normal_mat", normal_mat); diffuse_map.activate(); @@ -344,13 +389,15 @@ int main() { } // Draw light source - // model = glm::translate(glm::mat4(1.0f), glm::vec3(light_pos_dir)); - // model = glm::scale(model, glm::vec3(0.2f)); - // light_shader.activate(); - // light_shader.set_mat4("model", model); - // light_shader.set_vec3("light_diffuse", light_diffuse); - // glBindVertexArray(light_vao); - // glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, (void *)0); + for (int i = 0; i < point_light_positions.size(); ++i) { + model = glm::translate(glm::mat4(1.0f), point_light_positions[i]); + model = glm::scale(model, glm::vec3(0.2f)); + light_shader.activate(); + light_shader.set_mat4("model", model); + light_shader.set_vec3("light_diffuse", light_diffuse); + glBindVertexArray(light_vao); + glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, (void *)0); + } SDL_GL_SwapWindow(window); }