diff --git a/data/default.fs b/data/default.fs index 39afb28..7d87f03 100644 --- a/data/default.fs +++ b/data/default.fs @@ -1,11 +1,26 @@ #version 330 core in vec3 fragmentColor; +in vec3 fragNormal; +in vec3 fragVertex; + +uniform mat4 model; +uniform vec3 light_position; +uniform mat3 normal_matrix; out vec3 color; void main() { - color = fragmentColor; + // https://www.tomdalling.com/blog/modern-opengl/06-diffuse-point-lighting + vec3 normal = normalize(normal_matrix * fragNormal); + + vec3 fragPosition = vec3(model * vec4(fragVertex, 1)); + vec3 surfaceToLight = light_position - fragPosition; + + float brightness = dot(normal, surfaceToLight) / (length(surfaceToLight) * length(normal)); + brightness = clamp(brightness, 0, 1); + + color = brightness * fragmentColor; } diff --git a/data/default.vs b/data/default.vs index b30ca0e..0bbe9a8 100644 --- a/data/default.vs +++ b/data/default.vs @@ -1,9 +1,12 @@ #version 330 core -in vec3 vertexPosition_modelspace; -in vec3 vertexColor; +layout (location = 0) in vec3 vertexPosition_modelspace; +layout (location = 1) in vec3 vertexColor; +layout (location = 2) in vec3 normal; out vec3 fragmentColor; +out vec3 fragNormal; +out vec3 fragVertex; uniform mat4 model; uniform mat4 view; @@ -11,7 +14,9 @@ uniform mat4 projection; void main() { - gl_Position = projection * view * model * vec4(vertexPosition_modelspace, 1); fragmentColor = vertexColor; + fragNormal = normal; + fragVertex = vertexPosition_modelspace; + gl_Position = projection * view * model * vec4(vertexPosition_modelspace, 1); } diff --git a/src/gooey.cpp b/src/gooey.cpp index cd2fa51..debe46c 100644 --- a/src/gooey.cpp +++ b/src/gooey.cpp @@ -79,8 +79,8 @@ renderGooey(SDL_Handles &handles, HexDrawMode &mode, bool &is_debug, if (ImGui::CollapsingHeader("Camera Position")) { ImGui::Text("x: %f", camera_pos.x); - ImGui::Text("x: %f", camera_pos.y); - ImGui::Text("x: %f", camera_pos.z); + ImGui::Text("y: %f", camera_pos.y); + ImGui::Text("z: %f", camera_pos.z); } #if 0 diff --git a/src/hexgame.cpp b/src/hexgame.cpp index 92f57a4..9592f02 100644 --- a/src/hexgame.cpp +++ b/src/hexgame.cpp @@ -1,11 +1,15 @@ //----------------------------------------------------------------------------- // TODO: // - lighting +// - add light struct +// - pass all lights to render groups/shaders every frame +// - need to give hexagons vertex normals (can then get rid of rgDraw()) +// - maybe use more than one model in a scene // - map generation // - pathfinding // - assimp animation // - update imgui to v1.62 -- requires changes to example api -// - replace aixlog with custom logging iostream +// - replace aixlog with custom logging iostream? // - fix vector normalization in renderer.cpp when moving in 2 directions // - add prefix to interface function names for eg) gooey.h, renderer.h // - test build on windows / update vs project files @@ -565,8 +569,10 @@ int main(int argc, char* argv[]) g->is_moveforward, g->is_movebackward); rollCamera(g->is_rotateCW, g->is_rotateCCW); renderFrame(g->hex_array, g_render_state->entities, g_render_state->entity_count); +#if 0 if (r->is_debug_draw && g->draw_mode == CONE_FILL) renderDebug(g_polygon_select_vertices); +#endif renderGooey(handles, g->draw_mode, r->is_debug_draw, g->start_hex, g->current_hex, g->is_selecting, getCameraPosition()); SDL_GL_SwapWindow(handles.window); diff --git a/src/hexgame.h b/src/hexgame.h index bba06f4..ab44cc7 100644 --- a/src/hexgame.h +++ b/src/hexgame.h @@ -9,7 +9,7 @@ #include #endif -#include // vec3 +#include #include "hexlib.h" #include "util.h" diff --git a/src/mesh.h b/src/mesh.h index 78aa1b0..ab0a629 100644 --- a/src/mesh.h +++ b/src/mesh.h @@ -5,6 +5,7 @@ #pragma once +#include struct meMeshInfo { diff --git a/src/render_group.cpp b/src/render_group.cpp index 93d6937..dca5c7c 100644 --- a/src/render_group.cpp +++ b/src/render_group.cpp @@ -43,6 +43,7 @@ rgInitShaderProgram(gl_render_group* rg, const char * vertex_code, const char * rg->model_matrix_id = glGetUniformLocation(rg->program_id, model_name); rg->view_matrix_id = glGetUniformLocation(rg->program_id, view_name); rg->projection_matrix_id = glGetUniformLocation(rg->program_id, projection_name); + rg->normal_matrix_id = glGetUniformLocation(rg->program_id, "normal_matrix"); glDetachShader(rg->program_id, vertex_shader_id); glDetachShader(rg->program_id, fragment_shader_id); @@ -73,6 +74,7 @@ rgInitShaderProgram(gl_render_group* rg, const char * vertex_code, const char * void rgInitGLBufferObject(gl_buffer* buf_obj, uint len, GLenum usage, GLenum target, GLfloat data[]) { + // TODO: why not just assing the pointer to the render group instead of copying here? buf_obj->buffer_len = len; buf_obj->buffer = (GLfloat*) std::calloc(len, sizeof(GLfloat)); @@ -201,23 +203,31 @@ rgInitEntity(gl_render_group* rg, Entity* e) void rgDraw(gl_render_group* rg, GLenum draw_mode, glm::mat4 model_matrix, - glm::mat4 view_matrix, glm::mat4 projection_matrix, bool update_vertex_data) + glm::mat4 view_matrix, glm::mat4 projection_matrix, + glm::vec3 light_position, GLuint light_id) { glUseProgram(rg->program_id); glUniformMatrix4fv(rg->model_matrix_id, 1, GL_FALSE, &model_matrix[0][0]); glUniformMatrix4fv(rg->view_matrix_id, 1, GL_FALSE, &view_matrix[0][0]); glUniformMatrix4fv(rg->projection_matrix_id, 1, GL_FALSE, &projection_matrix[0][0]); + // TODO: testing lighting + glUniform3f(light_id, light_position.x, light_position.y, light_position.z); + glm::mat3 normal_matrix = glm::transpose(glm::inverse(glm::mat3(model_matrix))); + glUniformMatrix3fv(rg->normal_matrix_id, 1, GL_FALSE, &normal_matrix[0][0]); + // 1st attribute buffer : vertices glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, rg->vertex_buffer.buffer_id); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0); +#if 0 if (update_vertex_data) { glBufferSubData(GL_ARRAY_BUFFER, 0, rg->vertex_buffer.buffer_len * sizeof(GLfloat), rg->vertex_buffer.buffer); } +#endif // 2nd attribute buffer : colors if (rg->color_buffer.buffer) @@ -230,6 +240,14 @@ rgDraw(gl_render_group* rg, GLenum draw_mode, glm::mat4 model_matrix, glBufferSubData(GL_ARRAY_BUFFER, 0, rg->color_buffer.buffer_len * sizeof(GLfloat), rg->color_buffer.buffer); } + + // 3rd attribute buffer: normals + if (rg->use_normals) { + glEnableVertexAttribArray(2); + glBindBuffer(GL_ARRAY_BUFFER, rg->vertex_normals.buffer_id); + glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0); + } + // draw glDrawArrays(draw_mode, 0, rg->vertex_buffer.buffer_len / 3); @@ -241,12 +259,18 @@ rgDraw(gl_render_group* rg, GLenum draw_mode, glm::mat4 model_matrix, void rgDrawIndexed(gl_render_group* rg, GLenum draw_mode, glm::mat4 model_matrix, - glm::mat4 view_matrix, glm::mat4 projection_matrix, bool update_vertex_data) + glm::mat4 view_matrix, glm::mat4 projection_matrix, + glm::vec3 light_position, GLuint light_id) { glUseProgram(rg->program_id); glUniformMatrix4fv(rg->model_matrix_id, 1, GL_FALSE, &model_matrix[0][0]); glUniformMatrix4fv(rg->view_matrix_id, 1, GL_FALSE, &view_matrix[0][0]); glUniformMatrix4fv(rg->projection_matrix_id, 1, GL_FALSE, &projection_matrix[0][0]); + + // TODO: testing lighting + glUniform3f(light_id, light_position.x, light_position.y, light_position.z); + glm::mat3 normal_matrix = glm::transpose(glm::inverse(glm::mat3(model_matrix))); + glUniformMatrix3fv(rg->normal_matrix_id, 1, GL_FALSE, &normal_matrix[0][0]); // 1st attribute buffer : vertices glEnableVertexAttribArray(0); @@ -300,6 +324,8 @@ rgFree(gl_render_group* rg) rg->index_buffer.indices = nullptr; } + // TODO: free vertex_normals here, and switch to using utilFree function + std::free(rg); rg = nullptr; } diff --git a/src/render_group.h b/src/render_group.h index c66eead..fda7b02 100644 --- a/src/render_group.h +++ b/src/render_group.h @@ -28,6 +28,7 @@ struct gl_render_group GLuint model_matrix_id = 0; GLuint view_matrix_id = 0; GLuint projection_matrix_id = 0; + GLuint normal_matrix_id = 0; GLuint vertex_array_id = 0; bool use_normals = false; }; @@ -50,10 +51,12 @@ bool rgInitEntity(gl_render_group* rg, Entity* e); void rgFillColorBuffer(GLfloat buf[], int len, std::vector* hexes); void rgDraw(gl_render_group* rg, GLenum draw_mode, glm::mat4 model_matrix, - glm::mat4 view_matrix, glm::mat4 projection_matrix, bool update_vertex_data = false); + glm::mat4 view_matrix, glm::mat4 projection_matrix, + glm::vec3 light_position, GLuint light_id); void rgDrawIndexed(gl_render_group* rg, GLenum draw_mode, glm::mat4 model_matrix, - glm::mat4 view_matrix, glm::mat4 projection_matrix, bool update_vertex_data = false); + glm::mat4 view_matrix, glm::mat4 projection_matrix, + glm::vec3 light_position, GLuint light_id); void rgFree(gl_render_group* rg); diff --git a/src/renderer.cpp b/src/renderer.cpp index 4e198d8..a5b4108 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -90,6 +90,10 @@ gl_render_group* g_entity_render_group = rgCreateGroup(); camera g_camera; +// TODO: testing lighting +renPointLight g_test_light; + + bool addTexture(SDL_Handles &handles, const char * path) { @@ -375,7 +379,7 @@ createScene(std::vector* hexes, Entity* entities, uint32 entity_count) int hex_count = (int) hexes->size(); // 6 triangles * 3 vertices per triangle * 3 floats per vertex = 54 int vbuf_len = hex_count * 6 * 3 * 3; - + // TODO: surely there's a way to use indexed drawing for line vertices eg) line_loop // and still use one buffer for multiple shapes/paths gldrawarraysintanced?, gldrawelements? // https://gamedev.stackexchange.com/questions/104310/opengl-4-5-primitive-restart-vs-base-index @@ -389,19 +393,31 @@ createScene(std::vector* hexes, Entity* entities, uint32 entity_count) for (int i = 0; i < hex_count; i++) fillTriangleBufferFromHex(vbuf, 54 * i, (*hexes)[i]); - + rgInitGLBufferObject(&g_filled_hex_render_group->vertex_buffer, vbuf_len, GL_DYNAMIC_DRAW, GL_ARRAY_BUFFER, vbuf); // color data for hex vertices - + rgFillColorBuffer(cbuf, vbuf_len, hexes); rgInitGLBufferObject(&g_filled_hex_render_group->color_buffer, vbuf_len, GL_DYNAMIC_DRAW, GL_ARRAY_BUFFER, cbuf); - // hex line vertex data + // cheat at vertex normals since all hexes lay flat on z-axis + GLfloat* normal_buf = (GLfloat*) std::calloc(vbuf_len, sizeof(GLfloat)); + for (int i = 0; i < vbuf_len; i += 3) { + normal_buf[i] = 0; + normal_buf[i + 1] = 0; + normal_buf[i + 2] = 1; + } + rgInitGLBufferObject(&g_filled_hex_render_group->vertex_normals, vbuf_len, + GL_STATIC_DRAW, GL_ARRAY_BUFFER, normal_buf); + g_filled_hex_render_group->use_normals = true; + + // hex line vertex data + fillHexLineBuffer(line_buf, line_buf_len, hexes); rgInitGLBufferObject(&g_hex_line_render_group->vertex_buffer, line_buf_len, GL_STATIC_DRAW, GL_ARRAY_BUFFER, line_buf); @@ -412,7 +428,8 @@ createScene(std::vector* hexes, Entity* entities, uint32 entity_count) std::free(vbuf); std::free(cbuf); std::free(line_buf); - vbuf = cbuf = line_buf = nullptr; + std::free(normal_buf); + vbuf = cbuf = line_buf = normal_buf = nullptr; // debug draw vertexes int len = 4 * 3; // 4 vertices, 3 floats per vertex @@ -421,9 +438,20 @@ createScene(std::vector* hexes, Entity* entities, uint32 entity_count) // entities + // TODO: wtf, I only accounted for 1 entity in the entity render group :( + // probably need one render_group struct for each entity for (uint i = 0; i < entity_count; i++) rgInitEntity(g_entity_render_group, &entities[i]); + // lights + // TODO: load light properties from scene/level files + + g_test_light.light_ID = glGetUniformLocation(g_entity_render_group->program_id, "light_position"); + g_test_light.position = glm::vec3(640, 500, 400); // above center of hexgrid + g_test_light.direction = glm::vec3(0, 0, 0) - g_test_light.position; // back towards test entity + g_test_light.color = glm::vec3(1.f, 1.f, 1.f); + g_test_light.intensity = 1.f; + return true; } @@ -527,21 +555,26 @@ renderFrame(std::vector *hexes, Entity* entities, uint32 entity_count) // get new colors every frame gl_render_group* rg = g_filled_hex_render_group; rgFillColorBuffer(rg->color_buffer.buffer, rg->color_buffer.buffer_len, hexes); - rgDraw(rg, GL_TRIANGLES, m_model, m_view, m_projection); + rgDraw(rg, GL_TRIANGLES, m_model, m_view, m_projection, + g_test_light.position, g_test_light.light_ID); // hex lines - rgDraw(g_hex_line_render_group, GL_LINES, m_model, m_view, m_projection); + //rgDraw(g_hex_line_render_group, GL_LINES, m_model, m_view, m_projection); + // TODO: update and send array of lights (pos, dir, color, intesity to shaders + // every frame through rgDrawIndexed() // entities for (uint i = 0; i < entity_count; i++) { rgDrawIndexed( g_entity_render_group, GL_TRIANGLES, - entities[i].mesh->model_transform, m_view, m_projection + entities[i].mesh->model_transform, m_view, m_projection, + g_test_light.position, g_test_light.light_ID ); } } +#if 0 void renderDebug(std::vector &vertices) { @@ -561,6 +594,7 @@ renderDebug(std::vector &vertices) rgDraw(rg, GL_LINE_LOOP, g_scene_matrices.model, g_scene_matrices.view, g_scene_matrices.projection, true); } +#endif void freeBuffers() diff --git a/src/renderer.h b/src/renderer.h index 3cea771..618ad1c 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -3,9 +3,21 @@ #include +#include + #include "util.h" #include "hexgame.h" +struct renPointLight +{ + glm::vec3 position; + glm::vec3 direction; + glm::vec3 color; + float intensity; + + uint light_ID; +}; + bool initRenderer(SDL_Handles &handles, v2i vpDims); bool addTexture(SDL_Handles &handles, const char * path); v2f getUnprojectedCoords(int32 x, int32 y, int32 vp_width, int32 vp_height); @@ -15,6 +27,6 @@ void moveCamera(bool up, bool left, bool down, bool right, bool forward, bool ba void rollCamera(bool CW, bool CCW); void rotateCamera(int32 xrel, int32 yrel); void renderFrame(std::vector *hexes, Entity* entities, uint32 entity_count); -void renderDebug(std::vector &vertices); +//void renderDebug(std::vector &vertices); void freeBuffers(); diff --git a/src/util.cpp b/src/util.cpp index 2a848d5..c23aeae 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -29,7 +29,7 @@ utilDumpTextFile(const char* filename) return buf; } -// TODO: search/replace other calls to stdd::free with this +// TODO: search/replace other calls to std::free with this void utilSafeFree(void* mem) {