From c746f1d8eb502d060e49485c89fe1b215c690aea Mon Sep 17 00:00:00 2001 From: Nathan Chapman Date: Sat, 5 Jul 2025 12:13:42 -0600 Subject: [PATCH] Add diffuse lighting --- CMakeLists.txt | 2 ++ {lib => include}/stb_image.h | 0 shaders/shader.frag | 16 ++++++++++- shaders/shader.vert | 3 ++ src/file.cpp | 6 ++-- src/file.h | 5 ++-- src/light.cpp | 12 ++++++++ src/light.h | 19 +++++++++++++ src/main.cpp | 35 ++++++++++++++--------- src/math.h | 5 +++- src/mesh.cpp | 55 ++++++++++++++++++++++++++++++++++-- src/mesh.h | 1 + src/shader.cpp | 10 +++++-- src/shader.h | 4 +++ src/texture.h | 2 +- 15 files changed, 149 insertions(+), 26 deletions(-) rename {lib => include}/stb_image.h (100%) create mode 100644 src/light.cpp create mode 100644 src/light.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 207578d..ce5dd3f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.19) project(OpenGLTest CXX) set(CMAKE_CXX_STANDARD 17) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) find_package(OpenGL REQUIRED) find_package(GLEW REQUIRED) @@ -11,6 +12,7 @@ find_package(glfw3 REQUIRED) file(GLOB SOURCES src/*.h src/*.cpp) add_executable(opengl_test ${SOURCES}) +target_include_directories(opengl_test PUBLIC include) target_link_libraries(opengl_test OpenGL::GL GLEW::GLEW diff --git a/lib/stb_image.h b/include/stb_image.h similarity index 100% rename from lib/stb_image.h rename to include/stb_image.h diff --git a/shaders/shader.frag b/shaders/shader.frag index cc3bb6c..a5a7214 100644 --- a/shaders/shader.frag +++ b/shaders/shader.frag @@ -2,11 +2,25 @@ in vec4 vertex_color; in vec2 texture_coord; +in vec3 normal; out vec4 color; +struct Directional_Light { + vec3 color; + float ambient_intensity; + vec3 direction; + float diffuse_intensity; +}; + uniform sampler2D tex; +uniform Directional_Light sun; void main() { - color = texture(tex, texture_coord); + vec4 ambient_color = vec4(sun.color, 1.0f) * sun.ambient_intensity; + + float diffuse_factor = max(dot(normalize(normal), normalize(sun.direction)), 0.0f); + vec4 diffuse_color = vec4(sun.color, 1.0f) * sun.diffuse_intensity * diffuse_factor; + + color = texture(tex, texture_coord) * (ambient_color + diffuse_color); } diff --git a/shaders/shader.vert b/shaders/shader.vert index c79dad3..a3e4c6c 100644 --- a/shaders/shader.vert +++ b/shaders/shader.vert @@ -2,9 +2,11 @@ layout (location = 0) in vec3 pos; layout (location = 1) in vec2 tex; +layout (location = 2) in vec3 norm; out vec4 vertex_color; out vec2 texture_coord; +out vec3 normal; uniform mat4 projection; uniform mat4 model; @@ -14,4 +16,5 @@ void main() { gl_Position = projection * view * model * vec4(pos, 1.0); vertex_color = vec4(clamp(pos, 0.0f, 1.0f), 1.0f); texture_coord = tex; + normal = mat3(transpose(inverse(model))) * norm; } diff --git a/src/file.cpp b/src/file.cpp index fcc2ac9..1c042f2 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -1,7 +1,7 @@ #include "file.h" -std::string read_entire_file(const char *path) { - std::string content; +string read_entire_file(const char *path) { + string content; std::ifstream file_stream(path, std::ios::in); if (!file_stream.is_open()) { @@ -9,7 +9,7 @@ std::string read_entire_file(const char *path) { return ""; } - std::string line = ""; + string line = ""; while (!file_stream.eof()) { std::getline(file_stream, line); diff --git a/src/file.h b/src/file.h index b22bb39..9438bce 100644 --- a/src/file.h +++ b/src/file.h @@ -1,7 +1,6 @@ #pragma once -#include -#include #include +#include "math.h" -std::string read_entire_file(const char *path); +string read_entire_file(const char *path); diff --git a/src/light.cpp b/src/light.cpp new file mode 100644 index 0000000..e74df3f --- /dev/null +++ b/src/light.cpp @@ -0,0 +1,12 @@ +#include "light.h" + +Light::Light(Vector3 color, f32 ambient_intensity, Vector3 direction, f32 diffuse_intensity) : color(color), ambient_intensity(ambient_intensity), direction(direction), diffuse_intensity(diffuse_intensity) {} + +void use_light(Light *light, f32 color_location, f32 ambient_intensity_location, f32 direction_location, f32 diffuse_intensity_location) { + glUniform3f(color_location, light->color.x, light->color.y, light->color.z); + glUniform1f(ambient_intensity_location, light->ambient_intensity); + + glUniform3f(direction_location, light->direction.x, light->direction.y, light->direction.z); + glUniform1f(diffuse_intensity_location, light->diffuse_intensity); +} + diff --git a/src/light.h b/src/light.h new file mode 100644 index 0000000..334e7c4 --- /dev/null +++ b/src/light.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include +#include "math.h" + +struct Light { + Vector3 color = Vector3(1.0f, 1.0f, 1.0f); + f32 ambient_intensity = 1.0f; + + // For a directional light + Vector3 direction = Vector3(0.0f, -1.0f, 0.0f); // Default to down + f32 diffuse_intensity = 0.0f; + + Light(Vector3 color, f32 ambient_intensity, Vector3 direction, f32 diffuse_intensity); + ~Light() = default; +}; + +void use_light(Light *light, f32 color_location, f32 ambient_intensity_location, f32 direction_location, f32 diffuse_intensity_location); diff --git a/src/main.cpp b/src/main.cpp index 873d6e7..291c8f3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,6 +5,7 @@ #include "window.h" #include "camera.h" #include "texture.h" +#include "light.h" static const char *vertex_shader_code = "shaders/shader.vert"; @@ -24,11 +25,11 @@ int main() { { // Create a mesh f32 vertices[] = { - // x y z u v - -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, -1.0f, 1.0f, 1.0f, 0.0f, - 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, 1.0f + // x y z u v nx ny nz + -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f }; u32 indices[] = { @@ -38,12 +39,14 @@ int main() { 0, 1, 2 }; + calculate_normals_avg(vertices, 32, 8, indices, 12, 5); + Mesh *pyramid1 = new Mesh(); - create_mesh(pyramid1, vertices, indices, 20, 12); + create_mesh(pyramid1, vertices, indices, 32, 12); meshes[0] = pyramid1; Mesh *pyramid2 = new Mesh(); - create_mesh(pyramid2, vertices, indices, 20, 12); + create_mesh(pyramid2, vertices, indices, 32, 12); meshes[1] = pyramid2; } @@ -60,9 +63,9 @@ int main() { Texture plaster_texture = Texture((char *)"assets/textures/plaster_texture_1k.png"); load_texture(&plaster_texture); - Matrix4 projection = glm::perspective( - 45.0f, (f32)window.buffer_width / (f32)window.buffer_height, 0.1f, - 100.0f); + Light sun_light(Vector3(1.0f, 1.0f, 1.0f), 0.2f, Vector3(2.0f, -1.0, -2.0f), 1.0f); + + Matrix4 projection = glm::perspective(45.0f, (f32)window.buffer_width / (f32)window.buffer_height, 0.1f, 100.0f); Camera camera(Vector3(0.0f, 0.0f, 0.0f), Vector3(0.0f, 1.0f, 0.0f), 90.0f, 0.0f, 5.0f, 1.0f); @@ -74,9 +77,6 @@ int main() { dt = now - last_dt; last_dt = now; - // Get and handle user input events - glfwPollEvents(); - key_control(&camera, window.ascii_keys, dt); mouse_control(&camera, window.x_change_position, window.y_change_position); @@ -90,6 +90,12 @@ int main() { glUseProgram(shaders[0].id); + use_light( + &sun_light, + shaders[0].uniform_ambient_color, shaders[0].uniform_ambient_intensity, + shaders[0].uniform_diffuse_direction, shaders[0].uniform_diffuse_intensity + ); + { Matrix4 model(1.0f); model = glm::translate(model, Vector3(0.0f, 0.0f, -2.5f)); @@ -125,6 +131,9 @@ int main() { // that it now shows. We then can start drawing on the other // buffer. glfwSwapBuffers(window.gl_window); + + // Get and handle user input events + glfwPollEvents(); } return 0; diff --git a/src/math.h b/src/math.h index f5392a9..677716e 100644 --- a/src/math.h +++ b/src/math.h @@ -1,6 +1,7 @@ #pragma once -#include +// #include +#include #include #include #include @@ -34,5 +35,7 @@ typedef double f64; using Matrix4 = glm::mat4; using Vector3 = glm::vec3; +using string = std::string; const f32 RADIAN_FACTOR = 3.14159265f / 180.0f; + diff --git a/src/mesh.cpp b/src/mesh.cpp index 649ad93..226e247 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -32,13 +32,16 @@ void create_mesh( glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices_count, vertices, GL_STATIC_DRAW); // Position vertices - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(vertices[0]) * 5, 0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(vertices[0]) * 8, 0); glEnableVertexAttribArray(0); // Texture coordinates - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(vertices[0]) * 5, (void *)(sizeof(vertices[0]) * 3)); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(vertices[0]) * 8, (void *)(sizeof(vertices[0]) * 3)); glEnableVertexAttribArray(1); + glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(vertices[0]) * 8, (void *)(sizeof(vertices[0]) * 5)); + glEnableVertexAttribArray(2); + // Unbinding glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); @@ -73,3 +76,51 @@ void clear_mesh(Mesh *mesh) { mesh->index_count = 0; } + +void calculate_normals_avg(f32 *vertices, u32 vertices_count, u32 vertices_length, u32 *indices, u32 indices_count, u32 normal_offset) { + for (size_t i = 0; i< indices_count; i+=3) { + u32 in0 = indices[i] * vertices_length; + u32 in1 = indices[i+1] * vertices_length; + u32 in2 = indices[i+2] * vertices_length; + + Vector3 v1; + v1.x = vertices[in1] - vertices[in0]; + v1.y = vertices[in1+1] - vertices[in0+1]; + v1.z = vertices[in1+2] - vertices[in0+2]; + + Vector3 v2; + v2.x = vertices[in2] - vertices[in0]; + v2.y = vertices[in2+1] - vertices[in0+1]; + v2.z = vertices[in2+2] - vertices[in0+2]; + + Vector3 normal = glm::cross(v1, v2); + normal = glm::normalize(normal); + + in0 += normal_offset; + in1 += normal_offset; + in2 += normal_offset; + + vertices[in0] += normal.x; + vertices[in0+1] += normal.y; + vertices[in0+2] += normal.z; + + vertices[in1] += normal.x; + vertices[in1+1] += normal.y; + vertices[in1+2] += normal.z; + + vertices[in2] += normal.x; + vertices[in2+1] += normal.y; + vertices[in2+2] += normal.z; + } + + for(size_t i=0; iid = glCreateProgram(); @@ -65,6 +65,12 @@ bool create_shader(Shader *shader, const char *vertex_shader_path, const char *f shader->uniform_model = glGetUniformLocation(shader->id, "model"); shader->uniform_view = glGetUniformLocation(shader->id, "view"); + shader->uniform_ambient_color = glGetUniformLocation(shader->id, "sun.color"); + shader->uniform_ambient_intensity = glGetUniformLocation(shader->id, "sun.ambient_intensity"); + + shader->uniform_diffuse_direction = glGetUniformLocation(shader->id, "sun.direction"); + shader->uniform_diffuse_intensity = glGetUniformLocation(shader->id, "sun.diffuse_intensity"); + return true; } diff --git a/src/shader.h b/src/shader.h index 98cc1ba..5339245 100644 --- a/src/shader.h +++ b/src/shader.h @@ -15,6 +15,10 @@ struct Shader { u32 uniform_projection; u32 uniform_model; u32 uniform_view; + u32 uniform_ambient_color; + u32 uniform_ambient_intensity; + u32 uniform_diffuse_direction; + u32 uniform_diffuse_intensity; Shader(); ~Shader(); diff --git a/src/texture.h b/src/texture.h index 260aee1..45bc973 100644 --- a/src/texture.h +++ b/src/texture.h @@ -1,8 +1,8 @@ #pragma once #include +#include #include "math.h" -#include "../lib/stb_image.h" struct Texture { u32 id = 0;