From 9ab59b76c0ece5e261c0152af3f830f48532e103 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sat, 22 Feb 2020 08:55:48 +0100 Subject: Fix rendering of character --- README.md | 3 +- include/RenderBackend/OpenGL/ShaderFrame.hpp | 4 +- shaders/fragment_no_texture.frag | 7 ++ shaders/vertex_no_texture.vert | 11 ++ src/RenderBackend/OpenGL/ShaderFrame.cpp | 30 +++++- src/RenderBackend/OpenGL/Texture2D.cpp | 2 +- src/main.cpp | 147 ++++++++++++++++----------- src/model_loader/ObjModelLoader.cpp | 96 ++++++++++------- 8 files changed, 202 insertions(+), 98 deletions(-) create mode 100644 shaders/fragment_no_texture.frag create mode 100644 shaders/vertex_no_texture.vert diff --git a/README.md b/README.md index 2168a8a..d7dcf18 100644 --- a/README.md +++ b/README.md @@ -5,4 +5,5 @@ glm sibs (https://github.com/DEC05EBA/sibs) # TODO -Make use shader a no-op if already in use \ No newline at end of file +* Make use shader a no-op if already in use. +* Render vertices using glDrawElements instead of glDrawArrays. \ No newline at end of file diff --git a/include/RenderBackend/OpenGL/ShaderFrame.hpp b/include/RenderBackend/OpenGL/ShaderFrame.hpp index da0918e..01cec92 100644 --- a/include/RenderBackend/OpenGL/ShaderFrame.hpp +++ b/include/RenderBackend/OpenGL/ShaderFrame.hpp @@ -16,8 +16,8 @@ namespace amalgine { friend class ShaderProgram; public: ~ShaderFrame(); - ShaderFrame(ShaderFrame &&other) = default; - ShaderFrame& operator=(ShaderFrame &&other) = default; + ShaderFrame(ShaderFrame &&other); + ShaderFrame& operator=(ShaderFrame &&other); DeviceMemory* get_input_by_name(const char *name); Result get_uniform_by_name(const char *name); diff --git a/shaders/fragment_no_texture.frag b/shaders/fragment_no_texture.frag new file mode 100644 index 0000000..f6d7bf1 --- /dev/null +++ b/shaders/fragment_no_texture.frag @@ -0,0 +1,7 @@ +#version 330 core + +out vec4 out_color; + +void main() { + out_color = vec4(1.0, 1.0, 1.0, 1.0); +} \ No newline at end of file diff --git a/shaders/vertex_no_texture.vert b/shaders/vertex_no_texture.vert new file mode 100644 index 0000000..a44217b --- /dev/null +++ b/shaders/vertex_no_texture.vert @@ -0,0 +1,11 @@ +#version 330 core + +in vec3 position; + +uniform mat4 proj; +uniform mat4 view; +uniform mat4 model; + +void main() { + gl_Position = proj * view * model * vec4(position, 1.0); +} \ No newline at end of file diff --git a/src/RenderBackend/OpenGL/ShaderFrame.cpp b/src/RenderBackend/OpenGL/ShaderFrame.cpp index 3f7ff01..dc2653c 100644 --- a/src/RenderBackend/OpenGL/ShaderFrame.cpp +++ b/src/RenderBackend/OpenGL/ShaderFrame.cpp @@ -7,7 +7,22 @@ namespace amalgine { } ShaderFrame::~ShaderFrame() { - glDeleteVertexArrays(1, &vertex_array_object_id); + if(vertex_array_object_id != -1) + glDeleteVertexArrays(1, &vertex_array_object_id); + } + + ShaderFrame::ShaderFrame(ShaderFrame &&other) { + this->operator=(std::move(other)); + } + + ShaderFrame& ShaderFrame::operator=(ShaderFrame &&other) { + shader_program_id = other.shader_program_id; + vertex_array_object_id = other.vertex_array_object_id; + shader_inputs = std::move(other.shader_inputs); + + other.shader_program_id = -1; + other.vertex_array_object_id = -1; + return *this; } DeviceMemory* ShaderFrame::get_input_by_name(const char *name) { @@ -44,10 +59,23 @@ namespace amalgine { glUseProgram(shader_program_id); glBindVertexArray(vertex_array_object_id); // Set the active shader to use the data encapsulated by the vertex array object // TODO: Cache this num_vertices count (and reset it when device memory has changed) +#if 0 int num_vertices = 0; for(const auto &it : shader_inputs) { num_vertices = std::max(num_vertices, it.second->get_num_vertices()); } +#endif + int num_vertices = 0; + for(const auto &it : shader_inputs) { + int new_num_vertices = std::max(num_vertices, it.second->get_num_vertices()); +#if 0 + if(num_vertices != 0 && new_num_vertices != num_vertices) { + fprintf(stderr, "All inputs for shaders need to be of the same size!\n"); + abort(); + } +#endif + num_vertices = new_num_vertices; + } // TODO: Allow specifying mode different than GL_TRIANGLES glDrawArrays(GL_TRIANGLES, 0, num_vertices); } diff --git a/src/RenderBackend/OpenGL/Texture2D.cpp b/src/RenderBackend/OpenGL/Texture2D.cpp index 7d1b83c..089a5f1 100644 --- a/src/RenderBackend/OpenGL/Texture2D.cpp +++ b/src/RenderBackend/OpenGL/Texture2D.cpp @@ -72,9 +72,9 @@ namespace amalgine { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glGenerateMipmap(GL_TEXTURE_2D); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glGenerateMipmap(GL_TEXTURE_2D); } Texture2D::~Texture2D() diff --git a/src/main.cpp b/src/main.cpp index 33488bb..f2b2c3f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -54,8 +54,13 @@ static std::vector generate_sand() { return vertices; } +struct Model { + ShaderFrame frame; + Texture2D texture; +}; + static void create_sand(DeviceMemory *triangles, DeviceMemory *texcoords, Texture2D *texture); -static DeviceMemory* load_model(const char *filepath); +static Model load_model(const char *filepath, ShaderProgram *shader_program); int main() { initGlfw(); @@ -65,7 +70,7 @@ int main() { int window_height = 1; glfwGetWindowSize(window, &window_width, &window_height); - glm::mat4 proj = glm::perspective(glm::radians(75.0f), (float)window_width / (float)window_height, 0.2f, 1000.0f); + glm::mat4 proj = glm::perspective(glm::radians(75.0f), (float)window_width / (float)window_height, 0.01f, 1000.0f); std::unique_ptr sand_vertex_shader = load_shader_from_file("shaders/sand_vertex.vert", Shader::Type::VERTEX); std::unique_ptr sand_pixel_shader = load_shader_from_file("shaders/sand_fragment.frag", Shader::Type::PIXEL); @@ -91,30 +96,44 @@ int main() { std::unique_ptr vertex_shader = load_shader_from_file("shaders/vertex.vert", Shader::Type::VERTEX); std::unique_ptr pixel_shader = load_shader_from_file("shaders/fragment.frag", Shader::Type::PIXEL); std::unique_ptr shader_program = build_shader_program_from_shaders({ vertex_shader.get(), pixel_shader.get() }); - ShaderFrame model_frame = shader_program->create_frame(); - - std::vector triangles; - std::vector texture_coords; - Image *image; - ObjModelLoader::load_from_file("/home/dec05eba/Downloads/ELI4OS.obj", triangles, texture_coords, &image); - DeviceMemory *gpuModel = model_frame.get_input_by_name("position"); - gpuModel->set({triangles.data(), triangles.size()}, DeviceMemory::StorageType::STATIC); + Model buddha_model = load_model("/home/dec05eba/Downloads/ELI4OS.obj", shader_program.get()); + buddha_model.frame.get_uniform_by_name("proj")->set(proj); + Result view_uniform = buddha_model.frame.get_uniform_by_name("view"); + Result model_uniform = buddha_model.frame.get_uniform_by_name("model"); + + std::unique_ptr vertex_no_texture_shader = load_shader_from_file("shaders/vertex_no_texture.vert", Shader::Type::VERTEX); + std::unique_ptr pixel_no_texture_shader = load_shader_from_file("shaders/fragment_no_texture.frag", Shader::Type::PIXEL); + std::unique_ptr no_texture_shader_program = build_shader_program_from_shaders({ vertex_no_texture_shader.get(), pixel_no_texture_shader.get() }); + Model character_model = load_model("/home/dec05eba/Downloads/FinalBaseMesh.obj", no_texture_shader_program.get()); + character_model.frame.get_uniform_by_name("proj")->set(proj); + Result char_view_uniform = character_model.frame.get_uniform_by_name("view"); + Result char_model_uniform = character_model.frame.get_uniform_by_name("model"); + + + + glm::mat4 model = glm::rotate( + glm::mat4(1.0f), + 0.0f, + glm::vec3(0.0f, 0.0f, 1.0f) + ); + model_uniform->set(model); + + glm::mat4 char_model = glm::rotate( + glm::mat4(1.0f), + glm::pi() * 0.5f, + glm::vec3(1.0f, 0.0f, 0.0f) + ); + char_model = glm::scale(char_model, glm::vec3(0.1f, 0.1f, 0.1f)); + char_model_uniform->set(char_model); + + glm::mat4 sand_model = glm::rotate( + glm::mat4(1.0f), + 0.0f, + glm::vec3(0.0f, 0.0f, 1.0f) + ); + sand_model = glm::scale(sand_model, glm::vec3(50.0f, 50.0f, 50.0f)); + sand_model_uniform->set(sand_model); - Texture2D model_texture(image); - delete image; - DeviceMemory *model_gpu_texcoords = model_frame.get_input_by_name("texcoord_vert"); - model_gpu_texcoords->set({texture_coords.data(), texture_coords.size()}, DeviceMemory::StorageType::STATIC); - - Result proj_uniform = model_frame.get_uniform_by_name("proj"); - Result view_uniform = model_frame.get_uniform_by_name("view"); - Result model_uniform = model_frame.get_uniform_by_name("model"); - Result tex_uniform = model_frame.get_uniform_by_name("tex"); - - proj_uniform->set(proj); - tex_uniform->set(model_texture); - - triangles.resize(0); - texture_coords.resize(0); Userdata userdata; ThirdPersonCamera third_person_camera; @@ -128,7 +147,7 @@ int main() { glfwSetScrollCallback(window, [](GLFWwindow *window, double xoffset, double yoffset){ Userdata *userdata = (Userdata*)glfwGetWindowUserPointer(window); - userdata->third_person_camera->zoom(-yoffset); + userdata->third_person_camera->zoom(-yoffset*0.1f); }); glfwSetCursorPosCallback(window, [](GLFWwindow *window, double xpos, double ypos) { @@ -158,13 +177,9 @@ int main() { t_start = t_now; time += time_delta; - glm::mat4 camera_matrix = third_person_camera.get_matrix(); glm::vec3 camera_forward = third_person_camera.get_forward_vector(); glm::vec3 camera_right = third_person_camera.get_right_vector(); - sand_view_uniform->set(camera_matrix); - view_uniform->set(camera_matrix); - float move_speed = time_delta * 3.0f; glm::vec3 move_vec = glm::vec3(); if(glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) { @@ -183,40 +198,32 @@ int main() { move_vec.x += camera_right.x; move_vec.y += camera_right.y; } + if(glm::length(move_vec) > 0.0f) character_pos += (glm::normalize(move_vec) * move_speed); + third_person_camera.set_target_position(character_pos); + char_model[3][0] = character_pos.x; + char_model[3][1] = character_pos.y; + char_model[3][2] = character_pos.z - 2.0f; + char_model_uniform->set(char_model); - glm::mat4 model = glm::mat4(1.0f); - model = glm::rotate( - model, - 0.0f, - glm::vec3(0.0f, 0.0f, 1.0f) - ); - model_uniform->set(model); - - glm::mat4 sand_model = glm::mat4(1.0f); - sand_model = glm::rotate( - sand_model, - 0.0f, - glm::vec3(0.0f, 0.0f, 1.0f) - ); - sand_model = glm::scale(sand_model, glm::vec3(50.0f, 50.0f, 50.0f)); - sand_model_uniform->set(sand_model); - - //printf("now: %f\n", time); - //sand_time->set(time); + glm::mat4 camera_matrix = third_person_camera.get_matrix(); + sand_view_uniform->set(camera_matrix); + view_uniform->set(camera_matrix); + char_view_uniform->set(camera_matrix); // Set color for clearing glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Do the actual screen clearing, using the color set using glClearColor glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - model_frame.draw(); + buddha_model.frame.draw(); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + character_model.frame.draw(); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); sand_frame.draw(); - //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glfwSwapBuffers(window); } @@ -247,8 +254,32 @@ void create_sand(DeviceMemory *triangles, DeviceMemory *texcoords, Texture2D *te texcoords->set({height_map_texcoord.data(), height_map_texcoord.size()}, DeviceMemory::StorageType::STATIC); } -DeviceMemory* load_model(const char *filepath) { - return nullptr; +Model load_model(const char *filepath, ShaderProgram *shader_program) { + ShaderFrame model_frame = shader_program->create_frame(); + + std::vector triangles; + std::vector texture_coords; + Image *image; + ObjModelLoader::load_from_file(filepath, triangles, texture_coords, &image); + // TODO: This needs to be done to prevent crash in glDrawArrays, but this should not be used when shader doesn't handle any texture + //if(texture_coords.size() < triangles.size()) + // texture_coords.resize(triangles.size()); + + DeviceMemory *gpuModel = model_frame.get_input_by_name("position"); + gpuModel->set({triangles.data(), triangles.size()}, DeviceMemory::StorageType::STATIC); + + if(image) { + Texture2D model_texture(image); + delete image; + DeviceMemory *model_gpu_texcoords = model_frame.get_input_by_name("texcoord_vert"); + model_gpu_texcoords->set({texture_coords.data(), texture_coords.size()}, DeviceMemory::StorageType::STATIC); + + Result tex_uniform = model_frame.get_uniform_by_name("tex"); + tex_uniform->set(model_texture); + return { std::move(model_frame), std::move(model_texture) }; + } else { + return { std::move(model_frame), Texture2D() }; + } } void glfwErrorHandler(int errorCode, const char *errorDescription) @@ -282,10 +313,10 @@ void initGlfw() GLint flags; glGetIntegerv(GL_CONTEXT_FLAGS, &flags); if(flags & GL_CONTEXT_FLAG_DEBUG_BIT) { - glEnable(GL_DEBUG_OUTPUT); - glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); - glDebugMessageCallback(gl_debug_callback, nullptr); - glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE); + //glEnable(GL_DEBUG_OUTPUT); + //glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); + //glDebugMessageCallback(gl_debug_callback, nullptr); + //glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE); } else { fprintf(stderr, "Warning: failed to enable gl debugging\n"); } diff --git a/src/model_loader/ObjModelLoader.cpp b/src/model_loader/ObjModelLoader.cpp index f70123a..7976bc9 100644 --- a/src/model_loader/ObjModelLoader.cpp +++ b/src/model_loader/ObjModelLoader.cpp @@ -11,10 +11,12 @@ namespace amalgine { static StringView get_line(char *str, size_t size) { - char *found_ptr = (char*)memchr(str, '\n', size); - if(!found_ptr) - found_ptr = str + size; - return { str, static_cast(found_ptr - str) }; + for(size_t i = 0; i < size; ++i) { + char c = str[i]; + if(c == '\n' || c == '\r') + return { str, i }; + } + return { str, size }; } static bool is_whitespace(char c) { @@ -70,6 +72,29 @@ namespace amalgine { return static_cast(found_ptr - str.data); } + struct FaceData { + int vertex_index; + int texcoord_index; + int normal_index; + }; + + // TODO: Optimize? dont use sscanf 3 times + static bool split_faces(StringView *input, FaceData *face_data) { + input->data[input->size] = '\0'; + + face_data->vertex_index = 0; + face_data->texcoord_index = 0; + face_data->normal_index = 0; + if(sscanf(input->data, "%d/%d/%d", &face_data->vertex_index, &face_data->texcoord_index, &face_data->normal_index) == 3) + return true; + + face_data->texcoord_index = 0; + if(sscanf(input->data, "%d//%d", &face_data->vertex_index, &face_data->normal_index) == 2) + return true; + + return sscanf(input->data, "%d/%d", &face_data->vertex_index, &face_data->texcoord_index) == 2; + } + struct Material { Image *image; }; @@ -120,21 +145,22 @@ namespace amalgine { int num_columns = split_columns(column_data, ' ', columns, max_columns); if(num_columns == 3 || num_columns == 4) { bool valid = true; + // TODO: Handle these when they are not set in the below loop int vertex_indices[4]; int texture_coord_indices[4]; + int normal_indices[4]; // TODO: Use this for(int i = 0; i < num_columns; ++i) { - const int max_attributes = 3; - StringView attributes[max_attributes]; - int num_attributes = split_columns(columns[i], '/', attributes, max_attributes); - assert(num_attributes == 3); - - attributes[0].data[attributes[0].size] = '\0'; - attributes[1].data[attributes[1].size] = '\0'; - attributes[2].data[attributes[2].size] = '\0'; + FaceData face_data; + if(!split_faces(&columns[i], &face_data)) { + valid = false; + abort(); + break; + } - vertex_indices[i] = atoi(attributes[0].data); - texture_coord_indices[i] = atoi(attributes[1].data); + vertex_indices[i] = face_data.vertex_index; + texture_coord_indices[i] = face_data.texcoord_index; + normal_indices[i] = face_data.normal_index; if(vertex_indices[i] < 1 || vertex_indices[i] > vertices.size()) { valid = false; @@ -142,7 +168,7 @@ namespace amalgine { break; } - if(texture_coord_indices[i] < 1 || texture_coord_indices[i] > temp_texture_coords.size()) { + if(texture_coord_indices[i] != 0 && (texture_coord_indices[i] < 1 || texture_coord_indices[i] > temp_texture_coords.size())) { valid = false; abort(); break; @@ -150,26 +176,31 @@ namespace amalgine { --vertex_indices[i]; --texture_coord_indices[i]; + --normal_indices[i]; } if(valid) { if(num_columns == 3) { // Triangle triangles.push_back({ vertices[vertex_indices[0]], vertices[vertex_indices[1]], vertices[vertex_indices[2]] }); - texture_coords.push_back(temp_texture_coords[texture_coord_indices[0]]); - texture_coords.push_back(temp_texture_coords[texture_coord_indices[1]]); - texture_coords.push_back(temp_texture_coords[texture_coord_indices[2]]); + if(texture_coord_indices[0] >= 0) { + texture_coords.push_back(temp_texture_coords[texture_coord_indices[0]]); + texture_coords.push_back(temp_texture_coords[texture_coord_indices[1]]); + texture_coords.push_back(temp_texture_coords[texture_coord_indices[2]]); + } } else if(num_columns == 4) { // Quad, convert to triangle. TODO: Support rendering quads instead of converting to triangles triangles.push_back({ vertices[vertex_indices[0]], vertices[vertex_indices[1]], vertices[vertex_indices[2]] }); triangles.push_back({ vertices[vertex_indices[2]], vertices[vertex_indices[3]], vertices[vertex_indices[0]] }); - texture_coords.push_back(temp_texture_coords[texture_coord_indices[0]]); - texture_coords.push_back(temp_texture_coords[texture_coord_indices[1]]); - texture_coords.push_back(temp_texture_coords[texture_coord_indices[2]]); + if(texture_coord_indices[0] >= 0) { + texture_coords.push_back(temp_texture_coords[texture_coord_indices[0]]); + texture_coords.push_back(temp_texture_coords[texture_coord_indices[1]]); + texture_coords.push_back(temp_texture_coords[texture_coord_indices[2]]); - texture_coords.push_back(temp_texture_coords[texture_coord_indices[2]]); - texture_coords.push_back(temp_texture_coords[texture_coord_indices[3]]); - texture_coords.push_back(temp_texture_coords[texture_coord_indices[0]]); + texture_coords.push_back(temp_texture_coords[texture_coord_indices[2]]); + texture_coords.push_back(temp_texture_coords[texture_coord_indices[3]]); + texture_coords.push_back(temp_texture_coords[texture_coord_indices[0]]); + } } } } @@ -185,22 +216,17 @@ namespace amalgine { StringView column_data = { line_data.data + 7, line_data.size - 7 }; int num_columns = split_columns(column_data, ' ', columns, max_columns); if(num_columns == 1) { - std::string material_path; - material_path.resize(dir_path_size + 1 + columns[0].size); - memcpy(&material_path[0], dir_path.data(), dir_path_size); - material_path[dir_path_size] = '/'; - memcpy(&material_path[dir_path_size + 1], columns[0].data, columns[0].size); - printf("mtl file: %.*s\n", material_path.size(), material_path.data()); + std::string material_path = dir_path + '/'; + material_path.append(columns[0].data, columns[0].size); + printf("mtl file: %s\n", material_path.c_str()); assert(!*image); Result material = load_material_from_file(material_path.c_str()); if(!material) { - fprintf(stderr, "Error: %s\n", material.getErrorMsg().c_str()); - abort(); - goto cleanup; + fprintf(stderr, "Warning: %s\n", material.getErrorMsg().c_str()); + } else { + *image = material->image; } - - *image = material->image; } } -- cgit v1.2.3