From c6ae576289b8ac3006c8da1f9fdc8f06d4a1a6eb Mon Sep 17 00:00:00 2001 From: Nathan Chapman Date: Sun, 6 Jul 2025 21:30:29 -0600 Subject: [PATCH] Add floor and point lights --- shaders/shader.frag | 67 ++++++++++++++++++++++----- src/light.cpp | 8 ---- src/light.h | 9 +++- src/main.cpp | 107 ++++++++++++++++++++++++++++++++++---------- src/math.h | 2 +- src/shader.cpp | 71 ++++++++++++++++++++++++----- src/shader.h | 45 ++++++++++++++----- 7 files changed, 240 insertions(+), 69 deletions(-) diff --git a/shaders/shader.frag b/shaders/shader.frag index 0b548ee..c79f91f 100644 --- a/shaders/shader.frag +++ b/shaders/shader.frag @@ -7,42 +7,85 @@ in vec3 frag_pos; out vec4 color; -struct Directional_Light { +// Must match the same as in math.h +const int MAX_POINT_LIGHTS = 3; + +struct Light { vec3 color; float ambient_intensity; - vec3 direction; float diffuse_intensity; }; +struct Directional_Light { + Light base; + vec3 direction; +}; + +struct Point_Light { + Light base; + vec3 position; + float constant; + float linear; + float exponent; +}; + struct Material { float shininess; float specular_intensity; }; -uniform sampler2D tex; + uniform Directional_Light sun; +uniform Point_Light point_lights[MAX_POINT_LIGHTS]; + +uniform int point_light_count; +uniform sampler2D tex; uniform Material material; uniform vec3 eye_position; +vec4 calculate_light_by_direction(Light light, vec3 direction) { + vec4 ambient_color = vec4(light.color, 1.0f) * light.ambient_intensity; -void main() { - 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; + float diffuse_factor = max(dot(normalize(normal), normalize(direction)), 0.0f); + vec4 diffuse_color = vec4(light.color * light.diffuse_intensity * diffuse_factor, 1.0f); vec4 specular_color = vec4(0, 0, 0, 0); if (diffuse_factor > 0.0f) { vec3 frag_to_eye = normalize(eye_position - frag_pos); - vec3 reflected_vertex = normalize(reflect(sun.direction, normalize(normal))); + vec3 reflected_vertex = normalize(reflect(direction, normalize(normal))); float specular_factor = dot(frag_to_eye, reflected_vertex); - if (specular_factor > 0) { + if (specular_factor > 0.0f) { specular_factor = pow(specular_factor, material.shininess); - specular_color = vec4(sun.color * material.specular_intensity * specular_factor, 1.0f); + specular_color = vec4(light.color * material.specular_intensity * specular_factor, 1.0f); } } - color = texture(tex, texture_coord) * (ambient_color + diffuse_color + specular_color); + return ambient_color + diffuse_color + specular_color; +} + +vec4 calculate_point_lights() { + vec4 final_color = vec4(0, 0, 0, 0); + + for (int i=0; icolor.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 index 436fc12..fdb567e 100644 --- a/src/light.h +++ b/src/light.h @@ -14,5 +14,10 @@ struct Directional_Light : public Light { Vector3 direction = Vector3(0.0f, -1.0f, 0.0f); // Default to down }; -// Some of these should be u32 -void use_light(Directional_Light *light, f32 color_location, f32 ambient_intensity_location, f32 diffuse_intensity_location, f32 direction_location); +struct Point_Light : public Light { + Vector3 position = Vector3(0.0f, 0.0f, 0.0f); + f32 constant = 1.0f; + f32 linear = 0.0f; + f32 exponent = 0.0f; +}; + diff --git a/src/main.cpp b/src/main.cpp index 62b7d3c..bfb5bfa 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -30,6 +30,26 @@ int main() { f32 dt = 0.0f; f32 last_dt = 0.f; + { + // Create a floor + f32 vertices[] = { + // x y z u v nx ny nz + -10.0f, 0.0f, -10.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, + 10.0f, 0.0f, -10.0f, 10.0f, 0.0f, 0.0f, -1.0f, 0.0f, + -10.0f, 0.0f, 10.0f, 0.0f, 10.0f, 0.0f, -1.0f, 0.0f, + 10.0f, 0.0f, 10.0f, 10.0f, 10.0f, 0.0f, -1.0f, 0.0f, + }; + + u32 indices[] { + 0, 2, 1, + 1, 2, 3 + }; + + Mesh *floor = new Mesh(); + create_mesh(floor, vertices, indices, 32, 6); + meshes[0] = floor; + } + { // Create a mesh f32 vertices[] = { @@ -51,11 +71,11 @@ int main() { Mesh *pyramid1 = new Mesh(); create_mesh(pyramid1, vertices, indices, 32, 12); - meshes[0] = pyramid1; + meshes[1] = pyramid1; Mesh *pyramid2 = new Mesh(); create_mesh(pyramid2, vertices, indices, 32, 12); - meshes[1] = pyramid2; + meshes[2] = pyramid2; } { @@ -73,14 +93,47 @@ int main() { plaster_texture.file_path = (char *)"assets/textures/plaster_texture_1k.png"; load_texture(&plaster_texture); - Material shiny_material{32.0f, 1.0f}; - Material dull_material{4.0f, 0.3f}; + Material shiny_material; + shiny_material.shininess = 256.0f; + shiny_material.specular_intensity = 4.0f; + + Material dull_material; + dull_material.shininess = 4.0f; + dull_material.specular_intensity = 0.3f; Directional_Light sun_light; - sun_light.ambient_intensity = 0.2f; - sun_light.diffuse_intensity = 1.0f; + sun_light.ambient_intensity = 0.0f; + sun_light.diffuse_intensity = 0.0f; sun_light.direction = Vector3(2.0f, -1.0, -2.0f); + Point_Light point_lights[MAX_POINT_LIGHTS]; + + { + Point_Light point_light; + point_light.color = Vector3(1.0f, 1.0f, 1.0f); + point_light.ambient_intensity = 0.0f; + point_light.diffuse_intensity = 0.3f; + point_light.position = Vector3(10.0, 10.0f, 0.0f); + point_light.constant = 0.3f; + point_light.linear = 0.1f; + point_light.exponent = 0.1f; + point_lights[0] = point_light; + } + + { + Point_Light point_light; + point_light.color = Vector3(1.0f, 0.6f, 0.0f); + point_light.ambient_intensity = 0.00f; + point_light.diffuse_intensity = 0.3f; + point_light.position = Vector3(-10.0, 0.0f, 0.0f); + point_light.constant = 0.3f; + point_light.linear = 0.1f; + point_light.exponent = 0.1f; + point_lights[1] = point_light; + } + + u32 point_light_count = 2; + Matrix4 projection = glm::perspective(45.0f, (f32)window.buffer_width / (f32)window.buffer_height, 0.1f, 100.0f); Camera camera; @@ -107,38 +160,46 @@ int main() { glUseProgram(shaders[0].id); - use_light( - &sun_light, - shaders[0].uniform_ambient_color, shaders[0].uniform_ambient_intensity, - shaders[0].uniform_diffuse_intensity, shaders[0].uniform_diffuse_direction - ); + use_light(&shaders[0], &sun_light); + use_light(&shaders[0], point_lights, point_light_count); - glUniformMatrix4fv(shaders[0].uniform_projection, 1, GL_FALSE, glm::value_ptr(projection)); + glUniformMatrix4fv(shaders[0].projection, 1, GL_FALSE, glm::value_ptr(projection)); Matrix4 view = calculate_view_matrix(&camera); - glUniformMatrix4fv(shaders[0].uniform_view, 1, GL_FALSE, glm::value_ptr(view)); - glUniform3f(shaders[0].uniform_eye_position, camera.position.x, camera.position.y, camera.position.z); + glUniformMatrix4fv(shaders[0].view, 1, GL_FALSE, glm::value_ptr(view)); + glUniform3f(shaders[0].eye_position, camera.position.x, camera.position.y, camera.position.z); + { Matrix4 model(1.0f); - model = glm::translate(model, Vector3(0.0f, 3.0f, 2.5f)); - // model = glm::scale(model, Vector3(0.4f, 0.4f, 1.0f)); + model = glm::translate(model, Vector3(0.0f, -2.0f, 0.0f)); - glUniformMatrix4fv(shaders[0].uniform_model, 1, GL_FALSE, glm::value_ptr(model)); - use_texture(&clay_texture); - use_material(&shiny_material, shaders[0].uniform_shininess, shaders[0].uniform_specular_intensity); + glUniformMatrix4fv(shaders[0].model, 1, GL_FALSE, glm::value_ptr(model)); + use_texture(&plaster_texture); + use_material(&dull_material, shaders[0].shininess, shaders[0].specular_intensity); render_mesh(meshes[0]); } { Matrix4 model(1.0f); - model = glm::translate(model, Vector3(0.0f, 0.0f, 3.5f)); + model = glm::translate(model, Vector3(-2.0f, 0.0f, -4.0f)); + // model = glm::scale(model, Vector3(0.4f, 0.4f, 1.0f)); - glUniformMatrix4fv(shaders[0].uniform_model, 1, GL_FALSE, glm::value_ptr(model)); - use_texture(&plaster_texture); - use_material(&dull_material, shaders[0].uniform_shininess, shaders[0].uniform_specular_intensity); + glUniformMatrix4fv(shaders[0].model, 1, GL_FALSE, glm::value_ptr(model)); + use_texture(&clay_texture); + use_material(&shiny_material, shaders[0].shininess, shaders[0].specular_intensity); render_mesh(meshes[1]); } + { + Matrix4 model(1.0f); + model = glm::translate(model, Vector3(2.0f, 0.0f, -4.0f)); + + glUniformMatrix4fv(shaders[0].model, 1, GL_FALSE, glm::value_ptr(model)); + use_texture(&clay_texture); + use_material(&dull_material, shaders[0].shininess, shaders[0].specular_intensity); + render_mesh(meshes[2]); + } + glUseProgram(0); // We usually have two buffers, the first is hidden and that's diff --git a/src/math.h b/src/math.h index 677716e..6aff89c 100644 --- a/src/math.h +++ b/src/math.h @@ -38,4 +38,4 @@ using Vector3 = glm::vec3; using string = std::string; const f32 RADIAN_FACTOR = 3.14159265f / 180.0f; - +const u32 MAX_POINT_LIGHTS = 3; diff --git a/src/shader.cpp b/src/shader.cpp index f805e00..2e6fbd2 100644 --- a/src/shader.cpp +++ b/src/shader.cpp @@ -1,4 +1,5 @@ #include "shader.h" +#include "file.h" Shader::~Shader() { @@ -56,18 +57,39 @@ bool create_shader(Shader *shader, const char *vertex_shader_path, const char *f return false; } - shader->uniform_projection = glGetUniformLocation(shader->id, "projection"); - shader->uniform_model = glGetUniformLocation(shader->id, "model"); - shader->uniform_view = glGetUniformLocation(shader->id, "view"); - shader->uniform_eye_position = glGetUniformLocation(shader->id, "eye_position"); + shader->projection = glGetUniformLocation(shader->id, "projection"); + shader->model = glGetUniformLocation(shader->id, "model"); + shader->view = glGetUniformLocation(shader->id, "view"); + shader->eye_position = glGetUniformLocation(shader->id, "eye_position"); - 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"); + shader->directional_light.color = glGetUniformLocation(shader->id, "sun.base.color"); + shader->directional_light.ambient_intensity = glGetUniformLocation(shader->id, "sun.base.ambient_intensity"); + shader->directional_light.diffuse_intensity = glGetUniformLocation(shader->id, "sun.base.diffuse_intensity"); + shader->directional_light.direction = glGetUniformLocation(shader->id, "sun.direction"); - shader->uniform_shininess = glGetUniformLocation(shader->id, "material.shininess"); - shader->uniform_specular_intensity = glGetUniformLocation(shader->id, "material.specular_intensity"); + shader->shininess = glGetUniformLocation(shader->id, "material.shininess"); + shader->specular_intensity = glGetUniformLocation(shader->id, "material.specular_intensity"); + + shader->point_light_count = glGetUniformLocation(shader->id, "point_light_count"); + + for (size_t i=0; ipoint_lights[i].color = glGetUniformLocation(shader->id, location_buffer); + snprintf(location_buffer, sizeof(location_buffer), "point_lights[%zu].base.ambient_intensity", i); + shader->point_lights[i].ambient_intensity = glGetUniformLocation(shader->id, location_buffer); + snprintf(location_buffer, sizeof(location_buffer), "point_lights[%zu].base.diffuse_intensity", i); + shader->point_lights[i].diffuse_intensity = glGetUniformLocation(shader->id, location_buffer); + + snprintf(location_buffer, sizeof(location_buffer), "point_lights[%zu].position", i); + shader->point_lights[i].position = glGetUniformLocation(shader->id, location_buffer); + snprintf(location_buffer, sizeof(location_buffer), "point_lights[%zu].constant", i); + shader->point_lights[i].constant = glGetUniformLocation(shader->id, location_buffer); + snprintf(location_buffer, sizeof(location_buffer), "point_lights[%zu].constant", i); + shader->point_lights[i].constant = glGetUniformLocation(shader->id, location_buffer); + } return true; } @@ -105,7 +127,32 @@ void clear_shader(Shader *shader) { shader->id = 0; } - shader->uniform_model = 0; - shader->uniform_projection = 0; + shader->model = 0; + shader->projection = 0; +} + +void use_light(Shader *shader, Directional_Light *light) { + glUniform3f(shader->directional_light.color, light->color.x, light->color.y, light->color.z); + glUniform1f(shader->directional_light.ambient_intensity, light->ambient_intensity); + + glUniform3f(shader->directional_light.direction, light->direction.x, light->direction.y, light->direction.z); + glUniform1f(shader->directional_light.diffuse_intensity, light->diffuse_intensity); +} + +void use_light(Shader *shader, Point_Light *point_lights, u32 point_light_count) { + if (point_light_count > MAX_POINT_LIGHTS) point_light_count = MAX_POINT_LIGHTS; + + glUniform1i(shader->point_light_count, point_light_count); + + for (size_t i = 0; i < point_light_count; i++) { + glUniform3f(shader->point_lights[i].color, point_lights[i].color.x, point_lights[i].color.y, point_lights[i].color.z); + glUniform1f(shader->point_lights[i].ambient_intensity, point_lights[i].ambient_intensity); + glUniform1f(shader->point_lights[i].diffuse_intensity, point_lights[i].diffuse_intensity); + + glUniform3f(shader->point_lights[i].position, point_lights[i].position.x, point_lights[i].position.y, point_lights[i].position.z); + glUniform1f(shader->point_lights[i].constant, point_lights[i].constant); + glUniform1f(shader->point_lights[i].linear, point_lights[i].linear); + glUniform1f(shader->point_lights[i].exponent, point_lights[i].exponent); + } } diff --git a/src/shader.h b/src/shader.h index 55beaa2..f61def4 100644 --- a/src/shader.h +++ b/src/shader.h @@ -3,7 +3,7 @@ #include #include #include "math.h" -#include "file.h" +#include "light.h" enum Shader_Type : u32 { VERTEX = GL_VERTEX_SHADER, @@ -12,19 +12,38 @@ enum Shader_Type : u32 { struct Shader { u32 id = 0; - u32 uniform_projection = 0; - u32 uniform_model = 0; - u32 uniform_view = 0; - u32 uniform_eye_position = 0; - u32 uniform_ambient_color = 0; - u32 uniform_ambient_intensity = 0; + u32 projection = 0; + u32 model = 0; + u32 view = 0; + u32 eye_position = 0; + u32 shininess = 0; + u32 specular_intensity = 0; + u32 position = 0; + u32 constant = 0; + u32 linear = 0; + u32 exponent = 0; + + struct { + u32 color; + u32 ambient_intensity; + u32 diffuse_intensity; - u32 uniform_diffuse_direction = 0; - u32 uniform_diffuse_intensity = 0; + u32 direction; + } directional_light; - u32 uniform_shininess = 0; - u32 uniform_specular_intensity = 0; + u32 point_light_count = 0; + + struct { + u32 color; + u32 ambient_intensity; + u32 diffuse_intensity; + + u32 position; + u32 constant; + u32 linear; + u32 exponent; + } point_lights[MAX_POINT_LIGHTS]; ~Shader(); }; @@ -32,3 +51,7 @@ struct Shader { bool create_shader(Shader *shader, const char *vertex_shader_path, const char *fragment_shader_path); bool add_shader(Shader *shader, const char *shader_code, Shader_Type type); void clear_shader(Shader *shader); + +// Some of these should be u32 +void use_light(Shader *shader, Directional_Light *light); +void use_light(Shader *shader, Point_Light *light, u32 point_light_count);