diff --git a/assets/fish-map.qoi b/assets/fish-map.qoi new file mode 100644 index 0000000..0a59570 Binary files /dev/null and b/assets/fish-map.qoi differ diff --git a/assets/fish.png b/assets/fish.png new file mode 100644 index 0000000..9102229 Binary files /dev/null and b/assets/fish.png differ diff --git a/shaders/fragment.glsl b/shaders/fragment.glsl deleted file mode 100644 index 1f16171..0000000 --- a/shaders/fragment.glsl +++ /dev/null @@ -1,14 +0,0 @@ -#version 330 core - - -in vec2 TexCoord; - -out vec4 FragColor; - -uniform sampler2D tex; - - -void main() -{ - FragColor = texture(tex, TexCoord); -} diff --git a/shaders/light_cube_fragment.glsl b/shaders/light_cube_fragment.glsl new file mode 100644 index 0000000..1bd96c6 --- /dev/null +++ b/shaders/light_cube_fragment.glsl @@ -0,0 +1,7 @@ +#version 330 core +out vec4 FragColor; + +void main() +{ + FragColor = vec4(1.0); +} diff --git a/shaders/light_cube_vertex.glsl b/shaders/light_cube_vertex.glsl new file mode 100644 index 0000000..ae6d2c9 --- /dev/null +++ b/shaders/light_cube_vertex.glsl @@ -0,0 +1,11 @@ +#version 330 core +layout (location = 0) in vec3 aPos; + +uniform mat4 model; +uniform mat4 view; +uniform mat4 projection; + +void main() +{ + gl_Position = projection * view * model * vec4(aPos, 1.0); +} diff --git a/shaders/lighting_fragment.glsl b/shaders/lighting_fragment.glsl new file mode 100644 index 0000000..8428a05 --- /dev/null +++ b/shaders/lighting_fragment.glsl @@ -0,0 +1,88 @@ +#version 330 core +out vec4 FragColor; + +in vec3 Normal; +in vec3 FragPos; +in vec2 TexCoords; + +struct Material { + sampler2D diffuse; + sampler2D specular; + float shininess; +}; + +struct PointLight { + vec3 position; + + vec3 ambient; + vec3 diffuse; + vec3 specular; + + float constant; + float linear; + float quadratic; +}; + +struct DirectionalLight { + vec3 direction; + + vec3 ambient; + vec3 diffuse; + vec3 specular; +}; + +#define POINT_LIGHTS_COUNT 4 + +uniform Material material; +uniform vec3 viewPos; + +uniform DirectionalLight directionalLight; +uniform PointLight pointLights[POINT_LIGHTS_COUNT]; + + +vec3 ComputeDirectionalLight(DirectionalLight light, vec3 norm, vec3 viewDir) +{ + vec3 lightDir = normalize(-light.direction); + vec3 reflectDir = reflect(-lightDir, norm); + + 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)); + + return (ambient + diffuse + specular); +} + +vec3 ComputePointLight(PointLight light, vec3 norm, vec3 viewDir) +{ + 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 reflectDir = reflect(-lightDir, norm); + + 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)); + + return (ambient * attenuation + diffuse * attenuation + specular * 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); + } + + FragColor = vec4(result, 1.0); +} diff --git a/shaders/lighting_vertex.glsl b/shaders/lighting_vertex.glsl new file mode 100644 index 0000000..4501f79 --- /dev/null +++ b/shaders/lighting_vertex.glsl @@ -0,0 +1,20 @@ +#version 330 core +layout (location = 0) in vec3 aPos; +layout (location = 1) in vec3 aNormal; +layout (location = 2) in vec2 aTexCoords; + +out vec3 Normal; +out vec3 FragPos; +out vec2 TexCoords; + +uniform mat4 model; +uniform mat4 view; +uniform mat4 projection; + +void main() +{ + gl_Position = projection * view * model * vec4(aPos, 1.0); + FragPos = vec3(model * vec4(aPos, 1.0)); + Normal = mat3(transpose(inverse(model))) * aNormal; + TexCoords = aTexCoords; +} diff --git a/shaders/vertex.glsl b/shaders/vertex.glsl deleted file mode 100644 index ab99072..0000000 --- a/shaders/vertex.glsl +++ /dev/null @@ -1,18 +0,0 @@ -#version 330 core - - -layout (location = 0) in vec3 aPos; -layout (location = 1) in vec2 aTexCoord; - -out vec2 TexCoord; - -uniform mat4 model; -uniform mat4 view; -uniform mat4 projection; - - -void main() -{ - gl_Position = projection * view * model * vec4(aPos, 1.0); - TexCoord = aTexCoord; -} diff --git a/src/main.cpp b/src/main.cpp index bef521a..6ee14e1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -26,6 +26,9 @@ int main() qoi_desc fish_desc; void *fish_rgba = qoi_read("assets/fish.qoi", &fish_desc, 4); + qoi_desc fish_map_desc; + void *fish_map_rgba = qoi_read("assets/fish-map.qoi", &fish_map_desc, 4); + if (!glfwInit()) { return 1; @@ -59,81 +62,99 @@ int main() glEnable(GL_DEPTH_TEST); - float verts[] = { - -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, - 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, - 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, - 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, - -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, - -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, + float cube_verts[] = { + // positions // normals // texture coords + -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, + 0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, + 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, + 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, + -0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, + -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, - -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, - 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, - -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, - -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, + 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, + 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, + 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, + -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, - -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - -0.5f, 0.5f, -0.5f, 1.0f, 1.0f, - -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, - -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, + -0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, + -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, + -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, + -0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, + -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, - 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, + 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, + 0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, + 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, + 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, + 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, - -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - 0.5f, -0.5f, -0.5f, 1.0f, 1.0f, - 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, - 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, - -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, - -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, + -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, + 0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f, + 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, + 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, + -0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, + -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, - -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, - 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, - -0.5f, 0.5f, -0.5f, 0.0f, 1.0f + -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, + 0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, + 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, + 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, + -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, + -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f }; - unsigned int program = create_program("shaders/vertex.glsl", "shaders/fragment.glsl"); - - unsigned int texture; - glGenTextures(1, &texture); - glBindTexture(GL_TEXTURE_2D, texture); + unsigned int fish_texture; + glGenTextures(1, &fish_texture); + glBindTexture(GL_TEXTURE_2D, fish_texture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, fish_desc.width, fish_desc.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, fish_rgba); glGenerateMipmap(GL_TEXTURE_2D); - unsigned int vertex_array; - glGenVertexArrays(1, &vertex_array); - glBindVertexArray(vertex_array); + unsigned int fish_map_texture; + glGenTextures(1, &fish_map_texture); + glBindTexture(GL_TEXTURE_2D, fish_map_texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, fish_map_desc.width, fish_map_desc.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, fish_map_rgba); + glGenerateMipmap(GL_TEXTURE_2D); + + unsigned int lighting_program = create_program("shaders/lighting_vertex.glsl", "shaders/lighting_fragment.glsl"); + unsigned int light_cube_program = create_program("shaders/light_cube_vertex.glsl", "shaders/light_cube_fragment.glsl"); + + unsigned int cube_buffer = 0; + glGenBuffers(1, &cube_buffer); + glBindBuffer(GL_ARRAY_BUFFER, cube_buffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(cube_verts), &cube_verts, GL_STATIC_DRAW); + + unsigned int object_vao; + glGenVertexArrays(1, &object_vao); + glBindVertexArray(object_vao); - unsigned int buffer = 0; - glGenBuffers(1, &buffer); - glBindBuffer(GL_ARRAY_BUFFER, buffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(verts), &verts, GL_STATIC_DRAW); - // position - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (const void*)0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (const void*)0); + glEnableVertexAttribArray(0); + // normal + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (const void*)(3 * sizeof(float))); + glEnableVertexAttribArray(1); + // texture coord + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (const void*)(6 * sizeof(float))); + glEnableVertexAttribArray(2); + + unsigned int light_source_vao; + glGenVertexArrays(1, &light_source_vao); + glBindVertexArray(light_source_vao); + + // position + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (const void*)0); glEnableVertexAttribArray(0); - // texture coords - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (const void*)(3 * sizeof(float))); - glEnableVertexAttribArray(1); glm::mat4 projection = glm::mat4(1.0f); Camera camera; - framebuffer_size_callback = [&projection, program](int width, int height) { + framebuffer_size_callback = [&projection](int width, int height) { projection = glm::perspective(glm::radians(45.0f), (float)width / (float)height, 0.1f, 100.0f); - glUniformMatrix4fv(glGetUniformLocation(program, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); glViewport(0, 0, width, height); }; @@ -144,6 +165,8 @@ 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; @@ -171,16 +194,43 @@ int main() glClearColor(0.5, 0.5, 0.5, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glUseProgram(program); - glUniformMatrix4fv(glGetUniformLocation(program, "view"), 1, GL_FALSE, glm::value_ptr(camera.view)); + { + /* lit object */ + { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, fish_texture); + glActiveTexture (GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, fish_map_texture); - glBindTexture(GL_TEXTURE_2D, texture); - glBindVertexArray(vertex_array); + glUseProgram(lighting_program); - for (int i = 0; i < 12; i++) { - glm::mat4 model = glm::translate(glm::mat4(1.0), glm::vec3(2 * i, 0.0f, 0.0f)); - glUniformMatrix4fv(glGetUniformLocation(program, "model"), 1, GL_FALSE, glm::value_ptr(model)); - glDrawArrays(GL_TRIANGLES, 0, 36); + 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); + + 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); + } + + /* 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); + + } } glfwSwapBuffers(window);