diff --git a/.gitignore b/.gitignore index 1b4f3cb..ead74ec 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -builddir/ \ No newline at end of file +builddir/ +.cache/ diff --git a/assets/container2.qoi b/assets/container2.qoi new file mode 100644 index 0000000..5ec93ed Binary files /dev/null and b/assets/container2.qoi differ diff --git a/assets/container2_specular.qoi b/assets/container2_specular.qoi new file mode 100644 index 0000000..0b29e25 Binary files /dev/null and b/assets/container2_specular.qoi differ diff --git a/assets/fish-map.qoi b/assets/fish-map.qoi index 0a59570..b440f59 100644 Binary files a/assets/fish-map.qoi and b/assets/fish-map.qoi differ diff --git a/assets/fish.png b/assets/fish.png index 9102229..173aa45 100644 Binary files a/assets/fish.png and b/assets/fish.png differ diff --git a/shaders/lighting_fragment.glsl b/shaders/lighting_fragment.glsl index 8428a05..1cac6d6 100644 --- a/shaders/lighting_fragment.glsl +++ b/shaders/lighting_fragment.glsl @@ -31,11 +31,27 @@ struct DirectionalLight { vec3 specular; }; +struct SpotLight { + vec3 position; + vec3 direction; + float cutOff; + float outerCutOff; + + vec3 ambient; + vec3 diffuse; + vec3 specular; + + float constant; + float linear; + float quadratic; +}; + #define POINT_LIGHTS_COUNT 4 uniform Material material; uniform vec3 viewPos; +uniform SpotLight spotLight; uniform DirectionalLight directionalLight; uniform PointLight pointLights[POINT_LIGHTS_COUNT]; @@ -55,12 +71,12 @@ vec3 ComputeDirectionalLight(DirectionalLight light, vec3 norm, vec3 viewDir) return (ambient + diffuse + specular); } -vec3 ComputePointLight(PointLight light, vec3 norm, vec3 viewDir) +vec3 ComputePointLight(PointLight light, vec3 norm, vec3 viewDir, vec3 fragPos) { - float distance = length(light.position - FragPos); + float distance = length(light.position - fragPos); float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance)); - vec3 lightDir = normalize(light.position - FragPos); + vec3 lightDir = normalize(light.position - fragPos); vec3 reflectDir = reflect(-lightDir, norm); float diff = max(dot(norm, lightDir), 0.0); @@ -73,16 +89,40 @@ vec3 ComputePointLight(PointLight light, vec3 norm, vec3 viewDir) return (ambient * attenuation + diffuse * attenuation + specular * attenuation); } +vec3 ComputeSpotLight(SpotLight light, vec3 norm, vec3 viewDir, vec3 fragPos) { + vec3 lightDir = normalize(light.position - fragPos); + vec3 reflectDir = reflect(-lightDir, norm); + + float theta = dot(lightDir, normalize(-light.direction)); + float epsilon = light.cutOff - light.outerCutOff; + float intensity = clamp((theta - light.outerCutOff) / epsilon, 0.0, 1.0); + + float distance = length(light.position - fragPos); + float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance)); + + float diff = max(dot(norm, lightDir), 0.0); + 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)); + + // we leave ambient alone so there's always a little light + return ((ambient * attenuation) + (diffuse * intensity * attenuation) + (specular * intensity * attenuation)); +} + void main() { vec3 norm = normalize(Normal); vec3 viewDir = normalize(viewPos - FragPos); vec3 result = vec3(0.0); + result += ComputeDirectionalLight(directionalLight, norm, viewDir); for (int i = 0; i < POINT_LIGHTS_COUNT; i++) { - result += ComputePointLight(pointLights[i], norm, viewDir); + result += ComputePointLight(pointLights[i], norm, viewDir, FragPos); } + result += ComputeSpotLight(spotLight, norm, viewDir, FragPos); FragColor = vec4(result, 1.0); } diff --git a/src/main.cpp b/src/main.cpp index 6ee14e1..93b8ed0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -24,10 +24,10 @@ std::function cursor_position_callback = nullptr; int main() { qoi_desc fish_desc; - void *fish_rgba = qoi_read("assets/fish.qoi", &fish_desc, 4); + void *fish_rgba = qoi_read("assets/container2.qoi", &fish_desc, 4); qoi_desc fish_map_desc; - void *fish_map_rgba = qoi_read("assets/fish-map.qoi", &fish_map_desc, 4); + void *fish_map_rgba = qoi_read("assets/container2_specular.qoi", &fish_map_desc, 4); if (!glfwInit()) { @@ -107,6 +107,27 @@ int main() -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f }; + // positions all containers + glm::vec3 cube_positions[] = { + glm::vec3( 0.0f, 0.0f, 0.0f), + glm::vec3( 2.0f, 5.0f, -15.0f), + glm::vec3(-1.5f, -2.2f, -2.5f), + glm::vec3(-3.8f, -2.0f, -12.3f), + glm::vec3( 2.4f, -0.4f, -3.5f), + glm::vec3(-1.7f, 3.0f, -7.5f), + glm::vec3( 1.3f, -2.0f, -2.5f), + glm::vec3( 1.5f, 2.0f, -2.5f), + glm::vec3( 1.5f, 0.2f, -1.5f), + glm::vec3(-1.3f, 1.0f, -1.5f) + }; + // positions of the point lights + glm::vec3 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) + }; + unsigned int fish_texture; glGenTextures(1, &fish_texture); glBindTexture(GL_TEXTURE_2D, fish_texture); @@ -131,6 +152,8 @@ int main() glGenVertexArrays(1, &object_vao); glBindVertexArray(object_vao); + glBindBuffer(GL_ARRAY_BUFFER, cube_buffer); + // position glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (const void*)0); glEnableVertexAttribArray(0); @@ -145,6 +168,8 @@ int main() glGenVertexArrays(1, &light_source_vao); glBindVertexArray(light_source_vao); + glBindBuffer(GL_ARRAY_BUFFER, cube_buffer); + // position glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (const void*)0); glEnableVertexAttribArray(0); @@ -165,8 +190,6 @@ int main() float delta_time = 0.0f; float last_frame_time = 0.0f; - glm::vec3 light_position(1.2f, 1.0f, 2.0f); - while (!glfwWindowShouldClose(window)) { float current_frame_time = glfwGetTime(); delta_time = current_frame_time - last_frame_time; @@ -195,7 +218,7 @@ int main() glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); { - /* lit object */ + /* lit objects */ { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, fish_texture); @@ -203,33 +226,81 @@ int main() glBindTexture(GL_TEXTURE_2D, fish_map_texture); glUseProgram(lighting_program); - glBindVertexArray(object_vao); - glUniformMatrix4fv(glGetUniformLocation(lighting_program, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); - glUniformMatrix4fv(glGetUniformLocation(lighting_program, "view"), 1, GL_FALSE, glm::value_ptr(camera.view)); - glUniformMatrix4fv(glGetUniformLocation(lighting_program, "model"), 1, GL_FALSE, glm::value_ptr(glm::mat4(1.0f))); - glUniform3fv(glGetUniformLocation(lighting_program, "viewPos"), 1, glm::value_ptr(camera.position)); - glUniform1i(glGetUniformLocation(lighting_program, "material.diffuse"), 0); - glUniform1i(glGetUniformLocation(lighting_program, "material.specular"), 1); - glUniform1f(glGetUniformLocation(lighting_program, "material.shininess"), 32.0f); + program_set(lighting_program, "projection", projection); + program_set(lighting_program, "view", camera.view); + program_set(lighting_program, "viewPos", camera.position); - glUniform3fv(glGetUniformLocation(lighting_program, "light.position"), 1, glm::value_ptr(light_position)); - glUniform3f(glGetUniformLocation(lighting_program, "light.ambient"), 0.2f, 0.2f, 0.2f); - glUniform3f(glGetUniformLocation(lighting_program, "light.diffuse"), 0.5f, 0.5f, 0.5f); - glUniform3f(glGetUniformLocation(lighting_program, "light.specular"), 1.0f, 1.0f, 1.0f); - glDrawArrays(GL_TRIANGLES, 0, 36); + program_set(lighting_program, "material.shininess", 32.0f); + + program_set(lighting_program, "directionalLight.direction", -0.2f, -1.0f, -0.3f); + program_set(lighting_program, "directionalLight.ambient", 0.05f, 0.05f, 0.05f); + program_set(lighting_program, "directionalLight.diffuse", 0.4f, 0.4f, 0.4f); + program_set(lighting_program, "directionalLight.specular", 0.5f, 0.5f, 0.5f); + // point light 1 + program_set(lighting_program, "pointLights[0].position", point_light_positions[0]); + program_set(lighting_program, "pointLights[0].ambient", 0.05f, 0.05f, 0.05f); + program_set(lighting_program, "pointLights[0].diffuse", 0.8f, 0.8f, 0.8f); + program_set(lighting_program, "pointLights[0].specular", 1.0f, 1.0f, 1.0f); + program_set(lighting_program, "pointLights[0].constant", 1.0f); + program_set(lighting_program, "pointLights[0].linear", 0.09f); + program_set(lighting_program, "pointLights[0].quadratic", 0.032f); + // point light 2 + program_set(lighting_program, "pointLights[1].position", point_light_positions[1]); + program_set(lighting_program, "pointLights[1].ambient", 0.05f, 0.05f, 0.05f); + program_set(lighting_program, "pointLights[1].diffuse", 0.8f, 0.8f, 0.8f); + program_set(lighting_program, "pointLights[1].specular", 1.0f, 1.0f, 1.0f); + program_set(lighting_program, "pointLights[1].constant", 1.0f); + program_set(lighting_program, "pointLights[1].linear", 0.09f); + program_set(lighting_program, "pointLights[1].quadratic", 0.032f); + // point light 3 + program_set(lighting_program, "pointLights[2].position", point_light_positions[2]); + program_set(lighting_program, "pointLights[2].ambient", 0.05f, 0.05f, 0.05f); + program_set(lighting_program, "pointLights[2].diffuse", 0.8f, 0.8f, 0.8f); + program_set(lighting_program, "pointLights[2].specular", 1.0f, 1.0f, 1.0f); + program_set(lighting_program, "pointLights[2].constant", 1.0f); + program_set(lighting_program, "pointLights[2].linear", 0.09f); + program_set(lighting_program, "pointLights[2].quadratic", 0.032f); + // point light 4 + program_set(lighting_program, "pointLights[3].position", point_light_positions[3]); + program_set(lighting_program, "pointLights[3].ambient", 0.05f, 0.05f, 0.05f); + program_set(lighting_program, "pointLights[3].diffuse", 0.8f, 0.8f, 0.8f); + program_set(lighting_program, "pointLights[3].specular", 1.0f, 1.0f, 1.0f); + program_set(lighting_program, "pointLights[3].constant", 1.0f); + program_set(lighting_program, "pointLights[3].linear", 0.09f); + program_set(lighting_program, "pointLights[3].quadratic", 0.032f); + // spot light + program_set(lighting_program, "spotLight.position", camera.position); + program_set(lighting_program, "spotLight.direction", camera.front); + program_set(lighting_program, "spotLight.ambient", 0.0f, 0.0f, 0.0f); + program_set(lighting_program, "spotLight.diffuse", 1.0f, 1.0f, 1.0f); + program_set(lighting_program, "spotLight.specular", 1.0f, 1.0f, 1.0f); + program_set(lighting_program, "spotLight.constant", 1.0f); + program_set(lighting_program, "spotLight.linear", 0.09f); + program_set(lighting_program, "spotLight.quadratic", 0.032f); + program_set(lighting_program, "spotLight.cutOff", glm::cos(glm::radians(12.5f))); + program_set(lighting_program, "spotLight.outerCutOff", glm::cos(glm::radians(15.0f))); + + + for (int i = 0; i < 10; i++) { + program_set(lighting_program, "model", glm::rotate(glm::translate(glm::mat4(1.0f), cube_positions[i]), glm::radians(20.0f * i), glm::vec3(1.0f, 0.3f, 0.5f))); + glDrawArrays(GL_TRIANGLES, 0, 36); + } } /* lamp object */ { glUseProgram(light_cube_program); glBindVertexArray(light_source_vao); - glUniformMatrix4fv(glGetUniformLocation(light_cube_program, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); - glUniformMatrix4fv(glGetUniformLocation(light_cube_program, "view"), 1, GL_FALSE, glm::value_ptr(camera.view)); - glUniformMatrix4fv(glGetUniformLocation(light_cube_program, "model"), 1, GL_FALSE, glm::value_ptr(glm::scale(glm::translate(glm::mat4(1.0f), light_position), glm::vec3(0.2f)))); - glDrawArrays(GL_TRIANGLES, 0, 36); + program_set(light_cube_program, "view", camera.view); + program_set(light_cube_program, "projection", projection); + + for (int i = 0; i < 4; i++) { + program_set(light_cube_program, "model", glm::scale(glm::translate(glm::mat4(1.0f), point_light_positions[i]), glm::vec3(0.2f))); + glDrawArrays(GL_TRIANGLES, 0, 36); + } } } diff --git a/src/shader.cpp b/src/shader.cpp index 7f28f37..c890d2a 100644 --- a/src/shader.cpp +++ b/src/shader.cpp @@ -103,3 +103,28 @@ done: if (fragment_shader_source) free(fragment_shader_source); return ret; } + +void program_set(unsigned int program, const char *uniform, int value) +{ + glUniform1i(glGetUniformLocation(program, uniform), value); +} + +void program_set(unsigned int program, const char *uniform, float value) +{ + glUniform1f(glGetUniformLocation(program, uniform), value); +} + +void program_set(unsigned int program, const char *uniform, glm::vec3 vec) +{ + glUniform3fv(glGetUniformLocation(program, uniform), 1, &vec[0]); +} + +void program_set(unsigned int program, const char *uniform, float x, float y, float z) +{ + glUniform3f(glGetUniformLocation(program, uniform), x, y, z); +} + +void program_set(unsigned int program, const char *uniform, const glm::mat4 &mat) +{ + glUniformMatrix4fv(glGetUniformLocation(program, uniform), 1, GL_FALSE, &mat[0][0]); +} diff --git a/src/shader.hpp b/src/shader.hpp index 8028e06..ea92530 100644 --- a/src/shader.hpp +++ b/src/shader.hpp @@ -1,4 +1,11 @@ #pragma once +#include "vendor/glm/glm/mat4x4.hpp" +#include "vendor/glm/glm/vec3.hpp" unsigned int create_program(const char *vertex_shader_path, const char *fragment_shader_path); +void program_set(unsigned int program, const char *uniform, int value); +void program_set(unsigned int program, const char *uniform, float value); +void program_set(unsigned int program, const char *uniform, glm::vec3 vec); +void program_set(unsigned int program, const char *uniform, float x, float y, float z); +void program_set(unsigned int program, const char *uniform, const glm::mat4 &mat);