From c202e47d239a09e7de28f705bd694de643668025 Mon Sep 17 00:00:00 2001 From: Erik Cowley Date: Mon, 9 Oct 2023 19:33:09 -0400 Subject: [PATCH] Implement flashlight --- fragmentshader.txt | 53 +++++--- snowland.cpp | 293 ++++++++++++++++++++++++++++++--------------- 2 files changed, 233 insertions(+), 113 deletions(-) diff --git a/fragmentshader.txt b/fragmentshader.txt index 006bb98..fad8a30 100644 --- a/fragmentshader.txt +++ b/fragmentshader.txt @@ -1,38 +1,57 @@ #version 460 core out vec4 FragColor; -in vec3 Normal; +struct Material { + //sampler2D diffuse; + //sampler2D specular; + float shininess; + vec3 color; +}; + +struct Light { + vec3 position; + vec3 direction; + float largecutoff; + float smallcutoff; + + vec3 ambient; + vec3 diffuse; + vec3 specular; +}; + in vec3 FragPos; +in vec3 Normal; uniform vec3 viewPos; -uniform vec3 lightColor; -uniform vec3 objectColor; +uniform Material material; +uniform Light light; void main() { - // ambient - float ambientStrength = 0.1; - vec3 ambient = ambientStrength * lightColor; + vec3 lightDir = normalize(light.position - FragPos); - vec3 vecDist = viewPos - FragPos; - vec3 normDist = normalize(vecDist); + // check if lighting is inside the spotlight cone + float theta = dot(lightDir, normalize(-light.direction)); + float co = clamp((theta - light.largecutoff) / (light.smallcutoff - light.largecutoff), 0.0, 1.0); // diffuse vec3 norm = normalize(Normal); - vec3 lightDir = normDist; float diff = max(dot(norm, lightDir), 0.0); - vec3 diffuse = diff * lightColor; + vec3 diffuse = light.diffuse * diff * material.color * co; // specular - float specularStrength = 0.5; - vec3 viewDir = normDist; + vec3 viewDir = normalize(viewPos - FragPos); vec3 reflectDir = reflect(-lightDir, norm); - float spec = pow(max(dot(viewDir, reflectDir), 0.0), 8); - vec3 specular = specularStrength * spec * lightColor; + float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess); + vec3 specular = light.specular * spec * material.color * co; - float dist = distance(viewPos, FragPos); - float att = 1.0 / (1.0 + 0.1*dist + 0.01*dist*dist); + // attenuation + float distance = length(light.position - FragPos); + float atten = 1.0 / (1.0 + 0.1 * distance + 0.01 * (distance * distance)); - vec3 result = (ambient + diffuse + specular) * att * objectColor; + diffuse *= atten; + specular *= atten; + + vec3 result = light.ambient + diffuse + specular; FragColor = vec4(result, 1.0); } diff --git a/snowland.cpp b/snowland.cpp index d8aa6df..ed72014 100644 --- a/snowland.cpp +++ b/snowland.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include "collisions.h" @@ -20,6 +21,7 @@ void framebuffer_size_callback(GLFWwindow* window, int width, int height); void mouse_callback(GLFWwindow* window, double xpos, double ypos); void scroll_callback(GLFWwindow* window, double xoffset, double yoffset); void processInput(GLFWwindow *window); +int createShader(const char *filename, int shadertype); // settings const unsigned int WINDOWWIDTH = 1600; @@ -27,7 +29,7 @@ const unsigned int WINDOWHEIGHT = 900; // camera glm::vec3 player_pos = glm::vec3(0.0f, 0.0f, 3.0f); -glm::vec3 camera_front = glm::vec3(0.0f, 0.0f, -1.0f); +glm::vec3 camera_front = glm::vec3(1.0f, 0.0f, 0.0f); glm::vec3 camera_up = glm::vec3(0.0f, 1.0f, 0.0f); bool first_mouse = true; @@ -46,14 +48,24 @@ const char *projectionC = "projection"; const char *viewC = "view"; const char *modelC = "model"; +const char *objectcolorC = "objectcolor"; const char *viewposC = "viewPos"; -const char *lightcolorC = "lightColor"; -const char *objectcolorC = "objectColor"; -const char *lightstrengthC = "lightStrength"; +const char *shininessC = "material.shininess"; +const char *colorC = "material.color"; +const char *lightposC = "light.position"; +const char *directionC = "light.direction"; +const char *largecutoffC = "light.largecutoff"; +const char *smallcutoffC = "light.smallcutoff"; +const char *ambientC = "light.ambient"; +const char *diffuseC = "light.diffuse"; +const char *specularC = "light.specular"; + int num_walls; float *wall_vertices; +int trailmax = 1800; + glm::vec3 getNormalFromIndex(int ix) { return glm::vec3( wall_vertices[ix * 6 * 6 + 3], @@ -115,6 +127,34 @@ glm::vec3 checkIntersection(glm::vec3 movement) { int main() { + + int success; + + FILE *fp = fopen("maze.txt", "r"); + float fakeyaw; + fscanf(fp, "%f %f %f %f\n", &player_pos.x, &player_pos.y, &player_pos.z, &fakeyaw); + fscanf(fp, "%d\n", &num_walls); + // num surfaces * 6 (vertices per point) * 6 (floats per point) + int num_wall_vertices = num_walls * 6 * 6; + wall_vertices = (float *)calloc(sizeof(float), num_wall_vertices); + // read walls + for (int i = 0; i < num_walls; i++) { + for (int j = 0; j < 6; j++) { + int vix = i*6*6 + j*6; + fscanf( + fp, + "%f %f %f %f %f %f\n", + &wall_vertices[vix], + &wall_vertices[vix+1], + &wall_vertices[vix+2], + &wall_vertices[vix+3], + &wall_vertices[vix+4], + &wall_vertices[vix+5] + ); + } + fscanf(fp, "\n"); + } + glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); @@ -142,60 +182,12 @@ int main() glEnable(GL_DEPTH_TEST); - FILE* fp = fopen("vertexshader.txt", "r"); - if (!fp) { - printf("failed to open vertex shader!\n"); + int vertex_shader = createShader("vertexshader.txt", GL_VERTEX_SHADER); + if (vertex_shader < 0) { return -1; } - fseek(fp, 0L, SEEK_END); - unsigned int vertex_sz = ftell(fp); - rewind(fp); - - char *vertex_buffer = (char *)calloc(sizeof(char), vertex_sz + 1); - if (fread(vertex_buffer, vertex_sz, 1, fp) != 1) { - printf("failed to read vertex shader!\n"); - return -1; - } - fclose(fp); - - int vertex_shader = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(vertex_shader, 1, &vertex_buffer, NULL); - glCompileShader(vertex_shader); - int success; - glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success); - if (!success) { - char infoLog[1024]; - glGetShaderInfoLog(vertex_shader, 1024, NULL, infoLog); - printf("Vertex shader compile error: %s\n", infoLog); - glfwTerminate(); - return -1; - } - - fp = fopen("fragmentshader.txt", "r"); - if (!fp) { - printf("failed to open fragment shader!\n"); - return -1; - } - fseek(fp, 0L, SEEK_END); - unsigned int fragment_sz = ftell(fp); - rewind(fp); - - char *fragment_buffer = (char *)calloc(sizeof(char), fragment_sz + 1); - if (fread(fragment_buffer, fragment_sz, 1, fp) != 1) { - printf("failed to read fragment shader!\n"); - return -1; - } - fclose(fp); - - int fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(fragment_shader, 1, &fragment_buffer, NULL); - glCompileShader(fragment_shader); - glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success); - if (!success) { - char infoLog[1024]; - glGetShaderInfoLog(fragment_shader, 1024, NULL, infoLog); - printf("Fragment shader compile error: %s\n", infoLog); - glfwTerminate(); + int fragment_shader = createShader("fragmentshader.txt", GL_FRAGMENT_SHADER); + if (fragment_shader < 0) { return -1; } @@ -228,32 +220,6 @@ int main() glDeleteShader(vertex_shader); glDeleteShader(fragment_shader); - free(vertex_buffer); - free(fragment_buffer); - - fp = fopen("maze.txt", "r"); - fscanf(fp, "%f %f %f %f\n", &player_pos.x, &player_pos.y, &player_pos.z, &yaw); - fscanf(fp, "%d\n", &num_walls); - // num surfaces * 6 (vertices per point) * 6 (floats per point) - int num_wall_vertices = num_walls * 6 * 6; - wall_vertices = (float *)calloc(sizeof(float), num_wall_vertices); - // read walls - for (int i = 0; i < num_walls; i++) { - for (int j = 0; j < 6; j++) { - int vix = i*6*6 + j*6; - fscanf( - fp, - "%f %f %f %f %f %f\n", - &wall_vertices[vix], - &wall_vertices[vix+1], - &wall_vertices[vix+2], - &wall_vertices[vix+3], - &wall_vertices[vix+4], - &wall_vertices[vix+5] - ); - } - fscanf(fp, "\n"); - } // read floor float *floor_vertices = (float *)calloc(sizeof(float), 6*6); for (int j = 0; j < 6; j++) { @@ -307,7 +273,72 @@ int main() glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float))); glEnableVertexAttribArray(1); + // do stuff for trail + float trail_vertices[] = { + 0.25f, 0.0f, 0.0f, + -0.25f, 0.0f, 0.5f, + -0.25f, 0.0f, -0.5f, + + -0.25f, 0.0f, 0.1f, + -0.25f, 0.0f, -0.1f, + -0.75f, 0.0f, 0.1f, + + -0.75f, 0.0f, 0.1f, + -0.75f, 0.0f, -0.1f, + -0.25f, 0.0f, -0.1f, + }; + + unsigned int trailVBO, trailVAO; + glGenVertexArrays(1, &trailVAO); + glGenBuffers(1, &trailVBO); + + glBindVertexArray(trailVAO); + + glBindBuffer(GL_ARRAY_BUFFER, trailVBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * 3 * 3, trail_vertices, GL_STATIC_DRAW); + + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0); + glEnableVertexAttribArray(0); + + int trail_shader = createShader("trailshader.txt", GL_VERTEX_SHADER); + if (trail_shader < 0) { + return -1; + } + int trailfrag_shader = createShader("trailfragshader.txt", GL_FRAGMENT_SHADER); + if (trailfrag_shader < 0) { + return -1; + } + + int trail_program = glCreateProgram(); + glAttachShader(trail_program, trail_shader); + glAttachShader(trail_program, trailfrag_shader); + glLinkProgram(trail_program); + glGetProgramiv(trail_program, GL_LINK_STATUS, &success); + if (!success) { + char infoLog[1024]; + glGetProgramInfoLog(wall_program, 1024, NULL, infoLog); + printf("Shader trail_program link error: %s\n", infoLog); + glfwTerminate(); + return -1; + } + + glm::vec3 *trail_positions = (glm::vec3 *)calloc(sizeof(glm::vec3), trailmax); + float *trail_angles = (float *)calloc(sizeof(float), trailmax); + int trail_ix = 0; + int trail_sz = 0; + int time_sec = 0, num_frames = 0; + glm::vec3 wall_color = glm::vec3(0.61f, 0.6f, 0.59f); + float wall_shininess = 6.5; + glm::vec3 floor_color = glm::vec3(0.11f, 0.1f, 0.09f); + float floor_shininess = 3.25; + glm::vec3 ambient = glm::vec3(0.007f, 0.006f, 0.005f); + glm::vec3 diffuse = glm::vec3(0.41f, 0.40f, 0.39f); + glm::vec3 specular = glm::vec3(0.11f, 0.10f, 0.09f); + + float largecutoff = glm::cos(glm::radians(30.0f)); + float smallcutoff = glm::cos(glm::radians(7.5f)); + while (!glfwWindowShouldClose(window)) { float current_frame = static_cast(glfwGetTime()); @@ -316,6 +347,15 @@ int main() printf("FPS: %d\n", num_frames); time_sec = current_frameI; num_frames = 0; + trail_positions[trail_ix].x = player_pos.x; + trail_positions[trail_ix].y = 6.5; + trail_positions[trail_ix].z = player_pos.z; + trail_angles[trail_ix] = yaw; + printf("Recorded trail %d: (%f, %f, %f) %f\n", trail_ix, trail_positions[trail_ix].x, trail_positions[trail_ix].y, trail_positions[trail_ix].z, yaw); + trail_ix = (trail_ix + 1) % trailmax; + if (trail_sz < trailmax) { + trail_sz++; + } } else { num_frames++; } @@ -335,17 +375,21 @@ int main() glm::mat4 view = glm::lookAt(player_pos, player_pos + camera_front, camera_up); glUniformMatrix4fv(glGetUniformLocation(wall_program, viewC), 1, GL_FALSE, &view[0][0]); - glm::vec3 wall_color = glm::vec3(0.61f, 0.6f, 0.59f); - glUniform3fv(glGetUniformLocation(wall_program, objectcolorC), 1, &wall_color[0]); - - glm::vec3 light_color = glm::vec3(1.0f, 1.0f, 1.0f); - glUniform3fv(glGetUniformLocation(wall_program, lightcolorC), 1, &light_color[0]); - - glUniform3fv(glGetUniformLocation(wall_program, viewposC), 1, &player_pos[0]); - glm::mat4 model = glm::mat4(1.0f); glUniformMatrix4fv(glGetUniformLocation(wall_program, modelC), 1, GL_FALSE, &model[0][0]); + // fragment requirements + glUniform3fv(glGetUniformLocation(wall_program, viewposC), 1, &player_pos[0]); + glUniform1f(glGetUniformLocation(wall_program, shininessC), wall_shininess); + glUniform3fv(glGetUniformLocation(wall_program, colorC), 1, &wall_color[0]); + glUniform3fv(glGetUniformLocation(wall_program, lightposC), 1, &player_pos[0]); + glUniform3fv(glGetUniformLocation(wall_program, directionC), 1, &camera_front[0]); + glUniform1f(glGetUniformLocation(wall_program, largecutoffC), largecutoff); + glUniform1f(glGetUniformLocation(wall_program, smallcutoffC), smallcutoff); + glUniform3fv(glGetUniformLocation(wall_program, ambientC), 1, &ambient[0]); + glUniform3fv(glGetUniformLocation(wall_program, diffuseC), 1, &diffuse[0]); + glUniform3fv(glGetUniformLocation(wall_program, specularC), 1, &specular[0]); + glBindVertexArray(wallsVAO); glDrawArrays(GL_TRIANGLES, 0, num_wall_vertices); @@ -356,17 +400,41 @@ int main() glUniformMatrix4fv(glGetUniformLocation(floor_program, modelC), 1, GL_FALSE, &model[0][0]); glUniform3fv(glGetUniformLocation(floor_program, viewposC), 1, &player_pos[0]); - glm::vec3 floor_color = glm::vec3(0.11f, 0.1f, 0.09f); - glUniform3fv(glGetUniformLocation(floor_program, objectcolorC), 1, &floor_color[0]); - - glm::vec3 floor_light_color = glm::vec3(1.0f, 1.0f, 1.0f); - glUniform3fv(glGetUniformLocation(floor_program, lightcolorC), 1, &floor_light_color[0]); + // fragment requirements + glUniform3fv(glGetUniformLocation(floor_program, viewposC), 1, &player_pos[0]); + glUniform1f(glGetUniformLocation(floor_program, shininessC), floor_shininess); + glUniform3fv(glGetUniformLocation(floor_program, colorC), 1, &floor_color[0]); + glUniform3fv(glGetUniformLocation(floor_program, lightposC), 1, &player_pos[0]); + glUniform3fv(glGetUniformLocation(floor_program, directionC), 1, &camera_front[0]); + glUniform1f(glGetUniformLocation(floor_program, largecutoffC), largecutoff); + glUniform1f(glGetUniformLocation(floor_program, smallcutoffC), smallcutoff); + glUniform3fv(glGetUniformLocation(floor_program, ambientC), 1, &ambient[0]); + glUniform3fv(glGetUniformLocation(floor_program, diffuseC), 1, &diffuse[0]); + glUniform3fv(glGetUniformLocation(floor_program, specularC), 1, &specular[0]); glBindVertexArray(floorVAO); glDrawArrays(GL_TRIANGLES, 0, 6 * 6 * 1); + glUseProgram(trail_program); + + glUniformMatrix4fv(glGetUniformLocation(trail_program, projectionC), 1, GL_FALSE, &projection[0][0]); + glUniformMatrix4fv(glGetUniformLocation(trail_program, viewC), 1, GL_FALSE, &view[0][0]); + glm::vec3 trail_color = glm::vec3(1.0f, 0.0f, 0.0f); + glUniform3fv(glGetUniformLocation(trail_program, objectcolorC), 1, &trail_color[0]); + + for (int i = 0; i < trail_sz; i++) { + glm::mat4 model = glm::mat4(1.0f); + model = glm::translate(model, trail_positions[i]); + model = glm::rotate(model, glm::radians(trail_angles[i]), glm::vec3(0.0f, -1.0f, 0.0f)); + glUniformMatrix4fv(glGetUniformLocation(trail_program, modelC), 1, GL_FALSE, &model[0][0]); + glBindVertexArray(trailVAO); + + glDrawArrays(GL_TRIANGLES, 0, 3 * 3 * 3); + } + glfwSwapBuffers(window); glfwPollEvents(); + } glDeleteVertexArrays(1, &wallsVAO); @@ -392,7 +460,7 @@ void processInput(GLFWwindow *window) movement = glm::vec3(-camera_front.x, 0.0, -camera_front.z); } else if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) { glm::vec3 right = glm::cross(camera_front, camera_up); - movement = glm::vec3(right.x, 0.0, right.z); + movement = glm::vec3(-right.x, 0.0, -right.z); } else if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) { glm::vec3 right = glm::cross(camera_front, camera_up); movement = glm::vec3(right.x, 0.0, right.z); @@ -453,3 +521,36 @@ void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) if (fov > 90.0f) fov = 90.0f; } + +int createShader(const char *filename, int shadertype) { + FILE* fp = fopen(filename, "r"); + if (!fp) { + printf("failed to open vertex shader!\n"); + return -1; + } + fseek(fp, 0L, SEEK_END); + unsigned int buffer_sz = ftell(fp); + rewind(fp); + + char *buffer = (char *)calloc(sizeof(char), buffer_sz + 1); + if (fread(buffer, buffer_sz, 1, fp) != 1) { + printf("failed to read vertex shader!\n"); + return -1; + } + fclose(fp); + + int shader = glCreateShader(shadertype); + glShaderSource(shader, 1, &buffer, NULL); + free(buffer); + glCompileShader(shader); + int success; + glGetShaderiv(shader, GL_COMPILE_STATUS, &success); + if (!success) { + char info_log[1024]; + glGetShaderInfoLog(shader, 1024, NULL, info_log); + printf("Shader compile error for %s: %s\n", filename, info_log); + glfwTerminate(); + return -1; + } + return shader; +}