Add spot lights

This commit is contained in:
Nathan Chapman 2025-07-07 20:00:35 -06:00
parent c6ae576289
commit 62a4b739dd
9 changed files with 167 additions and 32 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

@ -1,4 +1,4 @@
#version 330 #version 460 core
in vec4 vertex_color; in vec4 vertex_color;
in vec2 texture_coord; in vec2 texture_coord;
@ -9,6 +9,7 @@ out vec4 color;
// Must match the same as in math.h // Must match the same as in math.h
const int MAX_POINT_LIGHTS = 3; const int MAX_POINT_LIGHTS = 3;
const int MAX_SPOT_LIGHTS = 3;
struct Light { struct Light {
vec3 color; vec3 color;
@ -17,18 +18,25 @@ struct Light {
}; };
struct Directional_Light { struct Directional_Light {
Light base; Light light;
vec3 direction; vec3 direction;
}; };
struct Point_Light { struct Point_Light {
Light base; Light light;
vec3 position; vec3 position;
float constant; float constant;
float linear; float linear;
float exponent; float exponent;
}; };
struct Spot_Light {
Point_Light point_light;
vec3 direction;
float edge;
};
struct Material { struct Material {
float shininess; float shininess;
float specular_intensity; float specular_intensity;
@ -37,8 +45,10 @@ struct Material {
uniform Directional_Light sun; uniform Directional_Light sun;
uniform Point_Light point_lights[MAX_POINT_LIGHTS]; uniform Point_Light point_lights[MAX_POINT_LIGHTS];
uniform Spot_Light spot_lights[MAX_SPOT_LIGHTS];
uniform int point_light_count; uniform int point_light_count;
uniform int spot_light_count;
uniform sampler2D tex; uniform sampler2D tex;
uniform Material material; uniform Material material;
uniform vec3 eye_position; uniform vec3 eye_position;
@ -65,27 +75,55 @@ vec4 calculate_light_by_direction(Light light, vec3 direction) {
return ambient_color + diffuse_color + specular_color; return ambient_color + diffuse_color + specular_color;
} }
vec4 calculate_point_light(Point_Light point_light) {
vec3 direction = frag_pos - point_light.position;
float distance = length(direction);
direction = normalize(direction);
vec4 light_color = calculate_light_by_direction(point_light.light, direction);
float attentuation = point_light.exponent * distance * distance + point_light.linear * distance + point_light.constant;
return (light_color / attentuation);
}
vec4 calculate_point_lights() { vec4 calculate_point_lights() {
vec4 final_color = vec4(0, 0, 0, 0); vec4 final_color = vec4(0, 0, 0, 0);
for (int i=0; i<point_light_count; i++) { for (int i=0; i<point_light_count; i++) {
vec3 direction = frag_pos - point_lights[i].position; final_color += calculate_point_light(point_lights[i]);
float distance = length(direction); }
direction = normalize(direction);
vec4 light_color = calculate_light_by_direction(point_lights[i].base, direction); return final_color;
float attentuation = point_lights[i].exponent * distance * distance + point_lights[i].linear * distance + point_lights[i].constant; }
final_color += (light_color / attentuation); vec4 calculate_spot_light(Spot_Light spot_light) {
vec3 ray_direction = normalize(frag_pos - spot_light.point_light.position);
float spot_light_factor = dot(ray_direction, spot_light.direction);
if (spot_light_factor > spot_light.edge) {
vec4 light_color = calculate_point_light(spot_light.point_light);
return light_color * (1.0f - (1.0f - spot_light_factor)*(1.0f/(1.0f - spot_light.edge)));
}
return vec4(0, 0, 0, 0);
}
vec4 calculate_spot_lights() {
vec4 final_color = vec4(0, 0, 0, 0);
for (int i=0; i<spot_light_count; i++) {
final_color += calculate_spot_light(spot_lights[i]);
} }
return final_color; return final_color;
} }
void main() { void main() {
vec4 final_color = calculate_light_by_direction(sun.base, sun.direction); vec4 final_color = calculate_light_by_direction(sun.light, sun.direction);
final_color += calculate_point_lights(); final_color += calculate_point_lights();
final_color += calculate_spot_lights();
color = texture(tex, texture_coord) * final_color; color = texture(tex, texture_coord) * final_color;
} }

View File

@ -1,4 +1,4 @@
#version 330 #version 460 core
layout (location = 0) in vec3 pos; layout (location = 0) in vec3 pos;
layout (location = 1) in vec2 tex; layout (location = 1) in vec2 tex;

View File

@ -1,2 +0,0 @@
#include "light.h"

View File

@ -21,3 +21,13 @@ struct Point_Light : public Light {
f32 exponent = 0.0f; f32 exponent = 0.0f;
}; };
struct Spot_Light : public Light {
Vector3 direction = Vector3(0.0f, -1.0f, 0.0f);
Vector3 position = Vector3(0.0f, 0.0f, 0.0f);
f32 constant = 1.0f;
f32 linear = 0.0f;
f32 exponent = 0.0f;
f32 edge = 0.0f;
f32 processed_edge = 0.0f; // Don't forget to glm::radians(edge)
};

View File

@ -107,36 +107,60 @@ int main() {
sun_light.direction = Vector3(2.0f, -1.0, -2.0f); sun_light.direction = Vector3(2.0f, -1.0, -2.0f);
Point_Light point_lights[MAX_POINT_LIGHTS]; Point_Light point_lights[MAX_POINT_LIGHTS];
u32 point_light_count = 0;
{ {
Point_Light point_light; Point_Light point_light;
point_light.color = Vector3(1.0f, 1.0f, 1.0f); point_light.color = Vector3(1.0f, 0.0f, 1.0f);
point_light.ambient_intensity = 0.0f; point_light.ambient_intensity = 0.0f;
point_light.diffuse_intensity = 0.3f; point_light.diffuse_intensity = 0.3f;
point_light.position = Vector3(10.0, 10.0f, 0.0f); point_light.position = Vector3(10.0f, 2.0f, 0.0f);
point_light.constant = 0.3f; point_light.constant = 0.3f;
point_light.linear = 0.1f; point_light.linear = 0.1f;
point_light.exponent = 0.1f; point_light.exponent = 0.1f;
point_lights[0] = point_light; point_lights[0] = point_light;
point_light_count++;
} }
{ {
Point_Light point_light; Point_Light point_light;
point_light.color = Vector3(1.0f, 0.6f, 0.0f); point_light.color = Vector3(0.0f, 1.0f, 0.0f);
point_light.ambient_intensity = 0.00f; point_light.ambient_intensity = 0.0f;
point_light.diffuse_intensity = 0.3f; point_light.diffuse_intensity = 0.3f;
point_light.position = Vector3(-10.0, 0.0f, 0.0f); point_light.position = Vector3(-10.0f, 2.0f, 0.0f);
point_light.constant = 0.3f; point_light.constant = 0.3f;
point_light.linear = 0.1f; point_light.linear = 0.1f;
point_light.exponent = 0.1f; point_light.exponent = 0.1f;
point_lights[1] = point_light; point_lights[1] = point_light;
point_light_count++;
} }
u32 point_light_count = 2; Spot_Light spot_lights[MAX_SPOT_LIGHTS];
u32 spot_light_count = 0;
{
Spot_Light spot_light;
spot_light.color = Vector3(0.0f, 0.0f, 1.0f);
spot_light.direction = glm::normalize(Vector3(0.0f, -1.0f, 0.0f));
spot_light.ambient_intensity = 5.0f;
spot_light.diffuse_intensity = 2.0f;
spot_light.position = Vector3(0.0f, 10.0f, 0.0f);
spot_light.constant = 1.0f;
spot_light.linear = 0.0f;
spot_light.exponent = 0.0f;
spot_light.edge = 20.0f;
spot_light.processed_edge = cosf(glm::radians(20.0f));
spot_lights[0] = spot_light;
spot_light_count++;
}
Matrix4 projection = glm::perspective(45.0f, (f32)window.buffer_width / (f32)window.buffer_height, 0.1f, 100.0f); Matrix4 projection = glm::perspective(45.0f, (f32)window.buffer_width / (f32)window.buffer_height, 0.1f, 100.0f);
Camera camera; Camera camera;
camera.position.y = 2.0f;
update_camera(&camera); update_camera(&camera);
@ -162,6 +186,7 @@ int main() {
use_light(&shaders[0], &sun_light); use_light(&shaders[0], &sun_light);
use_light(&shaders[0], point_lights, point_light_count); use_light(&shaders[0], point_lights, point_light_count);
use_light(&shaders[0], spot_lights, spot_light_count);
glUniformMatrix4fv(shaders[0].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); Matrix4 view = calculate_view_matrix(&camera);
@ -169,9 +194,9 @@ int main() {
glUniform3f(shaders[0].eye_position, camera.position.x, camera.position.y, camera.position.z); glUniform3f(shaders[0].eye_position, camera.position.x, camera.position.y, camera.position.z);
{ { // Floor
Matrix4 model(1.0f); Matrix4 model(1.0f);
model = glm::translate(model, Vector3(0.0f, -2.0f, 0.0f)); model = glm::translate(model, Vector3(0.0f, 0.0f, 0.0f));
glUniformMatrix4fv(shaders[0].model, 1, GL_FALSE, glm::value_ptr(model)); glUniformMatrix4fv(shaders[0].model, 1, GL_FALSE, glm::value_ptr(model));
use_texture(&plaster_texture); use_texture(&plaster_texture);
@ -179,9 +204,9 @@ int main() {
render_mesh(meshes[0]); render_mesh(meshes[0]);
} }
{ { // Prism
Matrix4 model(1.0f); Matrix4 model(1.0f);
model = glm::translate(model, Vector3(-2.0f, 0.0f, -4.0f)); model = glm::translate(model, Vector3(0.0f, 1.0f, 0.0f));
// model = glm::scale(model, Vector3(0.4f, 0.4f, 1.0f)); // model = glm::scale(model, Vector3(0.4f, 0.4f, 1.0f));
glUniformMatrix4fv(shaders[0].model, 1, GL_FALSE, glm::value_ptr(model)); glUniformMatrix4fv(shaders[0].model, 1, GL_FALSE, glm::value_ptr(model));
@ -190,9 +215,9 @@ int main() {
render_mesh(meshes[1]); render_mesh(meshes[1]);
} }
{ { // Prism
Matrix4 model(1.0f); Matrix4 model(1.0f);
model = glm::translate(model, Vector3(2.0f, 0.0f, -4.0f)); model = glm::translate(model, Vector3(2.0f, 1.0f, -4.0f));
glUniformMatrix4fv(shaders[0].model, 1, GL_FALSE, glm::value_ptr(model)); glUniformMatrix4fv(shaders[0].model, 1, GL_FALSE, glm::value_ptr(model));
use_texture(&clay_texture); use_texture(&clay_texture);

View File

@ -39,3 +39,4 @@ using string = std::string;
const f32 RADIAN_FACTOR = 3.14159265f / 180.0f; const f32 RADIAN_FACTOR = 3.14159265f / 180.0f;
const u32 MAX_POINT_LIGHTS = 3; const u32 MAX_POINT_LIGHTS = 3;
const u32 MAX_SPOT_LIGHTS = 3;

View File

@ -62,25 +62,27 @@ bool create_shader(Shader *shader, const char *vertex_shader_path, const char *f
shader->view = glGetUniformLocation(shader->id, "view"); shader->view = glGetUniformLocation(shader->id, "view");
shader->eye_position = glGetUniformLocation(shader->id, "eye_position"); shader->eye_position = glGetUniformLocation(shader->id, "eye_position");
shader->directional_light.color = glGetUniformLocation(shader->id, "sun.base.color"); shader->directional_light.color = glGetUniformLocation(shader->id, "sun.light.color");
shader->directional_light.ambient_intensity = glGetUniformLocation(shader->id, "sun.base.ambient_intensity"); shader->directional_light.ambient_intensity = glGetUniformLocation(shader->id, "sun.light.ambient_intensity");
shader->directional_light.diffuse_intensity = glGetUniformLocation(shader->id, "sun.base.diffuse_intensity"); shader->directional_light.diffuse_intensity = glGetUniformLocation(shader->id, "sun.light.diffuse_intensity");
shader->directional_light.direction = glGetUniformLocation(shader->id, "sun.direction"); shader->directional_light.direction = glGetUniformLocation(shader->id, "sun.direction");
shader->shininess = glGetUniformLocation(shader->id, "material.shininess"); shader->shininess = glGetUniformLocation(shader->id, "material.shininess");
shader->specular_intensity = glGetUniformLocation(shader->id, "material.specular_intensity"); shader->specular_intensity = glGetUniformLocation(shader->id, "material.specular_intensity");
shader->point_light_count = glGetUniformLocation(shader->id, "point_light_count"); shader->point_light_count = glGetUniformLocation(shader->id, "point_light_count");
shader->spot_light_count = glGetUniformLocation(shader->id, "spot_light_count");
// Point lights
for (size_t i=0; i<MAX_POINT_LIGHTS; i++) { for (size_t i=0; i<MAX_POINT_LIGHTS; i++) {
char location_buffer[100] = {"\0"}; char location_buffer[100] = {"\0"};
// Common // Common
snprintf(location_buffer, sizeof(location_buffer), "point_lights[%zu].base.color", i); snprintf(location_buffer, sizeof(location_buffer), "point_lights[%zu].light.color", i);
shader->point_lights[i].color = glGetUniformLocation(shader->id, location_buffer); shader->point_lights[i].color = glGetUniformLocation(shader->id, location_buffer);
snprintf(location_buffer, sizeof(location_buffer), "point_lights[%zu].base.ambient_intensity", i); snprintf(location_buffer, sizeof(location_buffer), "point_lights[%zu].light.ambient_intensity", i);
shader->point_lights[i].ambient_intensity = glGetUniformLocation(shader->id, location_buffer); shader->point_lights[i].ambient_intensity = glGetUniformLocation(shader->id, location_buffer);
snprintf(location_buffer, sizeof(location_buffer), "point_lights[%zu].base.diffuse_intensity", i); snprintf(location_buffer, sizeof(location_buffer), "point_lights[%zu].light.diffuse_intensity", i);
shader->point_lights[i].diffuse_intensity = glGetUniformLocation(shader->id, location_buffer); shader->point_lights[i].diffuse_intensity = glGetUniformLocation(shader->id, location_buffer);
snprintf(location_buffer, sizeof(location_buffer), "point_lights[%zu].position", i); snprintf(location_buffer, sizeof(location_buffer), "point_lights[%zu].position", i);
@ -91,6 +93,31 @@ bool create_shader(Shader *shader, const char *vertex_shader_path, const char *f
shader->point_lights[i].constant = glGetUniformLocation(shader->id, location_buffer); shader->point_lights[i].constant = glGetUniformLocation(shader->id, location_buffer);
} }
// Spot lights
for (size_t i=0; i<MAX_SPOT_LIGHTS; i++) {
char location_buffer[100] = {"\0"};
// Common
snprintf(location_buffer, sizeof(location_buffer), "spot_lights[%zu].point_light.light.color", i);
shader->spot_lights[i].color = glGetUniformLocation(shader->id, location_buffer);
snprintf(location_buffer, sizeof(location_buffer), "spot_lights[%zu].point_light.light.ambient_intensity", i);
shader->spot_lights[i].ambient_intensity = glGetUniformLocation(shader->id, location_buffer);
snprintf(location_buffer, sizeof(location_buffer), "spot_lights[%zu].point_light.light.diffuse_intensity", i);
shader->spot_lights[i].diffuse_intensity = glGetUniformLocation(shader->id, location_buffer);
snprintf(location_buffer, sizeof(location_buffer), "spot_lights[%zu].point_light.position", i);
shader->spot_lights[i].position = glGetUniformLocation(shader->id, location_buffer);
snprintf(location_buffer, sizeof(location_buffer), "spot_lights[%zu].point_light.constant", i);
shader->spot_lights[i].constant = glGetUniformLocation(shader->id, location_buffer);
snprintf(location_buffer, sizeof(location_buffer), "spot_lights[%zu].point_light.constant", i);
shader->spot_lights[i].constant = glGetUniformLocation(shader->id, location_buffer);
snprintf(location_buffer, sizeof(location_buffer), "spot_lights[%zu].direction", i);
shader->spot_lights[i].direction = glGetUniformLocation(shader->id, location_buffer);
snprintf(location_buffer, sizeof(location_buffer), "spot_lights[%zu].edge", i);
shader->spot_lights[i].edge = glGetUniformLocation(shader->id, location_buffer);
}
return true; return true;
} }
@ -156,3 +183,23 @@ void use_light(Shader *shader, Point_Light *point_lights, u32 point_light_count)
} }
} }
void use_light(Shader *shader, Spot_Light *spot_lights, u32 spot_light_count) {
if (spot_light_count > MAX_SPOT_LIGHTS) spot_light_count = MAX_SPOT_LIGHTS;
glUniform1i(shader->spot_light_count, spot_light_count);
for (size_t i = 0; i < spot_light_count; i++) {
glUniform3f(shader->spot_lights[i].color, spot_lights[i].color.x, spot_lights[i].color.y, spot_lights[i].color.z);
glUniform1f(shader->spot_lights[i].ambient_intensity, spot_lights[i].ambient_intensity);
glUniform1f(shader->spot_lights[i].diffuse_intensity, spot_lights[i].diffuse_intensity);
glUniform3f(shader->spot_lights[i].position, spot_lights[i].position.x, spot_lights[i].position.y, spot_lights[i].position.z);
glUniform1f(shader->spot_lights[i].constant, spot_lights[i].constant);
glUniform1f(shader->spot_lights[i].linear, spot_lights[i].linear);
glUniform1f(shader->spot_lights[i].exponent, spot_lights[i].exponent);
glUniform3f(shader->spot_lights[i].direction, spot_lights[i].direction.x, spot_lights[i].direction.y, spot_lights[i].direction.z);
glUniform1f(shader->spot_lights[i].edge, spot_lights[i].processed_edge);
}
}

View File

@ -45,6 +45,22 @@ struct Shader {
u32 exponent; u32 exponent;
} point_lights[MAX_POINT_LIGHTS]; } point_lights[MAX_POINT_LIGHTS];
u32 spot_light_count = 0;
struct {
u32 color;
u32 ambient_intensity;
u32 diffuse_intensity;
u32 position;
u32 constant;
u32 linear;
u32 exponent;
u32 direction;
u32 edge;
} spot_lights[MAX_SPOT_LIGHTS];
~Shader(); ~Shader();
}; };
@ -52,6 +68,6 @@ bool create_shader(Shader *shader, const char *vertex_shader_path, const char *f
bool add_shader(Shader *shader, const char *shader_code, Shader_Type type); bool add_shader(Shader *shader, const char *shader_code, Shader_Type type);
void clear_shader(Shader *shader); void clear_shader(Shader *shader);
// Some of these should be u32
void use_light(Shader *shader, Directional_Light *light); void use_light(Shader *shader, Directional_Light *light);
void use_light(Shader *shader, Point_Light *light, u32 point_light_count); void use_light(Shader *shader, Point_Light *light, u32 point_light_count);
void use_light(Shader *shader, Spot_Light *light, u32 point_light_count);