From cebca182eb312898582c7e224b571adf3811e440 Mon Sep 17 00:00:00 2001 From: ZhuohaoHe Date: Tue, 6 Aug 2024 12:42:31 -0400 Subject: [PATCH 01/17] run on MacOS successfully --- CMakeLists.txt | 5 ++++- cmake/3rd.cmake | 29 +++++++++++++++++++++++++++++ cmake/compile_config.cmake | 2 +- src/log_system.cpp | 9 ++++++++- test/CMakeLists.txt | 27 ++++++++++++++++++++------- 5 files changed, 62 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 31556e8..54766fb 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,9 @@ # 设置最小 cmake 版本 cmake_minimum_required(VERSION 3.27 FATAL_ERROR) +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED True) + # 设置项目名与版本 project(SimpleRenderer VERSION 0.0.1) @@ -39,7 +42,7 @@ set(FONT_FILE_PATH "${wqy_font_SOURCE_DIR}/wqy-zenhei.ttc") include(ProcessorCount) ProcessorCount(NPROC) # 日志文件路径 -set(LOG_FILE_PATH "${EXECUTABLE_OUTPUT_PATH}/logs/SimpleRendererLog.log") +set(LOG_FILE_PATH "${PROJECT_SOURCE_DIR}/build/logs/SimpleRendererLog.log") # 日志文件大小 set(LOG_FILE_MAX_SIZE 1024*1024*4) # 日志文件数量 diff --git a/cmake/3rd.cmake b/cmake/3rd.cmake index 496cbb8..061cf41 100644 --- a/cmake/3rd.cmake +++ b/cmake/3rd.cmake @@ -57,6 +57,21 @@ CPMAddPackage( "gtest_force_shared_crt ON" ) +# SDL2 + +CPMAddPackage( + NAME SDL2 + GITHUB_REPOSITORY libsdl-org/SDL + GIT_TAG release-2.30.6 + OPTIONS + "SDL2_DISABLE_INSTALL ON" + "SDL_SHARED OFF" + "SDL_STATIC ON" + "SDL_STATIC_PIC ON" + "SDL_WERROR OFF" +) +find_package(SDL2 REQUIRED) + # https://github.com/aminosbh/sdl2-cmake-modules.git CPMAddPackage( NAME sdl2-cmake-modules @@ -64,6 +79,10 @@ CPMAddPackage( GIT_TAG ad006a3daae65a612ed87415037e32188b81071e DOWNLOAD_ONLY True ) +if (SDL2_ADDED) + add_library(SDL2::SDL2) +endif() + if (sdl2-cmake-modules_ADDED) list(APPEND CMAKE_MODULE_PATH ${sdl2-cmake-modules_SOURCE_DIR}) endif () @@ -95,6 +114,16 @@ if (tinyobjloader_ADDED) ) endif () +CPMAddPackage( + NAME glm + GITHUB_REPOSITORY g-truc/glm + GIT_TAG 1.0.1 +) +if (glm_ADDED) + add_library(glm INTERFACE IMPORTED) + target_include_directories(glm INTERFACE ${glm_SOURCE_DIR}) +endif () + # https://github.com/nothings/stb.git CPMAddPackage( NAME stb diff --git a/cmake/compile_config.cmake b/cmake/compile_config.cmake index 330a14a..a0a3981 100644 --- a/cmake/compile_config.cmake +++ b/cmake/compile_config.cmake @@ -19,6 +19,6 @@ list(APPEND DEFAULT_LINK_LIB tinyobjloader Eigen ${glog_LIBRARIES} - SDL2::Main + SDL2::SDL2 OpenMP::OpenMP_CXX ) diff --git a/src/log_system.cpp b/src/log_system.cpp index dc8cc66..9f7382e 100755 --- a/src/log_system.cpp +++ b/src/log_system.cpp @@ -16,6 +16,8 @@ #include "log_system.h" +#include + #include #include #include @@ -27,15 +29,20 @@ namespace simple_renderer { LogSystem::LogSystem(const std::string &log_file_path, size_t lig_file_max_size, size_t log_file_max_count) { spdlog::init_thread_pool(65536, 1); +// std::string log_file_paths = "./logs/simple_renderer.log"; + std::cout << "-1: " << log_file_path << std::endl; auto stdout_sink = std::make_shared(); + std::cout << "0: " << log_file_path << std::endl; auto rotating_sink = std::make_shared( log_file_path, lig_file_max_size, log_file_max_count); - + std::cout << "1: " << log_file_path << std::endl; std::vector sinks{stdout_sink, rotating_sink}; logger_ = std::make_shared( "multi_sink", sinks.begin(), sinks.end(), spdlog::thread_pool(), spdlog::async_overflow_policy::block); + std::cout << "2: " << log_file_path << std::endl; + // [年-月-日 时:分:秒.毫秒] [文件名:行号] [日志级别以彩色大写输出 8 // 字符右对齐] 内容 logger_->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%s:%# %!] [%^%l%$] %v"); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a568aeb..61bc9ed 100755 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -38,13 +38,26 @@ link_libraries( SimpleRenderer ) -add_subdirectory(unit_test) +# Check if the platform is macOS +if(APPLE) + # Enable RPATH support on macOS + set(CMAKE_MACOSX_RPATH 1) + + # Set the RPATH to look for frameworks relative to the executable path + set(CMAKE_INSTALL_RPATH "/Library/Frameworks") + + # Ensure that RPATH is used in the build + set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) +endif() + + +# add_subdirectory(unit_test) #add_subdirectory(integration_test) add_subdirectory(system_test) -add_coverage_target( - DEPENDS unit_test - SOURCE_DIR ${SimpleRenderer_SOURCE_DIR} - BINARY_DIR ${SimpleRenderer_BINARY_DIR} - EXCLUDE_DIR ${SimpleRenderer_SOURCE_DIR}/3rd/* -) +# add_coverage_target( +# DEPENDS unit_test +# SOURCE_DIR ${SimpleRenderer_SOURCE_DIR} +# BINARY_DIR ${SimpleRenderer_BINARY_DIR} +# EXCLUDE_DIR ${SimpleRenderer_SOURCE_DIR}/3rd/* +# ) From 78ba9f3c16cd5f4783232e33190952735afc0abe Mon Sep 17 00:00:00 2001 From: ZhuohaoHe Date: Tue, 6 Aug 2024 12:43:17 -0400 Subject: [PATCH 02/17] update log_system --- src/log_system.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/log_system.cpp b/src/log_system.cpp index 9f7382e..6c81b14 100755 --- a/src/log_system.cpp +++ b/src/log_system.cpp @@ -30,19 +30,14 @@ LogSystem::LogSystem(const std::string &log_file_path, size_t lig_file_max_size, size_t log_file_max_count) { spdlog::init_thread_pool(65536, 1); // std::string log_file_paths = "./logs/simple_renderer.log"; - std::cout << "-1: " << log_file_path << std::endl; auto stdout_sink = std::make_shared(); - std::cout << "0: " << log_file_path << std::endl; auto rotating_sink = std::make_shared( log_file_path, lig_file_max_size, log_file_max_count); - std::cout << "1: " << log_file_path << std::endl; std::vector sinks{stdout_sink, rotating_sink}; logger_ = std::make_shared( "multi_sink", sinks.begin(), sinks.end(), spdlog::thread_pool(), spdlog::async_overflow_policy::block); - std::cout << "2: " << log_file_path << std::endl; - // [年-月-日 时:分:秒.毫秒] [文件名:行号] [日志级别以彩色大写输出 8 // 字符右对齐] 内容 logger_->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%s:%# %!] [%^%l%$] %v"); From cebb0663923cbb9287da7bc17552aebb296e1263 Mon Sep 17 00:00:00 2001 From: ZhuohaoHe Date: Tue, 6 Aug 2024 13:42:15 -0400 Subject: [PATCH 03/17] replace Eigen by glm --- cmake/3rd.cmake | 6 ++ cmake/compile_config.cmake | 2 +- src/default_shader.cpp | 22 +++--- src/include/default_shader.h | 2 +- src/include/light.h | 8 +- src/include/matrix.hpp | 17 +++-- src/include/model.hpp | 18 ++--- src/include/shader_base.h | 20 ++--- src/include/simple_renderer.h | 8 +- src/include/vector.hpp | 37 +++++---- src/light.cpp | 4 +- src/model.cpp | 137 ++++++++++++++++++---------------- src/shader_base.cpp | 12 +-- src/simple_renderer.cpp | 78 +++++++++---------- test/system_test/camera.h | 4 +- test/system_test/main.cpp | 11 ++- 16 files changed, 203 insertions(+), 183 deletions(-) diff --git a/cmake/3rd.cmake b/cmake/3rd.cmake index 061cf41..2be4a15 100644 --- a/cmake/3rd.cmake +++ b/cmake/3rd.cmake @@ -281,3 +281,9 @@ if (NOT spdlog_FOUND) message(FATAL_ERROR "spdlog not found.\n" "Following https://github.com/gabime/spdlog to install.") endif () + +find_package(glm REQUIRED) +if (NOT glm_FOUND) + message(FATAL_ERROR "glm not found.\n" + "Following https://github.com/g-truc/glm tp install") +endif () \ No newline at end of file diff --git a/cmake/compile_config.cmake b/cmake/compile_config.cmake index a0a3981..b82917f 100644 --- a/cmake/compile_config.cmake +++ b/cmake/compile_config.cmake @@ -17,7 +17,7 @@ list(APPEND DEFAULT_LINK_LIB spdlog::spdlog stb tinyobjloader - Eigen + glm::glm ${glog_LIBRARIES} SDL2::SDL2 OpenMP::OpenMP_CXX diff --git a/src/default_shader.cpp b/src/default_shader.cpp index 4a90f8a..82b1732 100644 --- a/src/default_shader.cpp +++ b/src/default_shader.cpp @@ -20,26 +20,26 @@ namespace simple_renderer { auto DefaultShader::InterpolateColor( const Color &color0, const Color &color1, const Color &color2, - const Vector3f &barycentric_coord) -> Color { + const glm::vec3 &barycentric_coord) -> Color { return Color( static_cast(static_cast(color0[Color::kColorIndexRed]) * - barycentric_coord.x() + + barycentric_coord.x + static_cast(color1[Color::kColorIndexRed]) * - barycentric_coord.y() + + barycentric_coord.y + static_cast(color2[Color::kColorIndexRed]) * - barycentric_coord.z()), + barycentric_coord.z), static_cast(static_cast(color0[Color::kColorIndexGreen]) * - barycentric_coord.x() + + barycentric_coord.x + static_cast(color1[Color::kColorIndexGreen]) * - barycentric_coord.y() + + barycentric_coord.y + static_cast(color2[Color::kColorIndexGreen]) * - barycentric_coord.z()), + barycentric_coord.z), static_cast(static_cast(color0[Color::kColorIndexBlue]) * - barycentric_coord.x() + + barycentric_coord.x + static_cast(color1[Color::kColorIndexBlue]) * - barycentric_coord.y() + + barycentric_coord.y + static_cast(color2[Color::kColorIndexBlue]) * - barycentric_coord.z())); + barycentric_coord.z)); } /// @todo 巨大性能开销 @@ -56,7 +56,7 @@ auto DefaultShader::Vertex(const ShaderVertexIn &shader_vertex_in) const auto DefaultShader::Fragment(const ShaderFragmentIn &shader_fragment_in) const -> ShaderFragmentOut { - auto intensity = (shader_fragment_in.normal_.dot(shader_fragment_in.light_)); + auto intensity = glm::dot(shader_fragment_in.normal_,shader_fragment_in.light_); auto is_need_draw = true; // 光照方向为正,不绘制背面 if (intensity <= 0) { diff --git a/src/include/default_shader.h b/src/include/default_shader.h index 717c802..a187577 100644 --- a/src/include/default_shader.h +++ b/src/include/default_shader.h @@ -64,7 +64,7 @@ class DefaultShader : public ShaderBase { */ static auto InterpolateColor(const Color &color0, const Color &color1, const Color &color2, - const Vector3f &barycentric_coord) -> Color; + const glm::vec3 &barycentric_coord) -> Color; }; } // namespace simple_renderer diff --git a/src/include/light.h b/src/include/light.h index f566308..c5307d9 100644 --- a/src/include/light.h +++ b/src/include/light.h @@ -33,9 +33,9 @@ class Light { /// 光照名称 std::string name_ = "default light name"; /// 位置 - Vector3f pos = kDefaultPos; + glm::vec3 pos = kDefaultPos; /// 方向 - Vector3f dir = kDefaultDir; + glm::vec3 dir = kDefaultDir; /// 颜色 Color color = kDefaultColor; @@ -57,9 +57,9 @@ class Light { private: /// 默认位置 - static const Vector3f kDefaultPos; + static const glm::vec3 kDefaultPos; /// 默认方向,左手系,x 向右,y 向下,z 正方向为屏幕由内向外 - static const Vector3f kDefaultDir; + static const glm::vec3 kDefaultDir; /// 默认颜色 static const Color kDefaultColor; }; diff --git a/src/include/matrix.hpp b/src/include/matrix.hpp index 30a1e1b..29b7f67 100755 --- a/src/include/matrix.hpp +++ b/src/include/matrix.hpp @@ -17,13 +17,13 @@ #ifndef SIMPLERENDER_SRC_INCLUDE_MATRIX_HPP_ #define SIMPLERENDER_SRC_INCLUDE_MATRIX_HPP_ -#include +#define GLM_ENABLE_EXPERIMENTAL +#include #include "log_system.h" namespace simple_renderer { -using Matrix4f = Eigen::Matrix4f; } // namespace simple_renderer @@ -31,12 +31,13 @@ using Matrix4f = Eigen::Matrix4f; * spdlog 输出矩阵实现 */ template <> -struct fmt::formatter : fmt::formatter { - auto format(simple_renderer::Matrix4f matrix, format_context &format_context) - const -> decltype(format_context.out()) { - std::stringstream buf; - buf << matrix; - return fmt::format_to(format_context.out(), "\n{}", buf.str()); +struct fmt::formatter : fmt::formatter { + auto format(const glm::mat4 &matrix, fmt::format_context &ctx) const -> decltype(ctx.out()) { + // Convert the glm::mat4 to a string using glm::to_string + std::string matrix_str = glm::to_string(matrix); + + // Format and output the string + return fmt::format_to(ctx.out(), "\n{}", matrix_str); } }; diff --git a/src/include/model.hpp b/src/include/model.hpp index 635436e..0e9e877 100755 --- a/src/include/model.hpp +++ b/src/include/model.hpp @@ -36,22 +36,22 @@ namespace simple_renderer { class Model { public: /// 顶点坐标 - using Coord = Vector3f; + using Coord = glm::vec3; /// 法向量 - using Normal = Vector3f; + using Normal = glm::vec3; /// 贴图 - using TextureCoord = Vector2f; + using TextureCoord = glm::vec2; class Material { public: /// 反光度 float shininess = 0; /// 环境光照 - Vector3f ambient; + glm::vec3 ambient; /// 漫反射光照 - Vector3f diffuse; + glm::vec3 diffuse; /// 镜面光照 - Vector3f specular; + glm::vec3 specular; /// @name 默认构造/析构函数 /// @{ @@ -108,7 +108,7 @@ class Model { * @param tran 要对顶点进行的变换矩阵 * @return 结果 */ - [[nodiscard]] auto operator*(const Matrix4f &tran) const -> Vertex; + [[nodiscard]] auto operator*(const glm::mat4 &tran) const -> Vertex; }; /// @todo 直接保存太浪费内存了 @@ -148,7 +148,7 @@ class Model { * @param tran 要对面进行的变换矩阵 * @return 结果 */ - [[nodiscard]] auto operator*(const Matrix4f &tran) const -> Face; + [[nodiscard]] auto operator*(const glm::mat4 &tran) const -> Face; }; /// obj 文件路径 @@ -179,7 +179,7 @@ class Model { * @param tran 要对模型进行的变换矩阵 * @return 结果 */ - [[nodiscard]] auto operator*(const Matrix4f &tran) const -> Model; + [[nodiscard]] auto operator*(const glm::mat4 &tran) const -> Model; /** * 获取面 diff --git a/src/include/shader_base.h b/src/include/shader_base.h index aa04937..a97e429 100644 --- a/src/include/shader_base.h +++ b/src/include/shader_base.h @@ -83,11 +83,11 @@ class ShaderVertexOut { class ShaderFragmentIn { public: /// 重心坐标 - Vector3f barycentric_coord_; + glm::vec3 barycentric_coord_; /// 法线方向 - Vector3f normal_; + glm::vec3 normal_; /// 光照方向 - Vector3f light_; + glm::vec3 light_; /// @name 三个顶点的颜色 /// @{ @@ -105,8 +105,8 @@ class ShaderFragmentIn { * @param color1 顶点 1 颜色 * @param color2 顶点 2 颜色 */ - explicit ShaderFragmentIn(const Vector3f &_barycentric_coord, - const Vector3f &_normal, const Vector3f &_light, + explicit ShaderFragmentIn(const glm::vec3 &_barycentric_coord, + const glm::vec3 &_normal, const glm::vec3 &_light, const Color &_color0, const Color &_color1, const Color &_color2); @@ -160,11 +160,11 @@ class ShaderFragmentOut { class ShaderData { public: /// 模型变换矩阵 - Matrix4f model_matrix_ = Matrix4f().setIdentity(); + glm::mat4 model_matrix_ = glm::mat4(1.0f); /// 视图变换矩阵 - Matrix4f view_matrix_ = Matrix4f().setIdentity(); + glm::mat4 view_matrix_ = glm::mat4(1.0f); /// 正交变换矩阵 - Matrix4f project_matrix_ = Matrix4f().setIdentity(); + glm::mat4 project_matrix_ = glm::mat4(1.0f); /** * 构造函数 @@ -172,8 +172,8 @@ class ShaderData { * @param view_matrix 视图变换矩阵 * @param project_matrix 正交变换矩阵 */ - explicit ShaderData(const Matrix4f &model_matrix, const Matrix4f &view_matrix, - const Matrix4f &project_matrix); + explicit ShaderData(const glm::mat4 &model_matrix, const glm::mat4 &view_matrix, + const glm::mat4 &project_matrix); /// @name 默认构造/析构函数 /// @{ diff --git a/src/include/simple_renderer.h b/src/include/simple_renderer.h index 9aa587f..05f7a44 100755 --- a/src/include/simple_renderer.h +++ b/src/include/simple_renderer.h @@ -128,9 +128,9 @@ class SimpleRenderer { * weight_B = s * weight_C = t */ - static auto GetBarycentricCoord(const Vector3f &p0, const Vector3f &p1, - const Vector3f &p2, const Vector3f &pa) - -> std::pair; + static auto GetBarycentricCoord(const glm::vec3 &p0, const glm::vec3 &p1, + const glm::vec3 &p2, const glm::vec3 &pa) + -> std::pair; /** * 深度插值,由重心坐标计算出对应点的深度值 @@ -141,7 +141,7 @@ class SimpleRenderer { * @return 深度值 */ static auto InterpolateDepth(float depth0, float depth1, float depth2, - const Vector3f &barycentric_coord) -> float; + const glm::vec3 &barycentric_coord) -> float; }; } // namespace simple_renderer diff --git a/src/include/vector.hpp b/src/include/vector.hpp index eab8995..4b8f96a 100755 --- a/src/include/vector.hpp +++ b/src/include/vector.hpp @@ -17,42 +17,41 @@ #ifndef SIMPLERENDER_SRC_INCLUDE_VECTOR_HPP_ #define SIMPLERENDER_SRC_INCLUDE_VECTOR_HPP_ -#include +#include + +#define GLM_ENABLE_EXPERIMENTAL +#include #include "log_system.h" namespace simple_renderer { -using Vector2f = Eigen::Vector2f; -using Vector3f = Eigen::Vector3f; -using Vector4f = Eigen::Vector4f; - } // namespace simple_renderer /** * spdlog 输出 Vector3f 实现 */ template <> -struct fmt::formatter : fmt::formatter { - auto format(simple_renderer::Vector3f vector, format_context &format_context) - const -> decltype(format_context.out()) { - std::stringstream buf; - buf << vector; - return fmt::format_to(format_context.out(), "\n{}", buf.str()); - } +struct fmt::formatter : fmt::formatter { + auto format(const glm::vec3 &vector, fmt::format_context &ctx) const -> decltype(ctx.out()) { + std::string vector_string = glm::to_string(vector); + + // Format and output the string + return fmt::format_to(ctx.out(), "\n{}", vector_string); + } }; /** * spdlog 输出 Vector4f 实现 */ template <> -struct fmt::formatter : fmt::formatter { - auto format(simple_renderer::Vector4f vector, format_context &format_context) - const -> decltype(format_context.out()) { - std::stringstream buf; - buf << vector; - return fmt::format_to(format_context.out(), "\n{}", buf.str()); - } +struct fmt::formatter : fmt::formatter { + auto format(const glm::vec4 &vector, fmt::format_context &ctx) const -> decltype(ctx.out()) { + std::string vector_string = glm::to_string(vector); + + // Format and output the string + return fmt::format_to(ctx.out(), "\n{}", vector_string); + } }; #endif /* SIMPLERENDER_SRC_INCLUDE_VECTOR_HPP_ */ diff --git a/src/light.cpp b/src/light.cpp index 21c0254..61503d0 100644 --- a/src/light.cpp +++ b/src/light.cpp @@ -22,8 +22,8 @@ namespace simple_renderer { -const Vector3f Light::kDefaultPos = Vector3f(0, 0, 0); -const Vector3f Light::kDefaultDir = Vector3f(0, 0, -1); +const glm::vec3 Light::kDefaultPos = glm::vec3(0, 0, 0); +const glm::vec3 Light::kDefaultDir = glm::vec3(0, 0, -1); const Color Light::kDefaultColor = Color::kWhite; Light::Light(const std::string &name) : name_(name) { diff --git a/src/model.cpp b/src/model.cpp index 8ce949b..19f7423 100755 --- a/src/model.cpp +++ b/src/model.cpp @@ -15,6 +15,7 @@ */ #include "model.hpp" +#include #include @@ -32,19 +33,21 @@ Model::Vertex::Vertex(Coord coord, Normal normal, TextureCoord texture_coord, texture_coord_(std::move(texture_coord)), color_(color) {} -auto Model::Vertex::operator*(const Matrix4f &tran) const -> Model::Vertex { - auto vertex(*this); +auto Model::Vertex::operator*(const glm::mat4 &tran) const -> Model::Vertex { + Vertex vertex(*this); - auto res4 = Vector4f(coord_.x(), coord_.y(), coord_.z(), 1); - auto ret4 = Vector4f(tran * res4); + // Convert the 3D coordinate to a 4D vector by adding a 1.0 w-component + glm::vec4 res4(coord_, 1.0f); - vertex.coord_.x() = ret4.x(); - vertex.coord_.y() = ret4.y(); - vertex.coord_.z() = ret4.z(); + // Apply the transformation matrix + glm::vec4 ret4 = tran * res4; - /// @todo 变换法线 + // Update the vertex coordinates with the transformed values + vertex.coord_ = glm::vec3(ret4); - return vertex; + /// @todo 变换法线 + + return vertex; } Model::Face::Face(const Model::Vertex &v0, const Model::Vertex &v1, @@ -52,31 +55,31 @@ Model::Face::Face(const Model::Vertex &v0, const Model::Vertex &v1, : v0_(v0), v1_(v1), v2_(v2), material_(std::move(material)) { // 计算法向量 // 如果 obj 内包含法向量,直接使用即可 - if (v0.normal_.norm() != 0 && v1.normal_.norm() != 0 && - v2.normal_.norm() != 0) { - normal_ = (v0.normal_ + v1.normal_ + v2.normal_).normalized(); + if (glm::normalize(v0.normal_) != glm::vec3(0.0f) && glm::normalize(v1.normal_) != glm::vec3(0.0f) && + glm::normalize(v2.normal_) != glm::vec3(0.0f)) { + normal_ = glm::normalize((v0.normal_ + v1.normal_ + v2.normal_)); } // 手动计算 else { // 两条相临边的叉积 auto v2v0 = v2.coord_ - v0.coord_; auto v1v0 = v1.coord_ - v0.coord_; - normal_ = (v2v0.cross(v1v0)).normalized(); + normal_ = glm::normalize(glm::cross(v2v0, v1v0)); } } -auto Model::Face::operator*(const Matrix4f &tran) const -> Model::Face { - auto face(*this); - face.v0_ = face.v0_ * tran; - face.v1_ = face.v1_ * tran; - face.v2_ = face.v2_ * tran; +auto Model::Face::operator*(const glm::mat4 &tran) const -> Model::Face { + auto face(*this); + face.v0_ = face.v0_ * tran; + face.v1_ = face.v1_ * tran; + face.v2_ = face.v2_ * tran; - /// @todo 通过矩阵变换法线 - auto v2v0 = face.v2_.coord_ - face.v0_.coord_; - auto v1v0 = face.v1_.coord_ - face.v0_.coord_; - face.normal_ = (v2v0.cross(v1v0)).normalized(); + // Calculate the transformed normal + glm::vec3 v2v0 = face.v2_.coord_ - face.v0_.coord_; + glm::vec3 v1v0 = face.v1_.coord_ - face.v0_.coord_; + face.normal_ = glm::normalize(glm::cross(v2v0, v1v0)); - return face; + return face; } Model::Model(const std::string &obj_path, const std::string &mtl_path) @@ -143,7 +146,7 @@ Model::Model(const std::string &obj_path, const std::string &mtl_path) // 如果法线索引存在(即 idx.normal_index >= 0), // 则构造并保存,否则设置为 0 - Normal normal = Normal::Zero(); + Normal normal = glm::vec3(0.0f); if (idx.normal_index >= 0) { normal = Normal(attrib.normals[3 * size_t(idx.normal_index) + 0], attrib.normals[3 * size_t(idx.normal_index) + 1], @@ -152,7 +155,7 @@ Model::Model(const std::string &obj_path, const std::string &mtl_path) // 如果贴图索引存在(即 idx.texcoord_index >= 0), // 则构造并保存,否则设置为 0 - TextureCoord texture_coord = TextureCoord::Zero(); + TextureCoord texture_coord = glm::vec3(0.0f); if (idx.texcoord_index >= 0) { texture_coord = TextureCoord( attrib.texcoords[2 * size_t(idx.texcoord_index) + 0], @@ -172,13 +175,13 @@ Model::Model(const std::string &obj_path, const std::string &mtl_path) auto material = Material(); if (!materials.empty()) { material.shininess = materials[shape_index].shininess; - material.ambient = Vector3f(materials[shape_index].ambient[0], + material.ambient = glm::vec3(materials[shape_index].ambient[0], materials[shape_index].ambient[1], materials[shape_index].ambient[2]); - material.diffuse = Vector3f(materials[shape_index].diffuse[0], + material.diffuse = glm::vec3(materials[shape_index].diffuse[0], materials[shape_index].diffuse[1], materials[shape_index].diffuse[2]); - material.specular = Vector3f(materials[shape_index].specular[0], + material.specular = glm::vec3(materials[shape_index].specular[0], materials[shape_index].specular[1], materials[shape_index].specular[2]); } @@ -190,7 +193,7 @@ Model::Model(const std::string &obj_path, const std::string &mtl_path) Normalize(); } -auto Model::operator*(const Matrix4f &tran) const -> Model { +auto Model::operator*(const glm::mat4 &tran) const -> Model { auto model = Model(*this); for (auto &i : model.faces_) { @@ -213,27 +216,27 @@ std::pair Model::GetMaxMinXYX() { std::numeric_limits::max()); for (const auto &i : faces_) { - auto curr_max_x = std::max(i.v0_.coord_.x(), - std::max(i.v1_.coord_.x(), i.v2_.coord_.x())); - auto curr_max_y = std::max(i.v0_.coord_.y(), - std::max(i.v1_.coord_.y(), i.v2_.coord_.y())); - auto curr_max_z = std::max(i.v0_.coord_.z(), - std::max(i.v1_.coord_.z(), i.v2_.coord_.z())); - - max.x() = curr_max_x > max.x() ? curr_max_x : max.x(); - max.y() = curr_max_y > max.y() ? curr_max_y : max.y(); - max.z() = curr_max_z > max.z() ? curr_max_z : max.z(); - - auto curr_min_x = std::min(i.v0_.coord_.x(), - std::min(i.v1_.coord_.x(), i.v2_.coord_.x())); - auto curr_min_y = std::min(i.v0_.coord_.y(), - std::min(i.v1_.coord_.y(), i.v2_.coord_.y())); - auto curr_min_z = std::min(i.v0_.coord_.z(), - std::min(i.v1_.coord_.z(), i.v2_.coord_.z())); - - min.x() = curr_min_x < min.x() ? curr_min_x : min.x(); - min.y() = curr_min_y < min.y() ? curr_min_y : min.y(); - min.z() = curr_min_z < min.z() ? curr_min_z : min.z(); + auto curr_max_x = std::max(i.v0_.coord_.x, + std::max(i.v1_.coord_.x, i.v2_.coord_.x)); + auto curr_max_y = std::max(i.v0_.coord_.y, + std::max(i.v1_.coord_.y, i.v2_.coord_.y)); + auto curr_max_z = std::max(i.v0_.coord_.z, + std::max(i.v1_.coord_.z, i.v2_.coord_.z)); + + max.x = curr_max_x > max.x ? curr_max_x : max.x; + max.y = curr_max_y > max.y ? curr_max_y : max.y; + max.z = curr_max_z > max.z ? curr_max_z : max.z; + + auto curr_min_x = std::min(i.v0_.coord_.x, + std::min(i.v1_.coord_.x, i.v2_.coord_.x)); + auto curr_min_y = std::min(i.v0_.coord_.y, + std::min(i.v1_.coord_.y, i.v2_.coord_.y)); + auto curr_min_z = std::min(i.v0_.coord_.z, + std::min(i.v1_.coord_.z, i.v2_.coord_.z)); + + min.x = curr_min_x < min.x ? curr_min_x : min.x; + min.y = curr_min_y < min.y ? curr_min_y : min.y; + min.z = curr_min_z < min.z ? curr_min_z : min.z; } return {max, min}; } @@ -241,25 +244,31 @@ std::pair Model::GetMaxMinXYX() { void Model::Normalize() { auto [max, min] = GetMaxMinXYX(); - auto x = std::abs(max.x()) + std::abs(min.x()); - auto y = std::abs(max.y()) + std::abs(min.y()); - auto z = std::abs(max.z()) + std::abs(min.z()); + // Compute the dimensions of the bounding box + auto x = std::abs(max.x) + std::abs(min.x); + auto y = std::abs(max.y) + std::abs(min.y); + auto z = std::abs(max.z) + std::abs(min.z); + + // Calculate the scaling factor + auto scale = 1.0f / std::max(x, std::max(y, z)); + + // Create the scaling matrix + glm::mat4 scale_matrix = glm::scale(glm::mat4(1.0f), glm::vec3(scale, scale, scale)); - auto scale = 1.0f / std::max(x, std::max(y, z)); - auto scale_matrix = Matrix4f(Matrix4f::Identity()); - scale_matrix.diagonal() << scale, scale, scale, 1; + // Calculate the center of the bounding box + glm::vec3 center = glm::vec3((max.x + min.x) / 2.0f, (max.y + min.y) / 2.0f, (max.z + min.z) / 2.0f); - auto center = Coord((max.x() + min.x()) / 2.f, (max.y() + min.y()) / 2.f, - (max.z() + min.z()) / 2.f); - auto translation_matrix = Matrix4f(Matrix4f::Identity()); - translation_matrix.col(translation_matrix.cols() - 1) << -center.x(), - -center.y(), -center.z(), 1; + // Create the translation matrix + glm::mat4 translation_matrix = glm::translate(glm::mat4(1.0f), -center); - auto matrix = Matrix4f(scale_matrix * translation_matrix); + // Combine the scaling and translation matrices + glm::mat4 normalization_matrix = scale_matrix * translation_matrix; - SPDLOG_DEBUG("matrix: {}", matrix); + // Debug output + SPDLOG_DEBUG("normalization_matrix: \n{}", glm::to_string(normalization_matrix)); - *this = *this * matrix; + // Apply the normalization matrix to the model + *this = *this * normalization_matrix; } } // namespace simple_renderer diff --git a/src/shader_base.cpp b/src/shader_base.cpp index c0e9a83..50a2968 100644 --- a/src/shader_base.cpp +++ b/src/shader_base.cpp @@ -22,9 +22,9 @@ ShaderVertexIn::ShaderVertexIn(const Model::Face &face) : face_(face) {} ShaderVertexOut::ShaderVertexOut(const Model::Face &face) : face_(face) {} -ShaderFragmentIn::ShaderFragmentIn(const Vector3f &barycentric_coord, - const Vector3f &normal, - const Vector3f &light, const Color &color0, +ShaderFragmentIn::ShaderFragmentIn(const glm::vec3 &barycentric_coord, + const glm::vec3 &normal, + const glm::vec3 &light, const Color &color0, const Color &color1, const Color &color2) : barycentric_coord_(barycentric_coord), normal_(normal), @@ -37,9 +37,9 @@ ShaderFragmentOut::ShaderFragmentOut(const bool &is_need_draw, const Color &color) : is_need_draw_(is_need_draw), color_(color) {} -ShaderData::ShaderData(const Matrix4f &model_matrix, - const Matrix4f &view_matrix, - const Matrix4f &project_matrix) +ShaderData::ShaderData(const glm::mat4 &model_matrix, + const glm::mat4 &view_matrix, + const glm::mat4 &project_matrix) : model_matrix_(model_matrix), view_matrix_(view_matrix), project_matrix_(project_matrix) {} diff --git a/src/simple_renderer.cpp b/src/simple_renderer.cpp index c259899..b01b9a7 100755 --- a/src/simple_renderer.cpp +++ b/src/simple_renderer.cpp @@ -135,38 +135,38 @@ void SimpleRenderer::DrawTriangle(const ShaderBase &shader, const Light &light, // 获取三角形的最小 box auto min = v0.coord_; auto max = v1.coord_; - auto max_x = std::max(face.v0_.coord_.x(), - std::max(face.v1_.coord_.x(), face.v2_.coord_.x())); - auto max_y = std::max(face.v0_.coord_.y(), - std::max(face.v1_.coord_.y(), face.v2_.coord_.y())); - max.x() = max_x > max.x() ? max_x : max.x(); - max.y() = max_y > max.y() ? max_y : max.y(); - max.z() = 0; - auto min_x = std::min(face.v0_.coord_.x(), - std::min(face.v1_.coord_.x(), face.v2_.coord_.x())); - auto min_y = std::min(face.v0_.coord_.y(), - std::min(face.v1_.coord_.y(), face.v2_.coord_.y())); - min.x() = min_x < min.x() ? min_x : min.x(); - min.y() = min_y < min.y() ? min_y : min.y(); - min.z() = 0; + auto max_x = std::max(face.v0_.coord_.x, + std::max(face.v1_.coord_.x, face.v2_.coord_.x)); + auto max_y = std::max(face.v0_.coord_.y, + std::max(face.v1_.coord_.y, face.v2_.coord_.y)); + max.x = max_x > max.x ? max_x : max.x; + max.y = max_y > max.y ? max_y : max.y; + max.z = 0; + auto min_x = std::min(face.v0_.coord_.x, + std::min(face.v1_.coord_.x, face.v2_.coord_.x)); + auto min_y = std::min(face.v0_.coord_.y, + std::min(face.v1_.coord_.y, face.v2_.coord_.y)); + min.x = min_x < min.x ? min_x : min.x; + min.y = min_y < min.y ? min_y : min.y; + min.z = 0; #pragma omp parallel for num_threads(kNProc) collapse(2) default(none) \ shared(min, max, v0, v1, v2, shader) firstprivate(normal, light) - for (auto x = int32_t(min.x()); x <= int32_t(max.x()); x++) { - for (auto y = int32_t(min.y()); y <= int32_t(max.y()); y++) { + for (auto x = int32_t(min.x); x <= int32_t(max.x); x++) { + for (auto y = int32_t(min.y); y <= int32_t(max.y); y++) { /// @todo 这里要用裁剪替换掉 if ((unsigned)x >= width_ || (unsigned)y >= height_) { continue; } auto [is_inside, barycentric_coord] = GetBarycentricCoord( v0.coord_, v1.coord_, v2.coord_, - Vector3f(static_cast(x), static_cast(y), 0)); + glm::vec3(static_cast(x), static_cast(y), 0)); // 如果点在三角形内再进行下一步 if (!is_inside) { continue; } // 计算该点的深度,通过重心坐标插值计算 - auto z = InterpolateDepth(v0.coord_.z(), v1.coord_.z(), v2.coord_.z(), + auto z = InterpolateDepth(v0.coord_.z, v1.coord_.z, v2.coord_.z, barycentric_coord); // 深度在已有颜色之上 if (z < depth_buffer_[y * width_ + x]) { @@ -202,12 +202,12 @@ void SimpleRenderer::DrawModel(const ShaderBase &shader, const Light &light, for (const auto &f : model.GetFace()) { /// @todo 巨大性能开销 auto face = shader.Vertex(ShaderVertexIn(f)).face_; - DrawLine(face.v0_.coord_.x(), face.v0_.coord_.y(), face.v1_.coord_.x(), - face.v1_.coord_.y(), Color::kRed); - DrawLine(face.v1_.coord_.x(), face.v1_.coord_.y(), face.v2_.coord_.x(), - face.v2_.coord_.y(), Color::kGreen); - DrawLine(face.v2_.coord_.x(), face.v2_.coord_.y(), face.v0_.coord_.x(), - face.v0_.coord_.y(), Color::kBlue); + DrawLine(face.v0_.coord_.x, face.v0_.coord_.y, face.v1_.coord_.x, + face.v1_.coord_.y, Color::kRed); + DrawLine(face.v1_.coord_.x, face.v1_.coord_.y, face.v2_.coord_.x, + face.v2_.coord_.y, Color::kGreen); + DrawLine(face.v2_.coord_.x, face.v2_.coord_.y, face.v0_.coord_.x, + face.v0_.coord_.y, Color::kBlue); } } if (draw_triangle) { @@ -222,41 +222,41 @@ void SimpleRenderer::DrawModel(const ShaderBase &shader, const Light &light, } /// @todo 巨大性能开销 -auto SimpleRenderer::GetBarycentricCoord(const Vector3f &p0, const Vector3f &p1, - const Vector3f &p2, const Vector3f &pa) - -> std::pair { +auto SimpleRenderer::GetBarycentricCoord(const glm::vec3 &p0, const glm::vec3 &p1, + const glm::vec3 &p2, const glm::vec3 &pa) + -> std::pair { auto p1p0 = p1 - p0; auto p2p0 = p2 - p0; auto pap0 = pa - p0; - auto deno = (p1p0.x() * p2p0.y() - p1p0.y() * p2p0.x()); + auto deno = (p1p0.x * p2p0.y - p1p0.y * p2p0.x); if (std::abs(deno) < std::numeric_limits::epsilon()) { - return std::pair{false, Vector3f()}; + return std::pair{false, glm::vec3()}; } - auto s = (p2p0.y() * pap0.x() - p2p0.x() * pap0.y()) / deno; + auto s = (p2p0.y * pap0.x - p2p0.x * pap0.y) / deno; if ((s > 1) || (s < 0)) { - return std::pair{false, Vector3f()}; + return std::pair{false, glm::vec3()}; } - auto t = (p1p0.x() * pap0.y() - p1p0.y() * pap0.x()) / deno; + auto t = (p1p0.x * pap0.y - p1p0.y * pap0.x) / deno; if ((t > 1) || (t < 0)) { - return std::pair{false, Vector3f()}; + return std::pair{false, glm::vec3()}; } if ((1 - s - t > 1) || (1 - s - t < 0)) { - return std::pair{false, Vector3f()}; + return std::pair{false, glm::vec3()}; } - return std::pair{true, Vector3f(1 - s - t, s, t)}; + return std::pair{true, glm::vec3(1 - s - t, s, t)}; } auto SimpleRenderer::InterpolateDepth(float depth0, float depth1, float depth2, - const Vector3f &_barycentric_coord) + const glm::vec3 &_barycentric_coord) -> float { - auto depth = depth0 * _barycentric_coord.x(); - depth += depth1 * _barycentric_coord.y(); - depth += depth2 * _barycentric_coord.z(); + auto depth = depth0 * _barycentric_coord.x; + depth += depth1 * _barycentric_coord.y; + depth += depth2 * _barycentric_coord.z; return depth; } diff --git a/test/system_test/camera.h b/test/system_test/camera.h index ffaf55b..b661e1f 100644 --- a/test/system_test/camera.h +++ b/test/system_test/camera.h @@ -33,9 +33,9 @@ class Camera { /// 光照名称 std::string name_ = "default light name"; /// 位置 - Vector3f pos_; + glm::vec3 pos_; /// 方向 - Vector3f dir_; + glm::vec3 dir_; /** * 构造函数 diff --git a/test/system_test/main.cpp b/test/system_test/main.cpp index 6000cd2..0a166c3 100755 --- a/test/system_test/main.cpp +++ b/test/system_test/main.cpp @@ -61,9 +61,14 @@ int main(int argc, char **argv) { auto matrix = - simple_renderer::Matrix4f(simple_renderer::Matrix4f::Identity()); - matrix.diagonal() << 500, 500, 500, 1; - matrix.col(matrix.cols() - 1) << kWidth / 2, kHeight / 2, 0, 1; + glm::mat4(1.0f); + glm::mat4 scale_matrix = glm::scale(glm::mat4(1.0f), glm::vec3(500.0f, 500.0f, 500.0f)); + +// Translation matrix + glm::mat4 translation_matrix = glm::translate(glm::mat4(1.0f), glm::vec3(kWidth / 2.0f, kHeight / 2.0f, 0.0f)); + + // Combined transformation matrix + matrix = translation_matrix * scale_matrix; // 矩阵运算的顺序 // 归一化 From 049e985dd684b284c53c30d4ed36da9b96f45cab Mon Sep 17 00:00:00 2001 From: ZhuohaoHe Date: Tue, 6 Aug 2024 14:00:20 -0400 Subject: [PATCH 04/17] update 3rd.cmake --- cmake/3rd.cmake | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/cmake/3rd.cmake b/cmake/3rd.cmake index 2be4a15..3c5b464 100644 --- a/cmake/3rd.cmake +++ b/cmake/3rd.cmake @@ -87,17 +87,6 @@ if (sdl2-cmake-modules_ADDED) list(APPEND CMAKE_MODULE_PATH ${sdl2-cmake-modules_SOURCE_DIR}) endif () -## https://github.com/freetype/freetype -#CPMAddPackage( -# NAME freetype -# GIT_REPOSITORY https://github.com/freetype/freetype.git -# GIT_TAG VER-2-13-0 -# VERSION 2.13.0 -#) -#if (freetype_ADDED) -# add_library(Freetype::Freetype ALIAS freetype) -#endif () - # https://github.com/tinyobjloader/tinyobjloader.git CPMAddPackage( NAME tinyobjloader @@ -119,10 +108,6 @@ CPMAddPackage( GITHUB_REPOSITORY g-truc/glm GIT_TAG 1.0.1 ) -if (glm_ADDED) - add_library(glm INTERFACE IMPORTED) - target_include_directories(glm INTERFACE ${glm_SOURCE_DIR}) -endif () # https://github.com/nothings/stb.git CPMAddPackage( @@ -140,19 +125,6 @@ if (stb_ADDED) ) endif () -# https://gitlab.com/libeigen/eigen.git -CPMAddPackage( - NAME Eigen - GIT_REPOSITORY https://gitlab.com/libeigen/eigen.git - GIT_TAG 3.4.0 - VERSION 3.4.0 - DOWNLOAD_ONLY True -) -if (Eigen_ADDED) - add_library(Eigen INTERFACE IMPORTED) - target_include_directories(Eigen INTERFACE ${Eigen_SOURCE_DIR}) -endif () - # http://wenq.org/wqy2/index.cgi?ZenHei CPMAddPackage( NAME wqy_font From ecdb5423ab7e3e91fd0bf14077daf40a648f022e Mon Sep 17 00:00:00 2001 From: ZhuohaoHe Date: Tue, 6 Aug 2024 16:10:28 -0400 Subject: [PATCH 05/17] update structure --- {src/include => include}/color.h | 0 include/config.h | 38 ++++++++++++++++++++++ {src/include => include}/default_shader.h | 0 {src/include => include}/light.h | 0 {src/include => include}/log_system.h | 0 {src/include => include}/matrix.hpp | 0 {src/include => include}/model.hpp | 0 {src/include => include}/shader_base.h | 0 {src/include => include}/simple_renderer.h | 0 {src/include => include}/vector.hpp | 0 10 files changed, 38 insertions(+) rename {src/include => include}/color.h (100%) create mode 100644 include/config.h rename {src/include => include}/default_shader.h (100%) rename {src/include => include}/light.h (100%) rename {src/include => include}/log_system.h (100%) rename {src/include => include}/matrix.hpp (100%) rename {src/include => include}/model.hpp (100%) rename {src/include => include}/shader_base.h (100%) rename {src/include => include}/simple_renderer.h (100%) rename {src/include => include}/vector.hpp (100%) diff --git a/src/include/color.h b/include/color.h similarity index 100% rename from src/include/color.h rename to include/color.h diff --git a/include/config.h b/include/config.h new file mode 100644 index 0000000..9427427 --- /dev/null +++ b/include/config.h @@ -0,0 +1,38 @@ + +/** + * @file config.h + * @brief 项目配置 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-08-24 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleRenderer + * @par change log: + * + *
DateAuthorDescription + *
2023-08-24Zone.N创建文件 + *
+ */ + +#ifndef SIMPLERENDER_SRC_INCLUDE_CONFIG_H_ +#define SIMPLERENDER_SRC_INCLUDE_CONFIG_H_ + +#include +#include + +namespace simple_renderer { + +/// 线程数 +static constexpr const size_t kNProc = 8; + +/// 日志文件路径 +static const std::string kLogFilePath = + std::string("/Users/hezhohao/Programming/GitRepo/SimpleRenderer/build/logs/SimpleRendererLog.log"); +/// 日志文件大小 +static constexpr const size_t kLogFileMaxSize = 1024*1024*4; +/// 日志文件数量 +static constexpr const size_t kLogFileMaxCount = 8; + +} // namespace simple_renderer + +#endif /* SIMPLERENDER_SRC_INCLUDE_CONFIG_H_ */ diff --git a/src/include/default_shader.h b/include/default_shader.h similarity index 100% rename from src/include/default_shader.h rename to include/default_shader.h diff --git a/src/include/light.h b/include/light.h similarity index 100% rename from src/include/light.h rename to include/light.h diff --git a/src/include/log_system.h b/include/log_system.h similarity index 100% rename from src/include/log_system.h rename to include/log_system.h diff --git a/src/include/matrix.hpp b/include/matrix.hpp similarity index 100% rename from src/include/matrix.hpp rename to include/matrix.hpp diff --git a/src/include/model.hpp b/include/model.hpp similarity index 100% rename from src/include/model.hpp rename to include/model.hpp diff --git a/src/include/shader_base.h b/include/shader_base.h similarity index 100% rename from src/include/shader_base.h rename to include/shader_base.h diff --git a/src/include/simple_renderer.h b/include/simple_renderer.h similarity index 100% rename from src/include/simple_renderer.h rename to include/simple_renderer.h diff --git a/src/include/vector.hpp b/include/vector.hpp similarity index 100% rename from src/include/vector.hpp rename to include/vector.hpp From 70c74966a7298746c5bcb0ed9470ec6d3407038a Mon Sep 17 00:00:00 2001 From: ZhuohaoHe Date: Tue, 6 Aug 2024 20:41:13 -0400 Subject: [PATCH 06/17] integrating assimp, part 1 --- .gitignore | 2 +- CMakeLists.txt | 2 +- cmake/3rd.cmake | 45 +++--- cmake/compile_config.cmake | 1 + include/Triangle.hpp | 20 +++ include/Vertex.hpp | 29 ++++ include/model.hpp | 235 +++++++++------------------- include/shader_base.h | 8 +- include/simple_renderer.h | 2 +- src/CMakeLists.txt | 20 +-- src/include/config.h | 38 +++++ src/model.cpp | 313 +++++++++++++------------------------ src/scene.cpp | 43 ----- src/shader_base.cpp | 4 +- src/simple_renderer.cpp | 12 +- test/CMakeLists.txt | 2 +- 16 files changed, 311 insertions(+), 465 deletions(-) create mode 100644 include/Triangle.hpp create mode 100644 include/Vertex.hpp create mode 100644 src/include/config.h delete mode 100644 src/scene.cpp diff --git a/.gitignore b/.gitignore index f646857..da25727 100755 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,4 @@ tools/opensbi/build .idea 3rd Doxyfile -src/include/config.h +include/config.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 54766fb..67725f4 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,7 +50,7 @@ set(LOG_FILE_MAX_COUNT 8) # 生成配置头文件 configure_file( "${PROJECT_SOURCE_DIR}/cmake/config.h.in" - "${PROJECT_SOURCE_DIR}/src/include/config.h" + "${PROJECT_SOURCE_DIR}/include/config.h" ) # 添加要编译的目录 diff --git a/cmake/3rd.cmake b/cmake/3rd.cmake index 3c5b464..35fcc75 100644 --- a/cmake/3rd.cmake +++ b/cmake/3rd.cmake @@ -46,19 +46,17 @@ endif () include(${CPM_DOWNLOAD_LOCATION}) # -------- get_cpm.cmake -------- -# https://github.com/google/googletest CPMAddPackage( NAME googletest - GITHUB_REPOSITORY google/googletest - GIT_TAG v1.14.0 - VERSION 1.14.0 + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG v1.15.2 + VERSION 1.15.2 OPTIONS "INSTALL_GTEST OFF" "gtest_force_shared_crt ON" ) # SDL2 - CPMAddPackage( NAME SDL2 GITHUB_REPOSITORY libsdl-org/SDL @@ -72,20 +70,26 @@ CPMAddPackage( ) find_package(SDL2 REQUIRED) -# https://github.com/aminosbh/sdl2-cmake-modules.git +# # https://github.com/aminosbh/sdl2-cmake-modules.git +# CPMAddPackage( +# NAME sdl2-cmake-modules +# GIT_REPOSITORY https://github.com/aminosbh/sdl2-cmake-modules.git +# DOWNLOAD_ONLY True +# ) + +# if (sdl2-cmake-modules_ADDED) +# list(APPEND CMAKE_MODULE_PATH ${sdl2-cmake-modules_SOURCE_DIR}) +# endif () + CPMAddPackage( - NAME sdl2-cmake-modules - GIT_REPOSITORY https://github.com/aminosbh/sdl2-cmake-modules.git - GIT_TAG ad006a3daae65a612ed87415037e32188b81071e - DOWNLOAD_ONLY True + NAME assimp + GIT_REPOSITORY https://github.com/assimp/assimp.git + GIT_TAG v5.4.1 + OPTIONS + "ASSIMP_BUILD_TESTS OFF" + "ASSIMP_BUILD_ASSIMP_TOOLS OFF" + "ASSIMP_BUILD_SAMPLES OFF" ) -if (SDL2_ADDED) - add_library(SDL2::SDL2) -endif() - -if (sdl2-cmake-modules_ADDED) - list(APPEND CMAKE_MODULE_PATH ${sdl2-cmake-modules_SOURCE_DIR}) -endif () # https://github.com/tinyobjloader/tinyobjloader.git CPMAddPackage( @@ -106,7 +110,6 @@ endif () CPMAddPackage( NAME glm GITHUB_REPOSITORY g-truc/glm - GIT_TAG 1.0.1 ) # https://github.com/nothings/stb.git @@ -258,4 +261,10 @@ find_package(glm REQUIRED) if (NOT glm_FOUND) message(FATAL_ERROR "glm not found.\n" "Following https://github.com/g-truc/glm tp install") +endif () + +find_package(assimp REQUIRED) +if (NOT assimp_FOUND) + message(FATAL_ERROR "assimp not found.\n" + "Following https://github.com/assimp/assimp to install.") endif () \ No newline at end of file diff --git a/cmake/compile_config.cmake b/cmake/compile_config.cmake index b82917f..252a9ab 100644 --- a/cmake/compile_config.cmake +++ b/cmake/compile_config.cmake @@ -21,4 +21,5 @@ list(APPEND DEFAULT_LINK_LIB ${glog_LIBRARIES} SDL2::SDL2 OpenMP::OpenMP_CXX + assimp ) diff --git a/include/Triangle.hpp b/include/Triangle.hpp new file mode 100644 index 0000000..28ccf8e --- /dev/null +++ b/include/Triangle.hpp @@ -0,0 +1,20 @@ +#pragma once +#include "Vertex.hpp" + +#include +#include + +class Triangle { +public: + std::array vertices; // Holds the three vertices of the triangle + + Triangle(const Vertex& v0, const Vertex& v1, const Vertex& v2) + : vertices{v0, v1, v2} {} + + // Calculate the normal of the triangle using the cross product + glm::vec3 normal() const { + glm::vec3 edge1 = vertices[1].Position - vertices[0].Position; + glm::vec3 edge2 = vertices[2].Position - vertices[0].Position; + return glm::normalize(glm::cross(edge1, edge2)); + } +}; diff --git a/include/Vertex.hpp b/include/Vertex.hpp new file mode 100644 index 0000000..27bf937 --- /dev/null +++ b/include/Vertex.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include + +struct Vertex { + glm::vec4 Position; // Position of the vertex in homogenous coordinates + glm::vec3 Normal; // Normal vector for the vertex + glm::vec2 TexCoords; // Texture coordinates + glm::vec3 Color; // Color of the vertex + + // Constructor with parameters + Vertex(const glm::vec4& pos, const glm::vec3& norm, const glm::vec2& tex, const glm::vec3& color = glm::vec3(1.0f, 1.0f, 1.0f)) + : Position(pos), Normal(norm), TexCoords(tex), Color(color) {} + + // Transform the vertex with a matrix + Vertex transform(const glm::mat4& matrix) const { + return Vertex(matrix * Position, Normal, TexCoords, Color); + } + + // Perspective divide to convert from clip space to normalized device coordinates + void perspectiveDivide() { + if (Position.w != 0) { + Position.x /= Position.w; + Position.y /= Position.w; + Position.z /= Position.w; + Position.w = 1.0f; // Homogenize + } + } +}; \ No newline at end of file diff --git a/include/model.hpp b/include/model.hpp index 0e9e877..0af36cd 100755 --- a/include/model.hpp +++ b/include/model.hpp @@ -17,7 +17,7 @@ #ifndef SIMPLERENDER_SRC_INCLUDE_MODEL_HPP_ #define SIMPLERENDER_SRC_INCLUDE_MODEL_HPP_ -#include +#include #include #include @@ -30,181 +30,86 @@ namespace simple_renderer { -/** - * 模型 - */ -class Model { - public: - /// 顶点坐标 - using Coord = glm::vec3; - /// 法向量 - using Normal = glm::vec3; - /// 贴图 - using TextureCoord = glm::vec2; - - class Material { - public: - /// 反光度 - float shininess = 0; - /// 环境光照 +class Material { +public: + Material() = default; + Material(const Material& material) = default; + Material(Material&& material) = default; + auto operator=(const Material& material) -> Material& = default; + auto operator=(Material&& material) -> Material& = default; + ~Material() = default; + + float shininess = 0.0f; glm::vec3 ambient; - /// 漫反射光照 glm::vec3 diffuse; - /// 镜面光照 glm::vec3 specular; +}; - /// @name 默认构造/析构函数 - /// @{ - Material() = default; - Material(const Material &material) = default; - Material(Material &&material) = default; - auto operator=(const Material &material) -> Material & = default; - auto operator=(Material &&material) -> Material & = default; - ~Material() = default; - /// @} - }; - - /** - * obj/mtl 文件的原始数据 - * @todo 直接保存太浪费内存了 - */ - class Vertex { - public: - /// 坐标 - Coord coord_; - /// 法线,顶点 v 的数量与 vn 的数量一样多 - Normal normal_; - /// 贴图(纹理),范围为 0~1,顶点 v 的个数不一定与纹理坐标 vt - /// 的个数一样多, 因为有可能很多顶点公用一个纹理坐标的像素。 - TextureCoord texture_coord_; - - /// 颜色,最终每个三角面的颜色,是由构成这个三角面的三个顶点进行插值计算 - /// 如果 obj 文件中没有指定则设为 1(白色) - /// 范围 [0, 1] - Color color_; - - /** - * 构造函数 - * @param coord 坐标 - * @param normal 法向量 - * @param texture_coord 贴图 - * @param color 颜色 - */ - explicit Vertex(Coord coord, Normal normal, TextureCoord texture_coord, - const Color &color); - - /// @name 默认构造/析构函数 - /// @{ +class Vertex { +public: + explicit Vertex(glm::vec3 coord, glm::vec3 normal, glm::vec2 texture_coord, const Color& color); Vertex() = default; - Vertex(const Vertex &vertex) = default; - Vertex(Vertex &&vertex) = default; - auto operator=(const Vertex &vertex) -> Vertex & = default; - auto operator=(Vertex &&vertex) -> Vertex & = default; + Vertex(const Vertex& vertex) = default; + Vertex(Vertex&& vertex) = default; + auto operator=(const Vertex& vertex) -> Vertex& = default; + auto operator=(Vertex&& vertex) -> Vertex& = default; ~Vertex() = default; - /// @} - - /** - * * 重载,对顶点应用变换矩阵 - * @param tran 要对顶点进行的变换矩阵 - * @return 结果 - */ - [[nodiscard]] auto operator*(const glm::mat4 &tran) const -> Vertex; - }; - - /// @todo 直接保存太浪费内存了 - class Face { - public: + + [[nodiscard]] Vertex operator*(const glm::mat4 &tran) const; + + glm::vec3 coord_; + glm::vec3 normal_; + glm::vec2 texture_coord_; + Color color_; +}; + +class Face { +public: + explicit Face(const Vertex& v0, const Vertex& v1, const Vertex& v2, Material material); + Face() = default; + Face(const Face& face) = default; + Face(Face&& face) = default; + auto operator=(const Face& face) -> Face& = default; + auto operator=(Face&& face) -> Face& = default; + ~Face() = default; + + [[nodiscard]] Face operator*(const glm::mat4 &tran) const; + Vertex v0_; Vertex v1_; Vertex v2_; - /// 面的法向量为三个点的法向量矢量和 - Normal normal_; - // 面的颜色为三个点的颜色插值 - /// 材质信息 + glm::vec3 normal_; Material material_; - - /** - * 构造函数 - * @param v0 第一个顶点 - * @param v1 第二个顶点 - * @param v2 第三个顶点 - * @param material 材质 - */ - explicit Face(const Vertex &v0, const Vertex &v1, const Vertex &v2, - Material material); - - /// @name 默认构造/析构函数 - /// @{ - Face() = default; - Face(const Face &face) = default; - Face(Face &&face) = default; - auto operator=(const Face &face) -> Face & = default; - auto operator=(Face &&face) -> Face & = default; - ~Face() = default; - /// @} - - /** - * * 重载,对面应用变换矩阵 - * @param tran 要对面进行的变换矩阵 - * @return 结果 - */ - [[nodiscard]] auto operator*(const glm::mat4 &tran) const -> Face; - }; - - /// obj 文件路径 - std::string obj_path_ = ""; - /// mtl 路径 - std::string mtl_path_ = ""; - - /** - * 构造函数 - * @param obj_path obj 文件路径 - * @param mtl_path mtl 文件路径 - * @todo 顶点去重 - */ - explicit Model(const std::string &obj_path, const std::string &mtl_path = ""); - - /// @name 默认构造/析构函数 - /// @{ - Model() = default; - Model(const Model &model) = default; - Model(Model &&model) = default; - auto operator=(const Model &model) -> Model & = default; - auto operator=(Model &&model) -> Model & = default; - ~Model() = default; - /// @} - - /** - * * 重载,对模型应用变换矩阵 - * @param tran 要对模型进行的变换矩阵 - * @return 结果 - */ - [[nodiscard]] auto operator*(const glm::mat4 &tran) const -> Model; - - /** - * 获取面 - * @return 所有面 - */ - [[nodiscard]] auto GetFace() const -> const std::vector &; - - private: - /// 三角形顶点数 - static constexpr const uint8_t kTriangleFaceVertexCount = 3; - - /// 保存模型的所有面 - std::vector faces_; - - /** - * 获取模型的 xyz 最大值/最小值 - */ - std::pair GetMaxMinXYX(); - - /** - * 将模型归一化,所有坐标在 [-1, 1] 内 - */ - void Normalize(); }; +class Model { +public: + Model(const std::string &model_path); + Model() = default; + Model(const Model& model) = default; + Model(Model&& model) = default; + auto operator=(const Model& model) -> Model& = default; + auto operator=(Model&& model) -> Model& = default; + ~Model() = default; + + [[nodiscard]] Model operator*(const glm::mat4 &tran) const; + + const std::vector& GetFaces() const; + const std::string ModelPath() const; + +private: + static constexpr const uint8_t kTriangleFaceVertexCount = 3; + + std::vector faces_; + std::string model_path_ = ""; + + std::pair GetMaxMinXYZ() const; + + void NormalizeModel(); + void LoadModel(const std::string& path); + void ProcessNode(aiNode* node, const aiScene* scene); + Face ProcessMesh(aiMesh* mesh, const aiScene* scene); +}; } // namespace simple_renderer -#endif /* SIMPLERENDER_SRC_INCLUDE_MODEL_HPP_ */ +#endif /* SIMPLERENDER_SRC_INCLUDE_MODEL_HPP_ */ \ No newline at end of file diff --git a/include/shader_base.h b/include/shader_base.h index a97e429..6cc3596 100644 --- a/include/shader_base.h +++ b/include/shader_base.h @@ -29,13 +29,13 @@ namespace simple_renderer { class ShaderVertexIn { public: /// 面信息 - Model::Face face_; + Face face_; /** * 构造函数 * @param face 面信息 */ - explicit ShaderVertexIn(const Model::Face &face); + explicit ShaderVertexIn(const Face &face); /// @name 默认构造/析构函数 /// @{ @@ -56,13 +56,13 @@ class ShaderVertexIn { class ShaderVertexOut { public: /// 面信息 - Model::Face face_; + Face face_; /** * 构造函数 * @param face 面信息 */ - explicit ShaderVertexOut(const Model::Face &face); + explicit ShaderVertexOut(const Face &face); /// @name 默认构造/析构函数 /// @{ diff --git a/include/simple_renderer.h b/include/simple_renderer.h index 05f7a44..e6ec0f8 100755 --- a/include/simple_renderer.h +++ b/include/simple_renderer.h @@ -91,7 +91,7 @@ class SimpleRenderer { * @todo 多线程支持 */ void DrawTriangle(const ShaderBase &shader, const Light &light, - const Model::Normal &normal, const Model::Face &face); + const glm::vec3 &normal, const Face &face); /** * 绘制模型 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2fbf564..912ee68 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,24 +5,14 @@ # CMakeLists.txt for Simple-XX/SimpleRenderer. # 生成静态库 -add_library(${PROJECT_NAME} STATIC - log_system.cpp - color.cpp - include/vector.hpp - include/matrix.hpp - include/model.hpp - include/shader_base.h - include/default_shader.h - include/light.h - model.cpp - light.cpp - shader_base.cpp - default_shader.cpp - simple_renderer.cpp +file(GLOB_RECURSE SRC_FILES CONFIGURE_DEPENDS + "*.cpp" + "*.c" ) +add_library(${PROJECT_NAME} STATIC ${SRC_FILES}) target_include_directories(${PROJECT_NAME} PRIVATE - $ + $ $ ) diff --git a/src/include/config.h b/src/include/config.h new file mode 100644 index 0000000..9427427 --- /dev/null +++ b/src/include/config.h @@ -0,0 +1,38 @@ + +/** + * @file config.h + * @brief 项目配置 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2023-08-24 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleRenderer + * @par change log: + * + *
DateAuthorDescription + *
2023-08-24Zone.N创建文件 + *
+ */ + +#ifndef SIMPLERENDER_SRC_INCLUDE_CONFIG_H_ +#define SIMPLERENDER_SRC_INCLUDE_CONFIG_H_ + +#include +#include + +namespace simple_renderer { + +/// 线程数 +static constexpr const size_t kNProc = 8; + +/// 日志文件路径 +static const std::string kLogFilePath = + std::string("/Users/hezhohao/Programming/GitRepo/SimpleRenderer/build/logs/SimpleRendererLog.log"); +/// 日志文件大小 +static constexpr const size_t kLogFileMaxSize = 1024*1024*4; +/// 日志文件数量 +static constexpr const size_t kLogFileMaxCount = 8; + +} // namespace simple_renderer + +#endif /* SIMPLERENDER_SRC_INCLUDE_CONFIG_H_ */ diff --git a/src/model.cpp b/src/model.cpp index 19f7423..48db956 100755 --- a/src/model.cpp +++ b/src/model.cpp @@ -19,6 +19,10 @@ #include +#include +#include +#include + #define TINYOBJLOADER_IMPLEMENTATION #include @@ -26,249 +30,142 @@ namespace simple_renderer { -Model::Vertex::Vertex(Coord coord, Normal normal, TextureCoord texture_coord, - const Color &color) - : coord_(std::move(coord)), - normal_(std::move(normal)), - texture_coord_(std::move(texture_coord)), - color_(color) {} - -auto Model::Vertex::operator*(const glm::mat4 &tran) const -> Model::Vertex { - Vertex vertex(*this); - - // Convert the 3D coordinate to a 4D vector by adding a 1.0 w-component - glm::vec4 res4(coord_, 1.0f); - - // Apply the transformation matrix - glm::vec4 ret4 = tran * res4; +Vertex::Vertex(glm::vec3 coord, glm::vec3 normal, glm::vec2 texture_coord, const Color &color) + : coord_(std::move(coord)), normal_(std::move(normal)), texture_coord_(std::move(texture_coord)), color_(color) {} - // Update the vertex coordinates with the transformed values - vertex.coord_ = glm::vec3(ret4); - - /// @todo 变换法线 - - return vertex; +Vertex Vertex::operator*(const glm::mat4 &tran) const { + glm::vec4 transformed_coord = tran * glm::vec4(coord_, 1.0f); + return Vertex(glm::vec3(transformed_coord), normal_, texture_coord_, color_); } -Model::Face::Face(const Model::Vertex &v0, const Model::Vertex &v1, - const Model::Vertex &v2, Material material) +Face::Face(const Vertex &v0, const Vertex &v1, const Vertex &v2, Material material) : v0_(v0), v1_(v1), v2_(v2), material_(std::move(material)) { - // 计算法向量 - // 如果 obj 内包含法向量,直接使用即可 - if (glm::normalize(v0.normal_) != glm::vec3(0.0f) && glm::normalize(v1.normal_) != glm::vec3(0.0f) && - glm::normalize(v2.normal_) != glm::vec3(0.0f)) { - normal_ = glm::normalize((v0.normal_ + v1.normal_ + v2.normal_)); - } - // 手动计算 - else { - // 两条相临边的叉积 - auto v2v0 = v2.coord_ - v0.coord_; - auto v1v0 = v1.coord_ - v0.coord_; - normal_ = glm::normalize(glm::cross(v2v0, v1v0)); - } + + if (glm::length(v0_.normal_) > 0.0f && glm::length(v1_.normal_) > 0.0f && glm::length(v2_.normal_) > 0.0f) { + normal_ = glm::normalize(v0_.normal_ + v1_.normal_ + v2_.normal_); + } else { + normal_ = glm::normalize(glm::cross(v2_.coord_ - v0_.coord_, v1_.coord_ - v0_.coord_)); + } } -auto Model::Face::operator*(const glm::mat4 &tran) const -> Model::Face { - auto face(*this); +Face Face::operator*(const glm::mat4 &tran) const { + Face face = *this; face.v0_ = face.v0_ * tran; face.v1_ = face.v1_ * tran; face.v2_ = face.v2_ * tran; - - // Calculate the transformed normal - glm::vec3 v2v0 = face.v2_.coord_ - face.v0_.coord_; - glm::vec3 v1v0 = face.v1_.coord_ - face.v0_.coord_; - face.normal_ = glm::normalize(glm::cross(v2v0, v1v0)); - + face.normal_ = glm::normalize(glm::cross(face.v2_.coord_ - face.v0_.coord_, + face.v1_.coord_ - face.v0_.coord_)); return face; } -Model::Model(const std::string &obj_path, const std::string &mtl_path) - : obj_path_(obj_path), mtl_path_(mtl_path) { - SPDLOG_DEBUG(SRLOG, "obj_path: {}", obj_path_); - - tinyobj::ObjReader reader; - tinyobj::ObjReaderConfig config; - config.mtl_search_path = mtl_path_; - // 默认开启三角化 - auto ret = reader.ParseFromFile(obj_path_, config); - if (!ret) { - if (!reader.Error().empty()) { - SPDLOG_ERROR(reader.Error()); - throw std::runtime_error(reader.Error()); +Model::Model(const std::string &model_path) + : model_path_(model_path) { + LoadModel(model_path_); +} + +void Model::LoadModel(const std::string& path) { + Assimp::Importer importer; + const aiScene* scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_GenNormals); + + if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) { + SPDLOG_ERROR("Assimp Error: {}", importer.GetErrorString()); + throw std::runtime_error("Failed to load model with Assimp"); } - } - - if (!reader.Warning().empty()) { - SPDLOG_WARN("TinyObjReader {}", reader.Warning()); - } - - const auto &attrib = reader.GetAttrib(); - const auto &shapes = reader.GetShapes(); - const auto &materials = reader.GetMaterials(); - - SPDLOG_INFO( - "加载模型: {}, 顶点数: {}, 法线数: {}, 颜色数: {}, UV数: {}, " - "子模型数: {}, 材质数: {}", - obj_path_, attrib.vertices.size() / 3, attrib.normals.size() / 3, - attrib.colors.size() / 3, attrib.texcoords.size() / 2, shapes.size(), - materials.size()); - - // 遍历所有 shape - for (size_t shape_index = 0; shape_index < shapes.size(); shape_index++) { - auto shape = shapes[shape_index]; - // Loop over faces(polygon) - size_t index_offset = 0; - for (size_t num_face_vertices_size = 0; - num_face_vertices_size < shape.mesh.num_face_vertices.size(); - num_face_vertices_size++) { - // 由于开启了三角化,所有的 shape 都是由三个点组成的,即 fv == 3 - auto num_face_vertices = - size_t(shape.mesh.num_face_vertices[num_face_vertices_size]); - if (num_face_vertices != kTriangleFaceVertexCount) { - SPDLOG_ERROR("num_face_vertices != kTriangleFaceVertexCount: {}, {}", - num_face_vertices, kTriangleFaceVertexCount); - throw std::runtime_error( - "num_face_vertices != kTriangleFaceVertexCount"); - } - - auto vertexes = std::array(); - // 遍历面上的顶点,这里 fv == 3 - for (size_t num_face_vertices_idx = 0; - num_face_vertices_idx < num_face_vertices; num_face_vertices_idx++) { - // 获取索引 - auto idx = shape.mesh.indices[index_offset + num_face_vertices_idx]; - - // 构造顶点信息并保存 - // 每组顶点信息有 xyz 三个分量,因此需要 3* - auto coord = Coord(attrib.vertices[3 * size_t(idx.vertex_index) + 0], - attrib.vertices[3 * size_t(idx.vertex_index) + 1], - attrib.vertices[3 * size_t(idx.vertex_index) + 2]); - - // 如果法线索引存在(即 idx.normal_index >= 0), - // 则构造并保存,否则设置为 0 - Normal normal = glm::vec3(0.0f); - if (idx.normal_index >= 0) { - normal = Normal(attrib.normals[3 * size_t(idx.normal_index) + 0], - attrib.normals[3 * size_t(idx.normal_index) + 1], - attrib.normals[3 * size_t(idx.normal_index) + 2]); - } - // 如果贴图索引存在(即 idx.texcoord_index >= 0), - // 则构造并保存,否则设置为 0 - TextureCoord texture_coord = glm::vec3(0.0f); - if (idx.texcoord_index >= 0) { - texture_coord = TextureCoord( - attrib.texcoords[2 * size_t(idx.texcoord_index) + 0], - attrib.texcoords[2 * size_t(idx.texcoord_index) + 1]); - } + SPDLOG_INFO("Loaded model: {}, with meshes: {}, materials: {}", path, scene->mNumMeshes, scene->mNumMaterials); + + ProcessNode(scene->mRootNode, scene); - // 顶点颜色,如果 obj 文件中没有指定则设为 1(白色),范围 [0, 1] - auto color = Color(attrib.colors[3 * size_t(idx.vertex_index) + 0], - attrib.colors[3 * size_t(idx.vertex_index) + 1], - attrib.colors[3 * size_t(idx.vertex_index) + 2]); - vertexes.at(num_face_vertices_idx) = - Vertex(coord, normal, texture_coord, color); - } - index_offset += num_face_vertices; - - // 如果材质不为空,加载材质信息 - auto material = Material(); - if (!materials.empty()) { - material.shininess = materials[shape_index].shininess; - material.ambient = glm::vec3(materials[shape_index].ambient[0], - materials[shape_index].ambient[1], - materials[shape_index].ambient[2]); - material.diffuse = glm::vec3(materials[shape_index].diffuse[0], - materials[shape_index].diffuse[1], - materials[shape_index].diffuse[2]); - material.specular = glm::vec3(materials[shape_index].specular[0], - materials[shape_index].specular[1], - materials[shape_index].specular[2]); - } - // 添加到 face 中 - faces_.emplace_back(vertexes[0], vertexes[1], vertexes[2], material); + NormalizeModel(); +} + +void Model::ProcessNode(aiNode* node, const aiScene* scene) { + for (unsigned int i = 0; i < node->mNumMeshes; i++) { + aiMesh* mesh = scene->mMeshes[node->mMeshes[i]]; + Face face = ProcessMesh(mesh, scene); + faces_.push_back(face); } - } - Normalize(); + for (unsigned int i = 0; i < node->mNumChildren; i++) { + ProcessNode(node->mChildren[i], scene); + } } -auto Model::operator*(const glm::mat4 &tran) const -> Model { - auto model = Model(*this); +Face Model::ProcessMesh(aiMesh* mesh, const aiScene* scene) { + std::vector vertices; + for (unsigned int i = 0; i < mesh->mNumVertices; i++) { + glm::vec3 coord(mesh->mVertices[i].x, mesh->mVertices[i].y, mesh->mVertices[i].z); + glm::vec3 normal = mesh->HasNormals() ? glm::vec3(mesh->mNormals[i].x, mesh->mNormals[i].y, mesh->mNormals[i].z) : glm::vec3(0.0f); + glm::vec2 texCoord = mesh->mTextureCoords[0] ? glm::vec2(mesh->mTextureCoords[0][i].x, mesh->mTextureCoords[0][i].y) : glm::vec2(0.0f); + Color color = mesh->HasVertexColors(0) ? Color(mesh->mColors[0][i].r, mesh->mColors[0][i].g, mesh->mColors[0][i].b) : Color(1.0f); - for (auto &i : model.faces_) { - i = i * tran; - } + vertices.emplace_back(coord, normal, texCoord, color); + } - return model; -} + Material material; + if (mesh->mMaterialIndex >= 0) { + aiMaterial* aiMaterial = scene->mMaterials[mesh->mMaterialIndex]; + aiColor3D ambient(0.0f, 0.0f, 0.0f); + aiColor3D diffuse(0.0f, 0.0f, 0.0f); + aiColor3D specular(0.0f, 0.0f, 0.0f); + float shininess; + + aiMaterial->Get(AI_MATKEY_COLOR_AMBIENT, ambient); + aiMaterial->Get(AI_MATKEY_COLOR_DIFFUSE, diffuse); + aiMaterial->Get(AI_MATKEY_COLOR_SPECULAR, specular); + aiMaterial->Get(AI_MATKEY_SHININESS, shininess); + + material.ambient = glm::vec3(ambient.r, ambient.g, ambient.b); + material.diffuse = glm::vec3(diffuse.r, diffuse.g, diffuse.b); + material.specular = glm::vec3(specular.r, specular.g, specular.b); + material.shininess = shininess; + } -auto Model::GetFace() const -> const std::vector & { - return faces_; + return Face(vertices[0], vertices[1], vertices[2], material); // Assumes a triangular face } -std::pair Model::GetMaxMinXYX() { - auto max = Coord(std::numeric_limits::lowest(), - std::numeric_limits::lowest(), - std::numeric_limits::lowest()); - auto min = Coord(std::numeric_limits::max(), - std::numeric_limits::max(), - std::numeric_limits::max()); - - for (const auto &i : faces_) { - auto curr_max_x = std::max(i.v0_.coord_.x, - std::max(i.v1_.coord_.x, i.v2_.coord_.x)); - auto curr_max_y = std::max(i.v0_.coord_.y, - std::max(i.v1_.coord_.y, i.v2_.coord_.y)); - auto curr_max_z = std::max(i.v0_.coord_.z, - std::max(i.v1_.coord_.z, i.v2_.coord_.z)); - - max.x = curr_max_x > max.x ? curr_max_x : max.x; - max.y = curr_max_y > max.y ? curr_max_y : max.y; - max.z = curr_max_z > max.z ? curr_max_z : max.z; - - auto curr_min_x = std::min(i.v0_.coord_.x, - std::min(i.v1_.coord_.x, i.v2_.coord_.x)); - auto curr_min_y = std::min(i.v0_.coord_.y, - std::min(i.v1_.coord_.y, i.v2_.coord_.y)); - auto curr_min_z = std::min(i.v0_.coord_.z, - std::min(i.v1_.coord_.z, i.v2_.coord_.z)); - - min.x = curr_min_x < min.x ? curr_min_x : min.x; - min.y = curr_min_y < min.y ? curr_min_y : min.y; - min.z = curr_min_z < min.z ? curr_min_z : min.z; - } - return {max, min}; +Model Model::operator*(const glm::mat4 &tran) const { + auto model = *this; + for (auto &face : model.faces_) { + face = face * tran; + } + return model; } -void Model::Normalize() { - auto [max, min] = GetMaxMinXYX(); - - // Compute the dimensions of the bounding box - auto x = std::abs(max.x) + std::abs(min.x); - auto y = std::abs(max.y) + std::abs(min.y); - auto z = std::abs(max.z) + std::abs(min.z); +const std::vector& Model::GetFaces() const { + return faces_; +} - // Calculate the scaling factor - auto scale = 1.0f / std::max(x, std::max(y, z)); +std::pair Model::GetMaxMinXYZ() const { + glm::vec3 max_coords(std::numeric_limits::lowest()); + glm::vec3 min_coords(std::numeric_limits::max()); - // Create the scaling matrix - glm::mat4 scale_matrix = glm::scale(glm::mat4(1.0f), glm::vec3(scale, scale, scale)); + for (const auto &face : faces_) { + for (const auto &vertex : {face.v0_, face.v1_, face.v2_}) { + max_coords = glm::max(max_coords, vertex.coord_); + min_coords = glm::min(min_coords, vertex.coord_); + } + } + return {max_coords, min_coords}; +} - // Calculate the center of the bounding box - glm::vec3 center = glm::vec3((max.x + min.x) / 2.0f, (max.y + min.y) / 2.0f, (max.z + min.z) / 2.0f); +void Model::NormalizeModel() { + auto [max, min] = GetMaxMinXYZ(); + glm::vec3 scale_factors = max - min; + float scale_factor = 1.0f / glm::max(scale_factors.x, glm::max(scale_factors.y, scale_factors.z)); - // Create the translation matrix + glm::mat4 scale_matrix = glm::scale(glm::mat4(1.0f), glm::vec3(scale_factor)); + glm::vec3 center = (max + min) * 0.5f; glm::mat4 translation_matrix = glm::translate(glm::mat4(1.0f), -center); - // Combine the scaling and translation matrices glm::mat4 normalization_matrix = scale_matrix * translation_matrix; + SPDLOG_DEBUG("Normalization matrix: \n{}", glm::to_string(normalization_matrix)); - // Debug output - SPDLOG_DEBUG("normalization_matrix: \n{}", glm::to_string(normalization_matrix)); - - // Apply the normalization matrix to the model *this = *this * normalization_matrix; } +const std::string Model::ModelPath() const { + return model_path_; +} + } // namespace simple_renderer diff --git a/src/scene.cpp b/src/scene.cpp deleted file mode 100644 index 49c48e9..0000000 --- a/src/scene.cpp +++ /dev/null @@ -1,43 +0,0 @@ - -/** - * @file scene.cpp - * @brief 场景抽象 - * @author Zone.N (Zone.Niuzh@hotmail.com) - * @version 1.0 - * @date 2022-12-15 - * @copyright MIT LICENSE - * https://github.com/Simple-XX/SimpleRenderer - * @par change log: - * - *
DateAuthorDescription - *
2022-12-15Zone.N创建文件 - *
- */ - -#include "scene.h" -#include "log_system.h" -#include "matrix.hpp" - -namespace simple_renderer { - -scene_t::scene_t(const std::string &_name, uint64_t _x, uint64_t _y, - uint64_t _z) - : name(_name), x(_x), y(_y), z(_z) {} - -void scene_t::add_model(const model_t &_model, const vector3f_t _pos) { - models.push_back(std::pair(_model, _pos)); - SPDLOG_LOGGER_INFO(SRLOG, "add_model: {} to: {}, total: {}", _model.obj_path, - name, models.size()); -} - -void scene_t::add_light(const light_t &_light) { - lights.push_back(_light); - SPDLOG_LOGGER_INFO(SRLOG, "add_light: {} to: {}", _light.name, name); -} - -void scene_t::add_camera(const SimpleRenderer::camera_t &_camera) { - camera = _camera; - SPDLOG_LOGGER_INFO(SRLOG, "add_camera: {} to: {}", _camera.name, name); -} - -} // namespace SimpleRenderer diff --git a/src/shader_base.cpp b/src/shader_base.cpp index 50a2968..9d5f937 100644 --- a/src/shader_base.cpp +++ b/src/shader_base.cpp @@ -18,9 +18,9 @@ namespace simple_renderer { -ShaderVertexIn::ShaderVertexIn(const Model::Face &face) : face_(face) {} +ShaderVertexIn::ShaderVertexIn(const Face &face) : face_(face) {} -ShaderVertexOut::ShaderVertexOut(const Model::Face &face) : face_(face) {} +ShaderVertexOut::ShaderVertexOut(const Face &face) : face_(face) {} ShaderFragmentIn::ShaderFragmentIn(const glm::vec3 &barycentric_coord, const glm::vec3 &normal, diff --git a/src/simple_renderer.cpp b/src/simple_renderer.cpp index b01b9a7..6f3995b 100755 --- a/src/simple_renderer.cpp +++ b/src/simple_renderer.cpp @@ -58,7 +58,7 @@ SimpleRenderer::SimpleRenderer(size_t width, size_t height, uint32_t *buffer, } bool SimpleRenderer::render(const Model &model) { - SPDLOG_INFO("render model: {}", model.obj_path_); + SPDLOG_INFO("render model: {}", model.ModelPath()); auto shader = DefaultShader(); auto light = Light(); DrawModel(shader, light, model, 1, 0); @@ -126,8 +126,8 @@ void SimpleRenderer::DrawLine(float x0, float y0, float x1, float y1, } void SimpleRenderer::DrawTriangle(const ShaderBase &shader, const Light &light, - const Model::Normal &normal, - const Model::Face &face) { + const glm::vec3 &normal, + const Face &face) { auto v0 = face.v0_; auto v1 = face.v1_; auto v2 = face.v2_; @@ -194,12 +194,12 @@ void SimpleRenderer::DrawTriangle(const ShaderBase &shader, const Light &light, void SimpleRenderer::DrawModel(const ShaderBase &shader, const Light &light, const Model &model, bool draw_line, bool draw_triangle) { - SPDLOG_INFO("draw {}", model.obj_path_); + SPDLOG_INFO("draw {}", model.ModelPath()); if (draw_line) { #pragma omp parallel for num_threads(kNProc) default(none) shared(shader) \ firstprivate(model) - for (const auto &f : model.GetFace()) { + for (const auto &f : model.GetFaces()) { /// @todo 巨大性能开销 auto face = shader.Vertex(ShaderVertexIn(f)).face_; DrawLine(face.v0_.coord_.x, face.v0_.coord_.y, face.v1_.coord_.x, @@ -213,7 +213,7 @@ void SimpleRenderer::DrawModel(const ShaderBase &shader, const Light &light, if (draw_triangle) { #pragma omp parallel for num_threads(kNProc) default(none) shared(shader) \ firstprivate(model, light) - for (const auto &f : model.GetFace()) { + for (const auto &f : model.GetFaces()) { /// @todo 巨大性能开销 auto face = shader.Vertex(ShaderVertexIn(f)).face_; DrawTriangle(shader, light, face.normal_, face); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 61bc9ed..fa647ac 100755 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -14,7 +14,7 @@ enable_testing() include(GoogleTest) include_directories( - ${SimpleRenderer_SOURCE_DIR}/src/include + ${SimpleRenderer_SOURCE_DIR}/include ) list(APPEND DEFAULT_TEST_COMPILE_OPTIONS From 5597014b4329afb85c41069f4a4d7aac3d5c3045 Mon Sep 17 00:00:00 2001 From: ZhuohaoHe Date: Thu, 8 Aug 2024 16:44:50 -0400 Subject: [PATCH 07/17] remove OpenMP --- cmake/3rd.cmake | 6 ------ cmake/compile_config.cmake | 1 - 2 files changed, 7 deletions(-) diff --git a/cmake/3rd.cmake b/cmake/3rd.cmake index 35fcc75..735c115 100644 --- a/cmake/3rd.cmake +++ b/cmake/3rd.cmake @@ -245,12 +245,6 @@ if (NOT SDL2_FOUND) "Following https://github.com/libsdl-org/SDL to install.") endif () -find_package(OpenMP REQUIRED) -if (NOT OpenMP_FOUND) - message(FATAL_ERROR "OpenMP not found.\n" - "Following https://www.openmp.org to install.") -endif () - find_package(spdlog REQUIRED) if (NOT spdlog_FOUND) message(FATAL_ERROR "spdlog not found.\n" diff --git a/cmake/compile_config.cmake b/cmake/compile_config.cmake index 252a9ab..9a98849 100644 --- a/cmake/compile_config.cmake +++ b/cmake/compile_config.cmake @@ -20,6 +20,5 @@ list(APPEND DEFAULT_LINK_LIB glm::glm ${glog_LIBRARIES} SDL2::SDL2 - OpenMP::OpenMP_CXX assimp ) From 32b0663117f21860ec11f9297a5cb2efd788f237 Mon Sep 17 00:00:00 2001 From: ZhuohaoHe Date: Thu, 8 Aug 2024 16:45:17 -0400 Subject: [PATCH 08/17] reorganize the output of vector and matrix --- include/log_math.hpp | 65 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100755 include/log_math.hpp diff --git a/include/log_math.hpp b/include/log_math.hpp new file mode 100755 index 0000000..0f86926 --- /dev/null +++ b/include/log_math.hpp @@ -0,0 +1,65 @@ + +/** + * @file matrix.hpp + * @brief 矩阵 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2022-09-07 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleRenderer + * @par change log: + * + *
DateAuthorDescription + *
2022-09-07Zone.N迁移到 doxygen + *
+ */ + +#ifndef SIMPLERENDER_SRC_INCLUDE_MATRIX_HPP_ +#define SIMPLERENDER_SRC_INCLUDE_MATRIX_HPP_ + +#define GLM_ENABLE_EXPERIMENTAL +#include + +#include "log_system.h" + +/** + * spdlog 输出 Vector3f 实现 + */ +template <> +struct fmt::formatter : fmt::formatter { + auto format(const glm::vec3 &vector, fmt::format_context &ctx) const -> decltype(ctx.out()) { + std::string vector_string = glm::to_string(vector); + + // Format and output the string + return fmt::format_to(ctx.out(), "\n{}", vector_string); + } +}; + +/** + * spdlog 输出 Vector4f 实现 + */ +template <> +struct fmt::formatter : fmt::formatter { + auto format(const glm::vec4 &vector, fmt::format_context &ctx) const -> decltype(ctx.out()) { + std::string vector_string = glm::to_string(vector); + + // Format and output the string + return fmt::format_to(ctx.out(), "\n{}", vector_string); + } +}; + +/** + * spdlog 输出矩阵实现 + */ +template <> +struct fmt::formatter : fmt::formatter { + auto format(const glm::mat4 &matrix, fmt::format_context &ctx) const -> decltype(ctx.out()) { + // Convert the glm::mat4 to a string using glm::to_string + std::string matrix_str = glm::to_string(matrix); + + // Format and output the string + return fmt::format_to(ctx.out(), "\n{}", matrix_str); + } +}; + +#endif /* SIMPLERENDER_SRC_INCLUDE_MATRIX_HPP_ */ From fb43f04c5481d0994399780b57e428f6233c5ed3 Mon Sep 17 00:00:00 2001 From: ZhuohaoHe Date: Thu, 8 Aug 2024 16:45:57 -0400 Subject: [PATCH 09/17] reorganize vertex and face class --- include/face.hpp | 51 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 include/face.hpp diff --git a/include/face.hpp b/include/face.hpp new file mode 100644 index 0000000..febb23d --- /dev/null +++ b/include/face.hpp @@ -0,0 +1,51 @@ +#pragma once + +#include "vertex.hpp" +#include "material.hpp" + +#include + +namespace simple_renderer { + +class Face { +public: + // Default constructor + Face() = default; + // Copy constructor + Face(const Face& face) = default; + Face& operator=(const Face& face) = default; + // Move constructor + Face(Face&& face) = default; + Face& operator=(Face&& face) = default; + // Destructor + ~Face() = default; + + explicit Face(const Vertex& v0, const Vertex& v1, const Vertex& v2, Material material) + : vertices_{v0, v1, v2}, material_(std::move(material)) { + calculateNormal(); + } + + void transform(const glm::mat4 &tran) { + vertices_[0].transform(tran); + vertices_[1].transform(tran); + vertices_[2].transform(tran); + } + + const std::array& vertices() const { return vertices_; } + const Vertex& vertex(size_t index) const { return vertices_[index]; } + const glm::vec3& normal() const { return normal_; } + const Material& material() const { return material_; } + +private: + std::array vertices_; + glm::vec3 normal_; + Material material_; + + void calculateNormal() { + glm::vec3 edge1 = glm::vec3(vertices_[1].position()) - glm::vec3(vertices_[0].position()); + glm::vec3 edge2 = glm::vec3(vertices_[2].position()) - glm::vec3(vertices_[0].position()); + normal_ = glm::normalize(glm::cross(edge1, edge2)); + } +}; + +} \ No newline at end of file From 8cdb7e28db5d6bee05fd648472279b6597cbb50e Mon Sep 17 00:00:00 2001 From: ZhuohaoHe Date: Thu, 8 Aug 2024 16:46:15 -0400 Subject: [PATCH 10/17] reorganize model class --- include/Triangle.hpp | 20 ---- include/Vertex.hpp | 55 ++++++++--- include/light.h | 2 +- include/material.hpp | 22 +++++ include/matrix.hpp | 44 --------- include/model.hpp | 87 ++++------------- include/shader_base.h | 3 +- include/simple_renderer.h | 3 +- include/vector.hpp | 57 ------------ src/default_shader.cpp | 6 +- src/include/config.h | 38 -------- src/light.cpp | 2 +- src/model.cpp | 164 ++++++++++++++------------------- src/simple_renderer.cpp | 58 ++++++------ test/system_test/camera.h | 2 +- test/system_test/main.cpp | 4 +- test/unit_test/matrix_test.cpp | 2 +- 17 files changed, 191 insertions(+), 378 deletions(-) delete mode 100644 include/Triangle.hpp create mode 100644 include/material.hpp delete mode 100755 include/matrix.hpp delete mode 100755 include/vector.hpp delete mode 100644 src/include/config.h diff --git a/include/Triangle.hpp b/include/Triangle.hpp deleted file mode 100644 index 28ccf8e..0000000 --- a/include/Triangle.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once -#include "Vertex.hpp" - -#include -#include - -class Triangle { -public: - std::array vertices; // Holds the three vertices of the triangle - - Triangle(const Vertex& v0, const Vertex& v1, const Vertex& v2) - : vertices{v0, v1, v2} {} - - // Calculate the normal of the triangle using the cross product - glm::vec3 normal() const { - glm::vec3 edge1 = vertices[1].Position - vertices[0].Position; - glm::vec3 edge2 = vertices[2].Position - vertices[0].Position; - return glm::normalize(glm::cross(edge1, edge2)); - } -}; diff --git a/include/Vertex.hpp b/include/Vertex.hpp index 27bf937..2b74460 100644 --- a/include/Vertex.hpp +++ b/include/Vertex.hpp @@ -2,28 +2,53 @@ #include -struct Vertex { - glm::vec4 Position; // Position of the vertex in homogenous coordinates - glm::vec3 Normal; // Normal vector for the vertex - glm::vec2 TexCoords; // Texture coordinates - glm::vec3 Color; // Color of the vertex +#include "color.h" + +namespace simple_renderer { + +class Vertex { +public: + + // Default constructor + Vertex() = default; + // Copy constructor + Vertex(const Vertex& vertex) = default; + Vertex& operator=(const Vertex& vertex) = default; + // Move constructor + Vertex(Vertex&& vertex) = default; + Vertex& operator=(Vertex&& vertex) = default; + // Destructor + ~Vertex() = default; // Constructor with parameters - Vertex(const glm::vec4& pos, const glm::vec3& norm, const glm::vec2& tex, const glm::vec3& color = glm::vec3(1.0f, 1.0f, 1.0f)) - : Position(pos), Normal(norm), TexCoords(tex), Color(color) {} + explicit Vertex(const glm::vec4& pos, const glm::vec3& norm, const glm::vec2& tex, const Color& color_) + : position_(pos), normal_(norm), texCoords_(tex), color_(color_) {} // Transform the vertex with a matrix - Vertex transform(const glm::mat4& matrix) const { - return Vertex(matrix * Position, Normal, TexCoords, Color); + void transform(const glm::mat4& matrix) { + position_ = matrix * position_; } // Perspective divide to convert from clip space to normalized device coordinates void perspectiveDivide() { - if (Position.w != 0) { - Position.x /= Position.w; - Position.y /= Position.w; - Position.z /= Position.w; - Position.w = 1.0f; // Homogenize + if (position_.w != 0) { + position_.x /= position_.w; + position_.y /= position_.w; + position_.z /= position_.w; + position_.w = 1.0f; // Homogenize } } -}; \ No newline at end of file + + glm::vec4 position() const { return position_; } + glm::vec3 normal() const { return normal_; } + glm::vec2 texCoords() const { return texCoords_; } + Color color() const { return color_; } + +private: + glm::vec4 position_; // Position of the vertex in homogenous coordinates + glm::vec3 normal_; // Normal vector for the vertex + glm::vec2 texCoords_; // Texture coordinates + Color color_; // Color of the vertex +}; + +} \ No newline at end of file diff --git a/include/light.h b/include/light.h index c5307d9..52b6964 100644 --- a/include/light.h +++ b/include/light.h @@ -21,7 +21,7 @@ #include #include "color.h" -#include "vector.hpp" +#include "log_math.hpp" namespace simple_renderer { diff --git a/include/material.hpp b/include/material.hpp new file mode 100644 index 0000000..ed489d1 --- /dev/null +++ b/include/material.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include + +class Material { +public: + // Default constructor + Material() = default; + // Copy constructor + Material(const Material& material) = default; + Material& operator=(const Material& material) = default; + // Move constructor + Material(Material&& material) = default; + Material& operator=(Material&& material) = default; + // Destructor + ~Material() = default; + + float shininess = 0.0f; + glm::vec3 ambient; + glm::vec3 diffuse; + glm::vec3 specular; +}; \ No newline at end of file diff --git a/include/matrix.hpp b/include/matrix.hpp deleted file mode 100755 index 29b7f67..0000000 --- a/include/matrix.hpp +++ /dev/null @@ -1,44 +0,0 @@ - -/** - * @file matrix.hpp - * @brief 矩阵 - * @author Zone.N (Zone.Niuzh@hotmail.com) - * @version 1.0 - * @date 2022-09-07 - * @copyright MIT LICENSE - * https://github.com/Simple-XX/SimpleRenderer - * @par change log: - * - *
DateAuthorDescription - *
2022-09-07Zone.N迁移到 doxygen - *
- */ - -#ifndef SIMPLERENDER_SRC_INCLUDE_MATRIX_HPP_ -#define SIMPLERENDER_SRC_INCLUDE_MATRIX_HPP_ - -#define GLM_ENABLE_EXPERIMENTAL -#include - -#include "log_system.h" - -namespace simple_renderer { - - -} // namespace simple_renderer - -/** - * spdlog 输出矩阵实现 - */ -template <> -struct fmt::formatter : fmt::formatter { - auto format(const glm::mat4 &matrix, fmt::format_context &ctx) const -> decltype(ctx.out()) { - // Convert the glm::mat4 to a string using glm::to_string - std::string matrix_str = glm::to_string(matrix); - - // Format and output the string - return fmt::format_to(ctx.out(), "\n{}", matrix_str); - } -}; - -#endif /* SIMPLERENDER_SRC_INCLUDE_MATRIX_HPP_ */ diff --git a/include/model.hpp b/include/model.hpp index 0af36cd..3266c1c 100755 --- a/include/model.hpp +++ b/include/model.hpp @@ -25,90 +25,43 @@ #include "color.h" #include "config.h" #include "log_system.h" -#include "matrix.hpp" -#include "vector.hpp" +#include "log_math.hpp" -namespace simple_renderer { - -class Material { -public: - Material() = default; - Material(const Material& material) = default; - Material(Material&& material) = default; - auto operator=(const Material& material) -> Material& = default; - auto operator=(Material&& material) -> Material& = default; - ~Material() = default; - - float shininess = 0.0f; - glm::vec3 ambient; - glm::vec3 diffuse; - glm::vec3 specular; -}; - -class Vertex { -public: - explicit Vertex(glm::vec3 coord, glm::vec3 normal, glm::vec2 texture_coord, const Color& color); - Vertex() = default; - Vertex(const Vertex& vertex) = default; - Vertex(Vertex&& vertex) = default; - auto operator=(const Vertex& vertex) -> Vertex& = default; - auto operator=(Vertex&& vertex) -> Vertex& = default; - ~Vertex() = default; - - [[nodiscard]] Vertex operator*(const glm::mat4 &tran) const; - - glm::vec3 coord_; - glm::vec3 normal_; - glm::vec2 texture_coord_; - Color color_; -}; +#include "vertex.hpp" +#include "face.hpp" -class Face { -public: - explicit Face(const Vertex& v0, const Vertex& v1, const Vertex& v2, Material material); - Face() = default; - Face(const Face& face) = default; - Face(Face&& face) = default; - auto operator=(const Face& face) -> Face& = default; - auto operator=(Face&& face) -> Face& = default; - ~Face() = default; - - [[nodiscard]] Face operator*(const glm::mat4 &tran) const; - - Vertex v0_; - Vertex v1_; - Vertex v2_; - glm::vec3 normal_; - Material material_; -}; +namespace simple_renderer { class Model { public: - Model(const std::string &model_path); + + // Default constructor Model() = default; + // Default copy constructor Model(const Model& model) = default; + Model& operator=(const Model& model) = default; + // Default move constructor Model(Model&& model) = default; - auto operator=(const Model& model) -> Model& = default; - auto operator=(Model&& model) -> Model& = default; + Model& operator=(Model&& model) = default; ~Model() = default; - [[nodiscard]] Model operator*(const glm::mat4 &tran) const; + Model(const std::string &model_path); + + void transform(const glm::mat4 &tran); - const std::vector& GetFaces() const; - const std::string ModelPath() const; + const std::vector& faces() const { return faces_; }; + const std::string& modelPath() const { return directory_; }; private: static constexpr const uint8_t kTriangleFaceVertexCount = 3; + std::string directory_; std::vector faces_; - std::string model_path_ = ""; - std::pair GetMaxMinXYZ() const; - - void NormalizeModel(); - void LoadModel(const std::string& path); - void ProcessNode(aiNode* node, const aiScene* scene); - Face ProcessMesh(aiMesh* mesh, const aiScene* scene); + void loadModel(const std::string& path); + void processNode(aiNode* node, const aiScene* scene); + void processMesh(aiMesh* mesh, const aiScene* scene); + Material processMaterial(aiMaterial* material); }; } // namespace simple_renderer diff --git a/include/shader_base.h b/include/shader_base.h index 6cc3596..e2b7b0c 100644 --- a/include/shader_base.h +++ b/include/shader_base.h @@ -17,9 +17,8 @@ #ifndef SIMPLERENDER_SRC_INCLUDE_SHADER_BASE_H_ #define SIMPLERENDER_SRC_INCLUDE_SHADER_BASE_H_ -#include "matrix.hpp" #include "model.hpp" -#include "vector.hpp" +#include "log_math.hpp" namespace simple_renderer { diff --git a/include/simple_renderer.h b/include/simple_renderer.h index e6ec0f8..3fc6bed 100755 --- a/include/simple_renderer.h +++ b/include/simple_renderer.h @@ -23,10 +23,9 @@ #include "light.h" #include "log_system.h" -#include "matrix.hpp" #include "model.hpp" #include "shader_base.h" -#include "vector.hpp" +#include "log_math.hpp" namespace simple_renderer { diff --git a/include/vector.hpp b/include/vector.hpp deleted file mode 100755 index 4b8f96a..0000000 --- a/include/vector.hpp +++ /dev/null @@ -1,57 +0,0 @@ - -/** - * @file vector.hpp - * @brief 向量模版 - * @author Zone.N (Zone.Niuzh@hotmail.com) - * @version 1.0 - * @date 2022-06-07 - * @copyright MIT LICENSE - * https://github.com/Simple-XX/SimpleRenderer - * @par change log: - * - *
DateAuthorDescription - *
2022-06-07Zone.N迁移到 doxygen - *
- */ - -#ifndef SIMPLERENDER_SRC_INCLUDE_VECTOR_HPP_ -#define SIMPLERENDER_SRC_INCLUDE_VECTOR_HPP_ - -#include - -#define GLM_ENABLE_EXPERIMENTAL -#include - -#include "log_system.h" - -namespace simple_renderer { - -} // namespace simple_renderer - -/** - * spdlog 输出 Vector3f 实现 - */ -template <> -struct fmt::formatter : fmt::formatter { - auto format(const glm::vec3 &vector, fmt::format_context &ctx) const -> decltype(ctx.out()) { - std::string vector_string = glm::to_string(vector); - - // Format and output the string - return fmt::format_to(ctx.out(), "\n{}", vector_string); - } -}; - -/** - * spdlog 输出 Vector4f 实现 - */ -template <> -struct fmt::formatter : fmt::formatter { - auto format(const glm::vec4 &vector, fmt::format_context &ctx) const -> decltype(ctx.out()) { - std::string vector_string = glm::to_string(vector); - - // Format and output the string - return fmt::format_to(ctx.out(), "\n{}", vector_string); - } -}; - -#endif /* SIMPLERENDER_SRC_INCLUDE_VECTOR_HPP_ */ diff --git a/src/default_shader.cpp b/src/default_shader.cpp index 82b1732..5c8065a 100644 --- a/src/default_shader.cpp +++ b/src/default_shader.cpp @@ -47,8 +47,10 @@ auto DefaultShader::Vertex(const ShaderVertexIn &shader_vertex_in) const -> ShaderVertexOut { auto face(shader_vertex_in.face_); - face = face * shader_data_.model_matrix_ * shader_data_.view_matrix_ * - shader_data_.project_matrix_; + face.transform( + shader_data_.project_matrix_ + * shader_data_.view_matrix_ + * shader_data_.model_matrix_); /// @todo 变换贴图 return ShaderVertexOut(face); diff --git a/src/include/config.h b/src/include/config.h deleted file mode 100644 index 9427427..0000000 --- a/src/include/config.h +++ /dev/null @@ -1,38 +0,0 @@ - -/** - * @file config.h - * @brief 项目配置 - * @author Zone.N (Zone.Niuzh@hotmail.com) - * @version 1.0 - * @date 2023-08-24 - * @copyright MIT LICENSE - * https://github.com/Simple-XX/SimpleRenderer - * @par change log: - * - *
DateAuthorDescription - *
2023-08-24Zone.N创建文件 - *
- */ - -#ifndef SIMPLERENDER_SRC_INCLUDE_CONFIG_H_ -#define SIMPLERENDER_SRC_INCLUDE_CONFIG_H_ - -#include -#include - -namespace simple_renderer { - -/// 线程数 -static constexpr const size_t kNProc = 8; - -/// 日志文件路径 -static const std::string kLogFilePath = - std::string("/Users/hezhohao/Programming/GitRepo/SimpleRenderer/build/logs/SimpleRendererLog.log"); -/// 日志文件大小 -static constexpr const size_t kLogFileMaxSize = 1024*1024*4; -/// 日志文件数量 -static constexpr const size_t kLogFileMaxCount = 8; - -} // namespace simple_renderer - -#endif /* SIMPLERENDER_SRC_INCLUDE_CONFIG_H_ */ diff --git a/src/light.cpp b/src/light.cpp index 61503d0..0686703 100644 --- a/src/light.cpp +++ b/src/light.cpp @@ -18,7 +18,7 @@ #include "color.h" #include "log_system.h" -#include "vector.hpp" +#include "log_math.hpp" namespace simple_renderer { diff --git a/src/model.cpp b/src/model.cpp index 48db956..5b3986d 100755 --- a/src/model.cpp +++ b/src/model.cpp @@ -30,142 +30,114 @@ namespace simple_renderer { -Vertex::Vertex(glm::vec3 coord, glm::vec3 normal, glm::vec2 texture_coord, const Color &color) - : coord_(std::move(coord)), normal_(std::move(normal)), texture_coord_(std::move(texture_coord)), color_(color) {} -Vertex Vertex::operator*(const glm::mat4 &tran) const { - glm::vec4 transformed_coord = tran * glm::vec4(coord_, 1.0f); - return Vertex(glm::vec3(transformed_coord), normal_, texture_coord_, color_); +Model::Model(const std::string &model_path) { + loadModel(model_path); } -Face::Face(const Vertex &v0, const Vertex &v1, const Vertex &v2, Material material) - : v0_(v0), v1_(v1), v2_(v2), material_(std::move(material)) { - - if (glm::length(v0_.normal_) > 0.0f && glm::length(v1_.normal_) > 0.0f && glm::length(v2_.normal_) > 0.0f) { - normal_ = glm::normalize(v0_.normal_ + v1_.normal_ + v2_.normal_); - } else { - normal_ = glm::normalize(glm::cross(v2_.coord_ - v0_.coord_, v1_.coord_ - v0_.coord_)); - } -} - -Face Face::operator*(const glm::mat4 &tran) const { - Face face = *this; - face.v0_ = face.v0_ * tran; - face.v1_ = face.v1_ * tran; - face.v2_ = face.v2_ * tran; - face.normal_ = glm::normalize(glm::cross(face.v2_.coord_ - face.v0_.coord_, - face.v1_.coord_ - face.v0_.coord_)); - return face; -} - -Model::Model(const std::string &model_path) - : model_path_(model_path) { - LoadModel(model_path_); -} - -void Model::LoadModel(const std::string& path) { +void Model::loadModel(const std::string& path) { Assimp::Importer importer; - const aiScene* scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_GenNormals); + const aiScene* scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs); if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) { SPDLOG_ERROR("Assimp Error: {}", importer.GetErrorString()); throw std::runtime_error("Failed to load model with Assimp"); } - SPDLOG_INFO("Loaded model: {}, with meshes: {}, materials: {}", path, scene->mNumMeshes, scene->mNumMaterials); + directory_ = path.substr(0, path.find_last_of('/')); - ProcessNode(scene->mRootNode, scene); + SPDLOG_INFO("Loaded model path: {}, Directory: {}, with meshes: {}, materials: {}", path, directory_, scene->mNumMeshes, scene->mNumMaterials); - NormalizeModel(); + processNode(scene->mRootNode, scene); } -void Model::ProcessNode(aiNode* node, const aiScene* scene) { +void Model::processNode(aiNode* node, const aiScene* scene) { for (unsigned int i = 0; i < node->mNumMeshes; i++) { aiMesh* mesh = scene->mMeshes[node->mMeshes[i]]; - Face face = ProcessMesh(mesh, scene); - faces_.push_back(face); + processMesh(mesh, scene); } for (unsigned int i = 0; i < node->mNumChildren; i++) { - ProcessNode(node->mChildren[i], scene); + processNode(node->mChildren[i], scene); } } -Face Model::ProcessMesh(aiMesh* mesh, const aiScene* scene) { +void Model::processMesh(aiMesh* mesh, const aiScene* scene) { std::vector vertices; - for (unsigned int i = 0; i < mesh->mNumVertices; i++) { - glm::vec3 coord(mesh->mVertices[i].x, mesh->mVertices[i].y, mesh->mVertices[i].z); - glm::vec3 normal = mesh->HasNormals() ? glm::vec3(mesh->mNormals[i].x, mesh->mNormals[i].y, mesh->mNormals[i].z) : glm::vec3(0.0f); - glm::vec2 texCoord = mesh->mTextureCoords[0] ? glm::vec2(mesh->mTextureCoords[0][i].x, mesh->mTextureCoords[0][i].y) : glm::vec2(0.0f); - Color color = mesh->HasVertexColors(0) ? Color(mesh->mColors[0][i].r, mesh->mColors[0][i].g, mesh->mColors[0][i].b) : Color(1.0f); - vertices.emplace_back(coord, normal, texCoord, color); - } + // Process vertices + for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { + glm::vec3 position( + mesh->mVertices[i].x, + mesh->mVertices[i].y, + mesh->mVertices[i].z + ); + glm::vec3 normal( + mesh->mNormals[i].x, + mesh->mNormals[i].y, + mesh->mNormals[i].z + ); + glm::vec2 texCoords(0.0f, 0.0f); + if (mesh->mTextureCoords[0]) { // Check if the mesh contains texture coordinates + texCoords = glm::vec2( + mesh->mTextureCoords[0][i].x, + mesh->mTextureCoords[0][i].y + ); + } - Material material; - if (mesh->mMaterialIndex >= 0) { - aiMaterial* aiMaterial = scene->mMaterials[mesh->mMaterialIndex]; - aiColor3D ambient(0.0f, 0.0f, 0.0f); - aiColor3D diffuse(0.0f, 0.0f, 0.0f); - aiColor3D specular(0.0f, 0.0f, 0.0f); - float shininess; - - aiMaterial->Get(AI_MATKEY_COLOR_AMBIENT, ambient); - aiMaterial->Get(AI_MATKEY_COLOR_DIFFUSE, diffuse); - aiMaterial->Get(AI_MATKEY_COLOR_SPECULAR, specular); - aiMaterial->Get(AI_MATKEY_SHININESS, shininess); + Color color(255.f, 255.f, 255.f, 255.f); - material.ambient = glm::vec3(ambient.r, ambient.g, ambient.b); - material.diffuse = glm::vec3(diffuse.r, diffuse.g, diffuse.b); - material.specular = glm::vec3(specular.r, specular.g, specular.b); - material.shininess = shininess; + vertices.emplace_back(glm::vec4(position, 1.0f), normal, texCoords, color); } + // Process faces (assuming triangulation, so each face has 3 vertices) + for (unsigned int i = 0; i < mesh->mNumFaces; ++i) { + aiFace face = mesh->mFaces[i]; + if (face.mNumIndices == 3) { // Ensure we are working with triangles + Vertex v0 = vertices[face.mIndices[0]]; + Vertex v1 = vertices[face.mIndices[1]]; + Vertex v2 = vertices[face.mIndices[2]]; - return Face(vertices[0], vertices[1], vertices[2], material); // Assumes a triangular face -} + Material material = processMaterial(scene->mMaterials[mesh->mMaterialIndex]); -Model Model::operator*(const glm::mat4 &tran) const { - auto model = *this; - for (auto &face : model.faces_) { - face = face * tran; + faces_.emplace_back(v0, v1, v2, std::move(material)); + } } - return model; -} - -const std::vector& Model::GetFaces() const { - return faces_; } -std::pair Model::GetMaxMinXYZ() const { - glm::vec3 max_coords(std::numeric_limits::lowest()); - glm::vec3 min_coords(std::numeric_limits::max()); +Material Model::processMaterial(aiMaterial* mat) { + Material material; - for (const auto &face : faces_) { - for (const auto &vertex : {face.v0_, face.v1_, face.v2_}) { - max_coords = glm::max(max_coords, vertex.coord_); - min_coords = glm::min(min_coords, vertex.coord_); - } + // Extract ambient color + aiColor3D ambient(0.0f, 0.0f, 0.0f); + if (AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_AMBIENT, ambient)) { + material.ambient = glm::vec3(ambient.r, ambient.g, ambient.b); } - return {max_coords, min_coords}; -} -void Model::NormalizeModel() { - auto [max, min] = GetMaxMinXYZ(); - glm::vec3 scale_factors = max - min; - float scale_factor = 1.0f / glm::max(scale_factors.x, glm::max(scale_factors.y, scale_factors.z)); + // Extract diffuse color + aiColor3D diffuse(1.0f, 1.0f, 1.0f); // Default to white + if (AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_DIFFUSE, diffuse)) { + material.diffuse = glm::vec3(diffuse.r, diffuse.g, diffuse.b); + } - glm::mat4 scale_matrix = glm::scale(glm::mat4(1.0f), glm::vec3(scale_factor)); - glm::vec3 center = (max + min) * 0.5f; - glm::mat4 translation_matrix = glm::translate(glm::mat4(1.0f), -center); + // Extract specular color + aiColor3D specular(0.0f, 0.0f, 0.0f); + if (AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_SPECULAR, specular)) { + material.specular = glm::vec3(specular.r, specular.g, specular.b); + } - glm::mat4 normalization_matrix = scale_matrix * translation_matrix; - SPDLOG_DEBUG("Normalization matrix: \n{}", glm::to_string(normalization_matrix)); + // Extract shininess + float shininess = 0.0f; + if (AI_SUCCESS == mat->Get(AI_MATKEY_SHININESS, shininess)) { + material.shininess = shininess; + } - *this = *this * normalization_matrix; + return material; } -const std::string Model::ModelPath() const { - return model_path_; +void Model::transform(const glm::mat4 &tran) { + for (auto& face : faces_) { + face.transform(tran); + } } } // namespace simple_renderer diff --git a/src/simple_renderer.cpp b/src/simple_renderer.cpp index 6f3995b..7c237c5 100755 --- a/src/simple_renderer.cpp +++ b/src/simple_renderer.cpp @@ -58,10 +58,10 @@ SimpleRenderer::SimpleRenderer(size_t width, size_t height, uint32_t *buffer, } bool SimpleRenderer::render(const Model &model) { - SPDLOG_INFO("render model: {}", model.ModelPath()); + SPDLOG_INFO("render model: {}", model.modelPath()); auto shader = DefaultShader(); auto light = Light(); - DrawModel(shader, light, model, 1, 0); + DrawModel(shader, light, model, 0, 1); return true; } @@ -128,24 +128,24 @@ void SimpleRenderer::DrawLine(float x0, float y0, float x1, float y1, void SimpleRenderer::DrawTriangle(const ShaderBase &shader, const Light &light, const glm::vec3 &normal, const Face &face) { - auto v0 = face.v0_; - auto v1 = face.v1_; - auto v2 = face.v2_; + auto v0 = face.vertex(0); + auto v1 = face.vertex(1); + auto v2 = face.vertex(2); // 获取三角形的最小 box - auto min = v0.coord_; - auto max = v1.coord_; - auto max_x = std::max(face.v0_.coord_.x, - std::max(face.v1_.coord_.x, face.v2_.coord_.x)); - auto max_y = std::max(face.v0_.coord_.y, - std::max(face.v1_.coord_.y, face.v2_.coord_.y)); + auto min = v0.position(); + auto max = v1.position(); + auto max_x = std::max(face.vertex(0).position().x, + std::max(face.vertex(1).position().x, face.vertex(2).position().x)); + auto max_y = std::max(face.vertex(0).position().y, + std::max(face.vertex(1).position().y, face.vertex(2).position().y)); max.x = max_x > max.x ? max_x : max.x; max.y = max_y > max.y ? max_y : max.y; max.z = 0; - auto min_x = std::min(face.v0_.coord_.x, - std::min(face.v1_.coord_.x, face.v2_.coord_.x)); - auto min_y = std::min(face.v0_.coord_.y, - std::min(face.v1_.coord_.y, face.v2_.coord_.y)); + auto min_x = std::min(face.vertex(0).position().x, + std::min(face.vertex(1).position().x, face.vertex(2).position().x)); + auto min_y = std::min(face.vertex(0).position().y, + std::min(face.vertex(1).position().y, face.vertex(2).position().y)); min.x = min_x < min.x ? min_x : min.x; min.y = min_y < min.y ? min_y : min.y; min.z = 0; @@ -159,14 +159,14 @@ void SimpleRenderer::DrawTriangle(const ShaderBase &shader, const Light &light, continue; } auto [is_inside, barycentric_coord] = GetBarycentricCoord( - v0.coord_, v1.coord_, v2.coord_, + v0.position(), v1.position(), v2.position(), glm::vec3(static_cast(x), static_cast(y), 0)); // 如果点在三角形内再进行下一步 if (!is_inside) { continue; } // 计算该点的深度,通过重心坐标插值计算 - auto z = InterpolateDepth(v0.coord_.z, v1.coord_.z, v2.coord_.z, + auto z = InterpolateDepth(v0.position().z, v1.position().z, v2.position().z, barycentric_coord); // 深度在已有颜色之上 if (z < depth_buffer_[y * width_ + x]) { @@ -174,8 +174,8 @@ void SimpleRenderer::DrawTriangle(const ShaderBase &shader, const Light &light, } // 构造着色器输入 auto shader_fragment_in = - ShaderFragmentIn(barycentric_coord, normal, light.dir, v0.color_, - v1.color_, v2.color_); + ShaderFragmentIn(barycentric_coord, normal, light.dir, v0.color(), + v1.color(), v2.color()); // 计算颜色,颜色为通过 shader 片段着色器计算 auto shader_fragment_out = shader.Fragment(shader_fragment_in); // 如果不需要绘制则跳过 @@ -194,29 +194,29 @@ void SimpleRenderer::DrawTriangle(const ShaderBase &shader, const Light &light, void SimpleRenderer::DrawModel(const ShaderBase &shader, const Light &light, const Model &model, bool draw_line, bool draw_triangle) { - SPDLOG_INFO("draw {}", model.ModelPath()); + SPDLOG_INFO("draw {}", model.modelPath()); if (draw_line) { #pragma omp parallel for num_threads(kNProc) default(none) shared(shader) \ firstprivate(model) - for (const auto &f : model.GetFaces()) { + for (const auto &f : model.faces()) { /// @todo 巨大性能开销 auto face = shader.Vertex(ShaderVertexIn(f)).face_; - DrawLine(face.v0_.coord_.x, face.v0_.coord_.y, face.v1_.coord_.x, - face.v1_.coord_.y, Color::kRed); - DrawLine(face.v1_.coord_.x, face.v1_.coord_.y, face.v2_.coord_.x, - face.v2_.coord_.y, Color::kGreen); - DrawLine(face.v2_.coord_.x, face.v2_.coord_.y, face.v0_.coord_.x, - face.v0_.coord_.y, Color::kBlue); + DrawLine(face.vertex(0).position().x, face.vertex(0).position().y, face.vertex(1).position().x, + face.vertex(1).position().y, Color::kRed); + DrawLine(face.vertex(1).position().x, face.vertex(1).position().y, face.vertex(2).position().x, + face.vertex(2).position().y, Color::kGreen); + DrawLine(face.vertex(2).position().x, face.vertex(2).position().y, face.vertex(0).position().x, + face.vertex(0).position().y, Color::kBlue); } } if (draw_triangle) { #pragma omp parallel for num_threads(kNProc) default(none) shared(shader) \ firstprivate(model, light) - for (const auto &f : model.GetFaces()) { + for (const auto &f : model.faces()) { /// @todo 巨大性能开销 auto face = shader.Vertex(ShaderVertexIn(f)).face_; - DrawTriangle(shader, light, face.normal_, face); + DrawTriangle(shader, light, face.normal(), face); } } } diff --git a/test/system_test/camera.h b/test/system_test/camera.h index b661e1f..2694bdd 100644 --- a/test/system_test/camera.h +++ b/test/system_test/camera.h @@ -21,7 +21,7 @@ #include #include "color.h" -#include "vector.hpp" +#include "log_math.hpp" namespace simple_renderer { diff --git a/test/system_test/main.cpp b/test/system_test/main.cpp index 0a166c3..6797ac6 100755 --- a/test/system_test/main.cpp +++ b/test/system_test/main.cpp @@ -62,7 +62,7 @@ int main(int argc, char **argv) { auto matrix = glm::mat4(1.0f); - glm::mat4 scale_matrix = glm::scale(glm::mat4(1.0f), glm::vec3(500.0f, 500.0f, 500.0f)); + glm::mat4 scale_matrix = glm::scale(glm::mat4(1.0f), glm::vec3(10.0f, 10.0f, 10.0f)); // Translation matrix glm::mat4 translation_matrix = glm::translate(glm::mat4(1.0f), glm::vec3(kWidth / 2.0f, kHeight / 2.0f, 0.0f)); @@ -88,7 +88,7 @@ int main(int argc, char **argv) { for (auto &obj : objs) { // 添加到场景中 auto model = simple_renderer::Model(obj); - model = model * matrix; + model.transform(matrix); simple_renderer.render(model); } diff --git a/test/unit_test/matrix_test.cpp b/test/unit_test/matrix_test.cpp index 9cb7543..045f4ba 100644 --- a/test/unit_test/matrix_test.cpp +++ b/test/unit_test/matrix_test.cpp @@ -15,7 +15,7 @@ * */ -#include "matrix.hpp" +#include "log_math.hpp" #include "gtest/gtest.h" From ddb1c296c3305a5fba18608a050418b806522485 Mon Sep 17 00:00:00 2001 From: ZhuohaoHe Date: Thu, 8 Aug 2024 17:13:49 -0400 Subject: [PATCH 11/17] add OpenMP back --- cmake/3rd.cmake | 10 ++++++++++ cmake/compile_config.cmake | 1 + src/simple_renderer.cpp | 2 +- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/cmake/3rd.cmake b/cmake/3rd.cmake index 735c115..7b6c381 100644 --- a/cmake/3rd.cmake +++ b/cmake/3rd.cmake @@ -261,4 +261,14 @@ find_package(assimp REQUIRED) if (NOT assimp_FOUND) message(FATAL_ERROR "assimp not found.\n" "Following https://github.com/assimp/assimp to install.") +endif () + +find_package(OpenMP REQUIRED) +if (APPLE) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L${OPENMP_LIBRARIES} -lomp") +endif () +if (NOT OpenMP_FOUND) + message(FATAL_ERROR "OpenMP not found. Please install OpenMP.") endif () \ No newline at end of file diff --git a/cmake/compile_config.cmake b/cmake/compile_config.cmake index 9a98849..252a9ab 100644 --- a/cmake/compile_config.cmake +++ b/cmake/compile_config.cmake @@ -20,5 +20,6 @@ list(APPEND DEFAULT_LINK_LIB glm::glm ${glog_LIBRARIES} SDL2::SDL2 + OpenMP::OpenMP_CXX assimp ) diff --git a/src/simple_renderer.cpp b/src/simple_renderer.cpp index 7c237c5..93105ab 100755 --- a/src/simple_renderer.cpp +++ b/src/simple_renderer.cpp @@ -61,7 +61,7 @@ bool SimpleRenderer::render(const Model &model) { SPDLOG_INFO("render model: {}", model.modelPath()); auto shader = DefaultShader(); auto light = Light(); - DrawModel(shader, light, model, 0, 1); + DrawModel(shader, light, model, 1, 0); return true; } From 8e7e7a5f643e3497b561994d018d844c0b2c4f89 Mon Sep 17 00:00:00 2001 From: ZhuohaoHe Date: Thu, 8 Aug 2024 17:27:51 -0400 Subject: [PATCH 12/17] update glm CPM version --- cmake/3rd.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/3rd.cmake b/cmake/3rd.cmake index 7b6c381..93ece6f 100644 --- a/cmake/3rd.cmake +++ b/cmake/3rd.cmake @@ -110,6 +110,7 @@ endif () CPMAddPackage( NAME glm GITHUB_REPOSITORY g-truc/glm + VERSION 1.0.1 ) # https://github.com/nothings/stb.git From 5c8b7da9917d76c398a78fd2dcaa8df850af28ec Mon Sep 17 00:00:00 2001 From: ZhuohaoHe Date: Thu, 8 Aug 2024 17:32:10 -0400 Subject: [PATCH 13/17] remove tinyobjloader reference --- cmake/3rd.cmake | 28 +--------------------------- cmake/add_header.cmake | 3 +-- cmake/compile_config.cmake | 1 - src/model.cpp | 3 --- test/system_test/main.cpp | 4 ++-- 5 files changed, 4 insertions(+), 35 deletions(-) diff --git a/cmake/3rd.cmake b/cmake/3rd.cmake index 93ece6f..a8937c5 100644 --- a/cmake/3rd.cmake +++ b/cmake/3rd.cmake @@ -70,16 +70,6 @@ CPMAddPackage( ) find_package(SDL2 REQUIRED) -# # https://github.com/aminosbh/sdl2-cmake-modules.git -# CPMAddPackage( -# NAME sdl2-cmake-modules -# GIT_REPOSITORY https://github.com/aminosbh/sdl2-cmake-modules.git -# DOWNLOAD_ONLY True -# ) - -# if (sdl2-cmake-modules_ADDED) -# list(APPEND CMAKE_MODULE_PATH ${sdl2-cmake-modules_SOURCE_DIR}) -# endif () CPMAddPackage( NAME assimp @@ -91,26 +81,10 @@ CPMAddPackage( "ASSIMP_BUILD_SAMPLES OFF" ) -# https://github.com/tinyobjloader/tinyobjloader.git -CPMAddPackage( - NAME tinyobjloader - GIT_REPOSITORY https://github.com/tinyobjloader/tinyobjloader.git - GIT_TAG 853f059d778058a43c954850e561a231934b33a7 - DOWNLOAD_ONLY True -) -if (tinyobjloader_ADDED) - add_library(tinyobjloader INTERFACE) - target_sources(tinyobjloader INTERFACE - FILE_SET HEADERS - BASE_DIRS ${tinyobjloader_SOURCE_DIR} - FILES tiny_obj_loader.h - ) -endif () - CPMAddPackage( NAME glm GITHUB_REPOSITORY g-truc/glm - VERSION 1.0.1 + GIT_TAG 1.0.1 ) # https://github.com/nothings/stb.git diff --git a/cmake/add_header.cmake b/cmake/add_header.cmake index 0e95eac..54104a8 100644 --- a/cmake/add_header.cmake +++ b/cmake/add_header.cmake @@ -6,6 +6,5 @@ # 将头文件路径添加到 _target 的搜索路径中 function(add_header_3rd _target) - target_include_directories(${_target} PRIVATE - ${tinyobjloader_SOURCE_DIR}) + target_include_directories(${_target} PRIVATE) endfunction() diff --git a/cmake/compile_config.cmake b/cmake/compile_config.cmake index 252a9ab..0cdec5a 100644 --- a/cmake/compile_config.cmake +++ b/cmake/compile_config.cmake @@ -16,7 +16,6 @@ list(APPEND DEFAULT_COMPILE_OPTIONS list(APPEND DEFAULT_LINK_LIB spdlog::spdlog stb - tinyobjloader glm::glm ${glog_LIBRARIES} SDL2::SDL2 diff --git a/src/model.cpp b/src/model.cpp index 5b3986d..1f82d75 100755 --- a/src/model.cpp +++ b/src/model.cpp @@ -23,9 +23,6 @@ #include #include -#define TINYOBJLOADER_IMPLEMENTATION -#include - #include "log_system.h" namespace simple_renderer { diff --git a/test/system_test/main.cpp b/test/system_test/main.cpp index 6797ac6..013382c 100755 --- a/test/system_test/main.cpp +++ b/test/system_test/main.cpp @@ -26,8 +26,8 @@ /// @name 默认大小 /// @{ -static constexpr const size_t kWidth = 1920; -static constexpr const size_t kHeight = 1080; +static constexpr const size_t kWidth = 800; +static constexpr const size_t kHeight = 600; /// @} static void pixel(size_t x, size_t y, uint32_t color, uint32_t *buffer) { From 47c179bd179acd4d5dc37276865ba216542de3b2 Mon Sep 17 00:00:00 2001 From: ZhuohaoHe Date: Thu, 8 Aug 2024 17:40:07 -0400 Subject: [PATCH 14/17] change uppercase to lowercase --- include/{Vertex.hpp => vertex.hpp} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename include/{Vertex.hpp => vertex.hpp} (100%) diff --git a/include/Vertex.hpp b/include/vertex.hpp similarity index 100% rename from include/Vertex.hpp rename to include/vertex.hpp From 6f62069ee8fad8cf8f765df3f03b4da724d71688 Mon Sep 17 00:00:00 2001 From: ZhuohaoHe Date: Fri, 9 Aug 2024 17:17:45 -0400 Subject: [PATCH 15/17] update CMakeLists files and codes according to reviews Signed-off-by: ZhuohaoHe --- CMakeLists.txt | 8 +- CMakePresets.json | 147 ++++++++------- cmake/3rd.cmake | 17 +- include/face.hpp | 51 ----- include/log_math.hpp | 65 ------- include/material.hpp | 22 --- include/model.hpp | 68 ------- include/vertex.hpp | 54 ------ src/CMakeLists.txt | 10 +- src/default_shader.cpp | 11 +- {include => src/include}/color.h | 0 {include => src/include}/config.h | 2 +- {include => src/include}/default_shader.h | 2 +- src/include/face.hpp | 78 ++++++++ {include => src/include}/light.h | 10 +- {include => src/include}/log_system.h | 0 src/include/material.hpp | 39 ++++ src/include/math.hpp | 58 ++++++ src/include/model.hpp | 100 ++++++++++ {include => src/include}/shader_base.h | 24 +-- {include => src/include}/simple_renderer.h | 12 +- src/include/vertex.hpp | 66 +++++++ src/light.cpp | 6 +- src/log_system.cpp | 6 +- src/model.cpp | 209 ++++++++++++--------- src/shader_base.cpp | 12 +- src/simple_renderer.cpp | 62 +++--- test/CMakeLists.txt | 52 ++--- test/system_test/CMakeLists.txt | 2 +- test/system_test/camera.h | 6 +- test/system_test/main.cpp | 22 ++- test/unit_test/matrix_test.cpp | 3 +- 32 files changed, 659 insertions(+), 565 deletions(-) delete mode 100644 include/face.hpp delete mode 100755 include/log_math.hpp delete mode 100644 include/material.hpp delete mode 100755 include/model.hpp delete mode 100644 include/vertex.hpp rename {include => src/include}/color.h (100%) rename {include => src/include}/config.h (95%) rename {include => src/include}/default_shader.h (96%) create mode 100644 src/include/face.hpp rename {include => src/include}/light.h (89%) rename {include => src/include}/log_system.h (100%) create mode 100644 src/include/material.hpp create mode 100644 src/include/math.hpp create mode 100755 src/include/model.hpp rename {include => src/include}/shader_base.h (91%) rename {include => src/include}/simple_renderer.h (91%) create mode 100644 src/include/vertex.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 67725f4..5b5d780 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,8 +7,6 @@ # 设置最小 cmake 版本 cmake_minimum_required(VERSION 3.27 FATAL_ERROR) -set(CMAKE_CXX_STANDARD 20) -set(CMAKE_CXX_STANDARD_REQUIRED True) # 设置项目名与版本 project(SimpleRenderer @@ -42,7 +40,7 @@ set(FONT_FILE_PATH "${wqy_font_SOURCE_DIR}/wqy-zenhei.ttc") include(ProcessorCount) ProcessorCount(NPROC) # 日志文件路径 -set(LOG_FILE_PATH "${PROJECT_SOURCE_DIR}/build/logs/SimpleRendererLog.log") +set(LOG_FILE_PATH "${EXECUTABLE_OUTPUT_PATH}/logs/SimpleRendererLog.log") # 日志文件大小 set(LOG_FILE_MAX_SIZE 1024*1024*4) # 日志文件数量 @@ -50,10 +48,10 @@ set(LOG_FILE_MAX_COUNT 8) # 生成配置头文件 configure_file( "${PROJECT_SOURCE_DIR}/cmake/config.h.in" - "${PROJECT_SOURCE_DIR}/include/config.h" + "${PROJECT_SOURCE_DIR}/src/include/config.h" ) # 添加要编译的目录 add_subdirectory(src) add_subdirectory(test) -add_subdirectory(doc) +add_subdirectory(doc) \ No newline at end of file diff --git a/CMakePresets.json b/CMakePresets.json index cdab07d..6976ac5 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -1,71 +1,84 @@ { - "version": 6, - "cmakeMinimumRequired": { - "major": 3, - "minor": 27, - "patch": 0 - }, - "configurePresets": [ - { - "name": "host", - "description": "Linux Only", - "hidden": true, - "condition": { - "type": "equals", - "lhs": "${hostSystemName}", - "rhs": "Linux" - } - }, - { - "name": "std", - "description": "This preset makes sure the project actually builds with at least the specified standard", - "hidden": true, - "cacheVariables": { - "CMAKE_C_EXTENSIONS": "OFF", - "CMAKE_C_STANDARD": "23", - "CMAKE_C_STANDARD_REQUIRED": "ON", - "CMAKE_CXX_EXTENSIONS": "OFF", - "CMAKE_CXX_STANDARD": "23", - "CMAKE_CXX_STANDARD_REQUIRED": "ON" - } + "version": 6, + "cmakeMinimumRequired": { + "major": 3, + "minor": 23, + "patch": 0 }, - { - "name": "configurePresets_base", - "hidden": true, - "inherits": [ - "host", - "std" - ], - "displayName": "configurePresets_base", - "description": "base configurePresets", - "binaryDir": "${sourceDir}/build", - "cacheVariables": { - "CMAKE_EXPORT_COMPILE_COMMANDS": { - "type": "BOOL", - "value": "ON" - }, - "EXECUTABLE_OUTPUT_PATH": { - "type": "STRING", - "value": "${sourceDir}/build/bin" - }, - "LIBRARY_OUTPUT_PATH": { - "type": "STRING", - "value": "${sourceDir}/build/lib" - }, - "COVERAGE_OUTPUT_DIR": { - "type": "STRING", - "value": "${sourceDir}/build/coverage" + "configurePresets": [ + { + "name": "std", + "description": "This preset makes sure the project actually builds with at least the specified standard", + "hidden": true, + "cacheVariables": { + "CMAKE_C_EXTENSIONS": "OFF", + "CMAKE_C_STANDARD": "23", + "CMAKE_C_STANDARD_REQUIRED": "ON", + "CMAKE_CXX_EXTENSIONS": "OFF", + "CMAKE_CXX_STANDARD": "23", + "CMAKE_CXX_STANDARD_REQUIRED": "ON" } + }, + { + "name": "config-base", + "hidden": true, + "inherits": [ "std" ], + "displayName": "config-base", + "description": "base configurePresets", + "binaryDir": "${sourceDir}/build", + "cacheVariables": { + "CMAKE_EXPORT_COMPILE_COMMANDS": { + "type": "BOOL", + "value": "ON" + }, + "EXECUTABLE_OUTPUT_PATH": { + "type": "STRING", + "value": "${sourceDir}/build/bin" + }, + "LIBRARY_OUTPUT_PATH": { + "type": "STRING", + "value": "${sourceDir}/build/lib" + }, + "COVERAGE_OUTPUT_DIR": { + "type": "STRING", + "value": "${sourceDir}/build/coverage" + } + } + }, + { + "name": "config-macos", + "hidden": true, + "inherits": [ "config-base" ], + "displayName": "config-base", + "description": "macOS configurePresets", + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Darwin" + }, + "cacheVariables": { + "CMAKE_MACOSX_RPATH": "1", + "CMAKE_INSTALL_RPATH": "/Library/Frameworks", + "CMAKE_BUILD_WITH_INSTALL_RPATH": "TRUE" + } + }, + { + "name": "build", + "hidden": false, + "inherits": [ + "config-base" + ], + "displayName": "build-base", + "description": "build base configurePresets" + }, + { + "name": "build-macos", + "hidden": false, + "inherits": [ + "config-macos" + ], + "displayName": "build-macos", + "description": "macOS build configurePresets" } - }, - { - "name": "build", - "hidden": false, - "inherits": [ - "configurePresets_base" - ], - "displayName": "build", - "description": "build" - } - ] -} \ No newline at end of file + ] + } \ No newline at end of file diff --git a/cmake/3rd.cmake b/cmake/3rd.cmake index a8937c5..7c06507 100644 --- a/cmake/3rd.cmake +++ b/cmake/3rd.cmake @@ -56,7 +56,7 @@ CPMAddPackage( "gtest_force_shared_crt ON" ) -# SDL2 +# https://github.com/libsdl-org/SDL CPMAddPackage( NAME SDL2 GITHUB_REPOSITORY libsdl-org/SDL @@ -68,8 +68,6 @@ CPMAddPackage( "SDL_STATIC_PIC ON" "SDL_WERROR OFF" ) -find_package(SDL2 REQUIRED) - CPMAddPackage( NAME assimp @@ -81,6 +79,7 @@ CPMAddPackage( "ASSIMP_BUILD_SAMPLES OFF" ) +# https://github.com/g-truc/glm CPMAddPackage( NAME glm GITHUB_REPOSITORY g-truc/glm @@ -214,24 +213,12 @@ if (NOT LCOV_EXE) "Following https://github.com/linux-test-project/lcov to install.") endif () -find_package(SDL2 REQUIRED) -if (NOT SDL2_FOUND) - message(FATAL_ERROR "sdl2 not found.\n" - "Following https://github.com/libsdl-org/SDL to install.") -endif () - find_package(spdlog REQUIRED) if (NOT spdlog_FOUND) message(FATAL_ERROR "spdlog not found.\n" "Following https://github.com/gabime/spdlog to install.") endif () -find_package(glm REQUIRED) -if (NOT glm_FOUND) - message(FATAL_ERROR "glm not found.\n" - "Following https://github.com/g-truc/glm tp install") -endif () - find_package(assimp REQUIRED) if (NOT assimp_FOUND) message(FATAL_ERROR "assimp not found.\n" diff --git a/include/face.hpp b/include/face.hpp deleted file mode 100644 index febb23d..0000000 --- a/include/face.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include "vertex.hpp" -#include "material.hpp" - -#include - -namespace simple_renderer { - -class Face { -public: - // Default constructor - Face() = default; - // Copy constructor - Face(const Face& face) = default; - Face& operator=(const Face& face) = default; - // Move constructor - Face(Face&& face) = default; - Face& operator=(Face&& face) = default; - // Destructor - ~Face() = default; - - explicit Face(const Vertex& v0, const Vertex& v1, const Vertex& v2, Material material) - : vertices_{v0, v1, v2}, material_(std::move(material)) { - calculateNormal(); - } - - void transform(const glm::mat4 &tran) { - vertices_[0].transform(tran); - vertices_[1].transform(tran); - vertices_[2].transform(tran); - } - - const std::array& vertices() const { return vertices_; } - const Vertex& vertex(size_t index) const { return vertices_[index]; } - const glm::vec3& normal() const { return normal_; } - const Material& material() const { return material_; } - -private: - std::array vertices_; - glm::vec3 normal_; - Material material_; - - void calculateNormal() { - glm::vec3 edge1 = glm::vec3(vertices_[1].position()) - glm::vec3(vertices_[0].position()); - glm::vec3 edge2 = glm::vec3(vertices_[2].position()) - glm::vec3(vertices_[0].position()); - normal_ = glm::normalize(glm::cross(edge1, edge2)); - } -}; - -} \ No newline at end of file diff --git a/include/log_math.hpp b/include/log_math.hpp deleted file mode 100755 index 0f86926..0000000 --- a/include/log_math.hpp +++ /dev/null @@ -1,65 +0,0 @@ - -/** - * @file matrix.hpp - * @brief 矩阵 - * @author Zone.N (Zone.Niuzh@hotmail.com) - * @version 1.0 - * @date 2022-09-07 - * @copyright MIT LICENSE - * https://github.com/Simple-XX/SimpleRenderer - * @par change log: - * - *
DateAuthorDescription - *
2022-09-07Zone.N迁移到 doxygen - *
- */ - -#ifndef SIMPLERENDER_SRC_INCLUDE_MATRIX_HPP_ -#define SIMPLERENDER_SRC_INCLUDE_MATRIX_HPP_ - -#define GLM_ENABLE_EXPERIMENTAL -#include - -#include "log_system.h" - -/** - * spdlog 输出 Vector3f 实现 - */ -template <> -struct fmt::formatter : fmt::formatter { - auto format(const glm::vec3 &vector, fmt::format_context &ctx) const -> decltype(ctx.out()) { - std::string vector_string = glm::to_string(vector); - - // Format and output the string - return fmt::format_to(ctx.out(), "\n{}", vector_string); - } -}; - -/** - * spdlog 输出 Vector4f 实现 - */ -template <> -struct fmt::formatter : fmt::formatter { - auto format(const glm::vec4 &vector, fmt::format_context &ctx) const -> decltype(ctx.out()) { - std::string vector_string = glm::to_string(vector); - - // Format and output the string - return fmt::format_to(ctx.out(), "\n{}", vector_string); - } -}; - -/** - * spdlog 输出矩阵实现 - */ -template <> -struct fmt::formatter : fmt::formatter { - auto format(const glm::mat4 &matrix, fmt::format_context &ctx) const -> decltype(ctx.out()) { - // Convert the glm::mat4 to a string using glm::to_string - std::string matrix_str = glm::to_string(matrix); - - // Format and output the string - return fmt::format_to(ctx.out(), "\n{}", matrix_str); - } -}; - -#endif /* SIMPLERENDER_SRC_INCLUDE_MATRIX_HPP_ */ diff --git a/include/material.hpp b/include/material.hpp deleted file mode 100644 index ed489d1..0000000 --- a/include/material.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include - -class Material { -public: - // Default constructor - Material() = default; - // Copy constructor - Material(const Material& material) = default; - Material& operator=(const Material& material) = default; - // Move constructor - Material(Material&& material) = default; - Material& operator=(Material&& material) = default; - // Destructor - ~Material() = default; - - float shininess = 0.0f; - glm::vec3 ambient; - glm::vec3 diffuse; - glm::vec3 specular; -}; \ No newline at end of file diff --git a/include/model.hpp b/include/model.hpp deleted file mode 100755 index 3266c1c..0000000 --- a/include/model.hpp +++ /dev/null @@ -1,68 +0,0 @@ - -/** - * @file model.hpp - * @brief 模型抽象 - * @author Zone.N (Zone.Niuzh@hotmail.com) - * @version 1.0 - * @date 2022-06-06 - * @copyright MIT LICENSE - * https://github.com/Simple-XX/SimpleRenderer - * @par change log: - * - *
DateAuthorDescription - *
2022-09-04Zone.N迁移到 doxygen - *
- */ - -#ifndef SIMPLERENDER_SRC_INCLUDE_MODEL_HPP_ -#define SIMPLERENDER_SRC_INCLUDE_MODEL_HPP_ - -#include - -#include -#include - -#include "color.h" -#include "config.h" -#include "log_system.h" -#include "log_math.hpp" - -#include "vertex.hpp" -#include "face.hpp" - -namespace simple_renderer { - -class Model { -public: - - // Default constructor - Model() = default; - // Default copy constructor - Model(const Model& model) = default; - Model& operator=(const Model& model) = default; - // Default move constructor - Model(Model&& model) = default; - Model& operator=(Model&& model) = default; - ~Model() = default; - - Model(const std::string &model_path); - - void transform(const glm::mat4 &tran); - - const std::vector& faces() const { return faces_; }; - const std::string& modelPath() const { return directory_; }; - -private: - static constexpr const uint8_t kTriangleFaceVertexCount = 3; - std::string directory_; - - std::vector faces_; - - void loadModel(const std::string& path); - void processNode(aiNode* node, const aiScene* scene); - void processMesh(aiMesh* mesh, const aiScene* scene); - Material processMaterial(aiMaterial* material); -}; -} // namespace simple_renderer - -#endif /* SIMPLERENDER_SRC_INCLUDE_MODEL_HPP_ */ \ No newline at end of file diff --git a/include/vertex.hpp b/include/vertex.hpp deleted file mode 100644 index 2b74460..0000000 --- a/include/vertex.hpp +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -#include - -#include "color.h" - -namespace simple_renderer { - -class Vertex { -public: - - // Default constructor - Vertex() = default; - // Copy constructor - Vertex(const Vertex& vertex) = default; - Vertex& operator=(const Vertex& vertex) = default; - // Move constructor - Vertex(Vertex&& vertex) = default; - Vertex& operator=(Vertex&& vertex) = default; - // Destructor - ~Vertex() = default; - - // Constructor with parameters - explicit Vertex(const glm::vec4& pos, const glm::vec3& norm, const glm::vec2& tex, const Color& color_) - : position_(pos), normal_(norm), texCoords_(tex), color_(color_) {} - - // Transform the vertex with a matrix - void transform(const glm::mat4& matrix) { - position_ = matrix * position_; - } - - // Perspective divide to convert from clip space to normalized device coordinates - void perspectiveDivide() { - if (position_.w != 0) { - position_.x /= position_.w; - position_.y /= position_.w; - position_.z /= position_.w; - position_.w = 1.0f; // Homogenize - } - } - - glm::vec4 position() const { return position_; } - glm::vec3 normal() const { return normal_; } - glm::vec2 texCoords() const { return texCoords_; } - Color color() const { return color_; } - -private: - glm::vec4 position_; // Position of the vertex in homogenous coordinates - glm::vec3 normal_; // Normal vector for the vertex - glm::vec2 texCoords_; // Texture coordinates - Color color_; // Color of the vertex -}; - -} \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 912ee68..5b4fe72 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -12,14 +12,14 @@ file(GLOB_RECURSE SRC_FILES CONFIGURE_DEPENDS add_library(${PROJECT_NAME} STATIC ${SRC_FILES}) target_include_directories(${PROJECT_NAME} PRIVATE - $ - $ + $ + $ ) target_compile_options(${PROJECT_NAME} PRIVATE - ${DEFAULT_COMPILE_OPTIONS} + ${DEFAULT_COMPILE_OPTIONS} ) target_link_libraries(${PROJECT_NAME} PRIVATE - ${DEFAULT_LINK_LIB} -) + ${DEFAULT_LINK_LIB} +) \ No newline at end of file diff --git a/src/default_shader.cpp b/src/default_shader.cpp index 5c8065a..ba1c34e 100644 --- a/src/default_shader.cpp +++ b/src/default_shader.cpp @@ -20,7 +20,7 @@ namespace simple_renderer { auto DefaultShader::InterpolateColor( const Color &color0, const Color &color1, const Color &color2, - const glm::vec3 &barycentric_coord) -> Color { + const Vector3f &barycentric_coord) -> Color { return Color( static_cast(static_cast(color0[Color::kColorIndexRed]) * barycentric_coord.x + @@ -47,10 +47,8 @@ auto DefaultShader::Vertex(const ShaderVertexIn &shader_vertex_in) const -> ShaderVertexOut { auto face(shader_vertex_in.face_); - face.transform( - shader_data_.project_matrix_ - * shader_data_.view_matrix_ - * shader_data_.model_matrix_); + face.transform(shader_data_.project_matrix_ * shader_data_.view_matrix_ * + shader_data_.model_matrix_); /// @todo 变换贴图 return ShaderVertexOut(face); @@ -58,7 +56,8 @@ auto DefaultShader::Vertex(const ShaderVertexIn &shader_vertex_in) const auto DefaultShader::Fragment(const ShaderFragmentIn &shader_fragment_in) const -> ShaderFragmentOut { - auto intensity = glm::dot(shader_fragment_in.normal_,shader_fragment_in.light_); + auto intensity = + glm::dot(shader_fragment_in.normal_, shader_fragment_in.light_); auto is_need_draw = true; // 光照方向为正,不绘制背面 if (intensity <= 0) { diff --git a/include/color.h b/src/include/color.h similarity index 100% rename from include/color.h rename to src/include/color.h diff --git a/include/config.h b/src/include/config.h similarity index 95% rename from include/config.h rename to src/include/config.h index 9427427..fcc39ed 100644 --- a/include/config.h +++ b/src/include/config.h @@ -27,7 +27,7 @@ static constexpr const size_t kNProc = 8; /// 日志文件路径 static const std::string kLogFilePath = - std::string("/Users/hezhohao/Programming/GitRepo/SimpleRenderer/build/logs/SimpleRendererLog.log"); + std::string("/Users/hezhohao/Programming/GitRepo/SimpleRenderer/build/bin/logs/SimpleRendererLog.log"); /// 日志文件大小 static constexpr const size_t kLogFileMaxSize = 1024*1024*4; /// 日志文件数量 diff --git a/include/default_shader.h b/src/include/default_shader.h similarity index 96% rename from include/default_shader.h rename to src/include/default_shader.h index a187577..717c802 100644 --- a/include/default_shader.h +++ b/src/include/default_shader.h @@ -64,7 +64,7 @@ class DefaultShader : public ShaderBase { */ static auto InterpolateColor(const Color &color0, const Color &color1, const Color &color2, - const glm::vec3 &barycentric_coord) -> Color; + const Vector3f &barycentric_coord) -> Color; }; } // namespace simple_renderer diff --git a/src/include/face.hpp b/src/include/face.hpp new file mode 100644 index 0000000..1c0e16f --- /dev/null +++ b/src/include/face.hpp @@ -0,0 +1,78 @@ +#pragma once + +#include + +#include "material.hpp" +#include "vertex.hpp" + +namespace simple_renderer { + +class Face { + public: + // Default constructor + // 默认构造函数 + Face() = default; + + // Copy constructor + // 拷贝构造函数 + Face(const Face& face) = default; + // Copy assignment operator + // 拷贝赋值操作符 + Face& operator=(const Face& face) = default; + + // Move constructor + // 移动构造函数 + Face(Face&& face) = default; + // Move assignment operator + // 移动赋值操作符 + Face& operator=(Face&& face) = default; + + // Destructor + // 析构函数 + ~Face() = default; + + // Constructor that initializes the Face with three vertices and a material + // 使用三个顶点和材质初始化 Face 的构造函数 + explicit Face(const Vertex& v0, const Vertex& v1, const Vertex& v2, + Material material) + : vertices_{v0, v1, v2}, material_(std::move(material)) { + // Calculate the normal vector when the face is created + // 创建 Face 时计算法向量 + calculateNormal(); + } + + // Apply a transformation matrix to the vertices + // 对顶点应用变换矩阵 + void transform(const Matrix4f& tran) { + vertices_[0].transform(tran); + vertices_[1].transform(tran); + vertices_[2].transform(tran); + } + + // Get functions + // 获取函数 + const std::array& vertices() const { return vertices_; } + const Vertex& vertex(size_t index) const { return vertices_[index]; } + const Vector3f& normal() const { return normal_; } + const Material& material() const { return material_; } + + private: + std::array vertices_; + Vector3f normal_; + Material material_; + + // Calculate the normal vector based on the vertices + // 根据顶点计算法向量 + void calculateNormal() { + Vector3f edge1 = + Vector3f(vertices_[1].position()) - Vector3f(vertices_[0].position()); + Vector3f edge2 = + Vector3f(vertices_[2].position()) - Vector3f(vertices_[0].position()); + normal_ = glm::normalize( + // Normalize the cross product to get the + // normal 归一化叉积以获得法向量 + glm::cross(edge1, edge2)); + } +}; + +} // namespace simple_renderer diff --git a/include/light.h b/src/include/light.h similarity index 89% rename from include/light.h rename to src/include/light.h index 52b6964..81fde8e 100644 --- a/include/light.h +++ b/src/include/light.h @@ -21,7 +21,7 @@ #include #include "color.h" -#include "log_math.hpp" +#include "math.hpp" namespace simple_renderer { @@ -33,9 +33,9 @@ class Light { /// 光照名称 std::string name_ = "default light name"; /// 位置 - glm::vec3 pos = kDefaultPos; + Vector3f pos = kDefaultPos; /// 方向 - glm::vec3 dir = kDefaultDir; + Vector3f dir = kDefaultDir; /// 颜色 Color color = kDefaultColor; @@ -57,9 +57,9 @@ class Light { private: /// 默认位置 - static const glm::vec3 kDefaultPos; + static const Vector3f kDefaultPos; /// 默认方向,左手系,x 向右,y 向下,z 正方向为屏幕由内向外 - static const glm::vec3 kDefaultDir; + static const Vector3f kDefaultDir; /// 默认颜色 static const Color kDefaultColor; }; diff --git a/include/log_system.h b/src/include/log_system.h similarity index 100% rename from include/log_system.h rename to src/include/log_system.h diff --git a/src/include/material.hpp b/src/include/material.hpp new file mode 100644 index 0000000..cc4cece --- /dev/null +++ b/src/include/material.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include + +namespace simple_renderer { + +class Material { + public: + // Default constructor + // 默认构造函数 + Material() = default; + + // Copy constructor + // 拷贝构造函数 + Material(const Material& material) = default; + + // Copy assignment operator + // 拷贝赋值操作符 + Material& operator=(const Material& material) = default; + + // Move constructor + // 移动构造函数 + Material(Material&& material) = default; + + // Move assignment operator + // 移动赋值操作符 + Material& operator=(Material&& material) = default; + + // Destructor + // 析构函数 + ~Material() = default; + + float shininess = 0.0f; + Vector3f ambient; + Vector3f diffuse; + Vector3f specular; +}; + +} // namespace simple_renderer \ No newline at end of file diff --git a/src/include/math.hpp b/src/include/math.hpp new file mode 100644 index 0000000..eb7d3f2 --- /dev/null +++ b/src/include/math.hpp @@ -0,0 +1,58 @@ +#pragma once + +#include + +#define GLM_ENABLE_EXPERIMENTAL +#include + +#include "log_system.h" + +namespace simple_renderer { +using Vector2f = glm::vec2; +using Vector3f = glm::vec3; +using Vector4f = glm::vec4; +using Matrix4f = glm::mat4; +} // namespace simple_renderer + +/** + * spdlog 输出 Vector3f 实现 + */ +template <> +struct fmt::formatter : fmt::formatter { + auto format(const simple_renderer::Vector3f &vector, + fmt::format_context &ctx) const -> decltype(ctx.out()) { + std::string vector_string = glm::to_string(vector); + + // Format and output the string + return fmt::format_to(ctx.out(), "\n{}", vector_string); + } +}; + +/** + * spdlog 输出 Vector4f 实现 + */ +template <> +struct fmt::formatter : fmt::formatter { + auto format(const simple_renderer::Vector4f &vector, + fmt::format_context &ctx) const -> decltype(ctx.out()) { + std::string vector_string = glm::to_string(vector); + + // Format and output the string + return fmt::format_to(ctx.out(), "\n{}", vector_string); + } +}; + +/** + * spdlog 输出矩阵实现 + */ +template <> +struct fmt::formatter : fmt::formatter { + auto format(const simple_renderer::Matrix4f &matrix, + fmt::format_context &ctx) const -> decltype(ctx.out()) { + // Convert the Matrix4f to a string using glm::to_string + std::string matrix_str = glm::to_string(matrix); + + // Format and output the string + return fmt::format_to(ctx.out(), "\n{}", matrix_str); + } +}; diff --git a/src/include/model.hpp b/src/include/model.hpp new file mode 100755 index 0000000..de8924b --- /dev/null +++ b/src/include/model.hpp @@ -0,0 +1,100 @@ + +/** + * @file model.hpp + * @brief 模型抽象 + * @author Zone.N (Zone.Niuzh@hotmail.com) + * @version 1.0 + * @date 2022-06-06 + * @copyright MIT LICENSE + * https://github.com/Simple-XX/SimpleRenderer + * @par change log: + * + *
DateAuthorDescription + *
2022-09-04Zone.N迁移到 doxygen + *
+ */ + +#ifndef SIMPLERENDER_SRC_INCLUDE_MODEL_HPP_ +#define SIMPLERENDER_SRC_INCLUDE_MODEL_HPP_ + +#include + +#include +#include + +#include "color.h" +#include "config.h" +#include "face.hpp" +#include "log_system.h" +#include "math.hpp" +#include "vertex.hpp" + +namespace simple_renderer { + +class Model { + public: + // Default constructor + // 默认构造函数 + Model() = default; + + // Default copy constructor + // 默认拷贝构造函数 + Model(const Model& model) = default; + // Default copy assignment operator + // 默认拷贝赋值运算符 + Model& operator=(const Model& model) = default; + + // Default move constructor + // 默认移动构造函数 + Model(Model&& model) = default; + // Default move assignment operator + // 默认移动赋值运算符 + Model& operator=(Model&& model) = default; + + // Destructor + // 析构函数 + ~Model() = default; + + // Constructor that loads a model from a file path + // 从文件路径加载模型的构造函数 + Model(const std::string& model_path); + + // Apply a transformation to the model + // 对模型应用变换 + void transform(const Matrix4f& tran); + + // Get functions + // 获取函数 + const std::vector& faces() const { return faces_; }; + const std::string& modelPath() const { return directory_; }; + + private: + // Number of vertices per triangle face + // 每个三角形面的顶点数 + static constexpr const uint8_t kTriangleFaceVertexCount = 3; + // Directory where the model is located + // 模型所在的目录 + std::string directory_; + // List of faces(triangles) that make up the model + // 构成模型的面(三角形)列表 + std::vector faces_; + + // Load the model from the specified file path + // 从指定的文件路径加载模型 + void loadModel(const std::string& path); + + // Process a node in the model + // 处理模型中的一个节点 + void processNode(aiNode* node, const aiScene* scene); + + // Process a mesh in the model + // 处理模型中的一个网格 + void processMesh(aiMesh* mesh, const aiScene* scene); + + // Process the material of the model + // 处理模型的材质 + Material processMaterial(aiMaterial* material); +}; +} // namespace simple_renderer + +#endif /* SIMPLERENDER_SRC_INCLUDE_MODEL_HPP_ */ \ No newline at end of file diff --git a/include/shader_base.h b/src/include/shader_base.h similarity index 91% rename from include/shader_base.h rename to src/include/shader_base.h index e2b7b0c..9f69382 100644 --- a/include/shader_base.h +++ b/src/include/shader_base.h @@ -17,8 +17,8 @@ #ifndef SIMPLERENDER_SRC_INCLUDE_SHADER_BASE_H_ #define SIMPLERENDER_SRC_INCLUDE_SHADER_BASE_H_ +#include "math.hpp" #include "model.hpp" -#include "log_math.hpp" namespace simple_renderer { @@ -55,7 +55,7 @@ class ShaderVertexIn { class ShaderVertexOut { public: /// 面信息 - Face face_; + Face face_; /** * 构造函数 @@ -82,11 +82,11 @@ class ShaderVertexOut { class ShaderFragmentIn { public: /// 重心坐标 - glm::vec3 barycentric_coord_; + Vector3f barycentric_coord_; /// 法线方向 - glm::vec3 normal_; + Vector3f normal_; /// 光照方向 - glm::vec3 light_; + Vector3f light_; /// @name 三个顶点的颜色 /// @{ @@ -104,8 +104,8 @@ class ShaderFragmentIn { * @param color1 顶点 1 颜色 * @param color2 顶点 2 颜色 */ - explicit ShaderFragmentIn(const glm::vec3 &_barycentric_coord, - const glm::vec3 &_normal, const glm::vec3 &_light, + explicit ShaderFragmentIn(const Vector3f &_barycentric_coord, + const Vector3f &_normal, const Vector3f &_light, const Color &_color0, const Color &_color1, const Color &_color2); @@ -159,11 +159,11 @@ class ShaderFragmentOut { class ShaderData { public: /// 模型变换矩阵 - glm::mat4 model_matrix_ = glm::mat4(1.0f); + Matrix4f model_matrix_ = Matrix4f(1.0f); /// 视图变换矩阵 - glm::mat4 view_matrix_ = glm::mat4(1.0f); + Matrix4f view_matrix_ = Matrix4f(1.0f); /// 正交变换矩阵 - glm::mat4 project_matrix_ = glm::mat4(1.0f); + Matrix4f project_matrix_ = Matrix4f(1.0f); /** * 构造函数 @@ -171,8 +171,8 @@ class ShaderData { * @param view_matrix 视图变换矩阵 * @param project_matrix 正交变换矩阵 */ - explicit ShaderData(const glm::mat4 &model_matrix, const glm::mat4 &view_matrix, - const glm::mat4 &project_matrix); + explicit ShaderData(const Matrix4f &model_matrix, const Matrix4f &view_matrix, + const Matrix4f &project_matrix); /// @name 默认构造/析构函数 /// @{ diff --git a/include/simple_renderer.h b/src/include/simple_renderer.h similarity index 91% rename from include/simple_renderer.h rename to src/include/simple_renderer.h index 3fc6bed..44e2ca6 100755 --- a/include/simple_renderer.h +++ b/src/include/simple_renderer.h @@ -23,9 +23,9 @@ #include "light.h" #include "log_system.h" +#include "math.hpp" #include "model.hpp" #include "shader_base.h" -#include "log_math.hpp" namespace simple_renderer { @@ -90,7 +90,7 @@ class SimpleRenderer { * @todo 多线程支持 */ void DrawTriangle(const ShaderBase &shader, const Light &light, - const glm::vec3 &normal, const Face &face); + const Vector3f &normal, const Face &face); /** * 绘制模型 @@ -127,9 +127,9 @@ class SimpleRenderer { * weight_B = s * weight_C = t */ - static auto GetBarycentricCoord(const glm::vec3 &p0, const glm::vec3 &p1, - const glm::vec3 &p2, const glm::vec3 &pa) - -> std::pair; + static auto GetBarycentricCoord(const Vector3f &p0, const Vector3f &p1, + const Vector3f &p2, const Vector3f &pa) + -> std::pair; /** * 深度插值,由重心坐标计算出对应点的深度值 @@ -140,7 +140,7 @@ class SimpleRenderer { * @return 深度值 */ static auto InterpolateDepth(float depth0, float depth1, float depth2, - const glm::vec3 &barycentric_coord) -> float; + const Vector3f &barycentric_coord) -> float; }; } // namespace simple_renderer diff --git a/src/include/vertex.hpp b/src/include/vertex.hpp new file mode 100644 index 0000000..1cd3084 --- /dev/null +++ b/src/include/vertex.hpp @@ -0,0 +1,66 @@ +#pragma once + +#include + +#include "color.h" + +namespace simple_renderer { + +class Vertex { + public: + // Default constructor + // 默认构造函数 + Vertex() = default; + + // Copy constructor + // 拷贝构造函数 + Vertex(const Vertex& vertex) = default; + // Copy assignment operator + // 拷贝赋值操作符 + Vertex& operator=(const Vertex& vertex) = default; + + // Move constructor + // 移动构造函数 + Vertex(Vertex&& vertex) = default; + // Move assignment operator + // 移动赋值操作符 + Vertex& operator=(Vertex&& vertex) = default; + + // Destructor + // 析构函数 + ~Vertex() = default; + + // Constructor with parameters 带参数的构造函数 + explicit Vertex(const Vector4f& pos, const Vector3f& norm, + const Vector2f& tex, const Color& color_) + : position_(pos), normal_(norm), texCoords_(tex), color_(color_) {} + + // Transform the vertex with a matrix 使用矩阵变换顶点 + void transform(const Matrix4f& matrix) { position_ = matrix * position_; } + + // Perspective divide to convert from clip space to normalized device + // coordinates 透视除法,将裁剪空间转换为标准化设备坐标 + void perspectiveDivide() { + if (position_.w != 0) { + position_.x /= position_.w; + position_.y /= position_.w; + position_.z /= position_.w; + position_.w = 1.0f; // Homogenize, 齐次坐标 + } + } + + // Get functions + // 获取函数 + Vector4f position() const { return position_; } + Vector3f normal() const { return normal_; } + Vector2f texCoords() const { return texCoords_; } + Color color() const { return color_; } + + private: + Vector4f position_; // 3D position, 3D顶点坐标 + Vector3f normal_; // Normal vector, 顶点法向量 + Vector2f texCoords_; // Texture coordinates, 顶点纹理坐标 + Color color_; +}; + +} // namespace simple_renderer \ No newline at end of file diff --git a/src/light.cpp b/src/light.cpp index 0686703..f25fb4c 100644 --- a/src/light.cpp +++ b/src/light.cpp @@ -18,12 +18,12 @@ #include "color.h" #include "log_system.h" -#include "log_math.hpp" +#include "math.hpp" namespace simple_renderer { -const glm::vec3 Light::kDefaultPos = glm::vec3(0, 0, 0); -const glm::vec3 Light::kDefaultDir = glm::vec3(0, 0, -1); +const Vector3f Light::kDefaultPos = Vector3f(0, 0, 0); +const Vector3f Light::kDefaultDir = Vector3f(0, 0, -1); const Color Light::kDefaultColor = Color::kWhite; Light::Light(const std::string &name) : name_(name) { diff --git a/src/log_system.cpp b/src/log_system.cpp index 6c81b14..e6e7218 100755 --- a/src/log_system.cpp +++ b/src/log_system.cpp @@ -16,20 +16,20 @@ #include "log_system.h" -#include - #include #include #include #include #include +#include + namespace simple_renderer { LogSystem::LogSystem(const std::string &log_file_path, size_t lig_file_max_size, size_t log_file_max_count) { spdlog::init_thread_pool(65536, 1); -// std::string log_file_paths = "./logs/simple_renderer.log"; + // std::string log_file_paths = "./logs/simple_renderer.log"; auto stdout_sink = std::make_shared(); auto rotating_sink = std::make_shared( log_file_path, lig_file_max_size, log_file_max_count); diff --git a/src/model.cpp b/src/model.cpp index 1f82d75..53b8bac 100755 --- a/src/model.cpp +++ b/src/model.cpp @@ -1,7 +1,6 @@ - /** * @file model.cpp - * @brief 模型抽象 + * @brief Model abstraction (模型抽象) * @author Zone.N (Zone.Niuzh@hotmail.com) * @version 1.0 * @date 2022-06-06 @@ -15,126 +14,148 @@ */ #include "model.hpp" -#include - -#include -#include #include #include +#include +#include +#include + #include "log_system.h" namespace simple_renderer { +// Constructor that loads a model from a file path +// 构造函数从文件路径加载模型 +Model::Model(const std::string& model_path) { loadModel(model_path); } -Model::Model(const std::string &model_path) { - loadModel(model_path); -} - +// Load the model using Assimp and process its nodes and meshes +// 使用 Assimp 加载模型并处理其节点和网格 void Model::loadModel(const std::string& path) { - Assimp::Importer importer; - const aiScene* scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs); - - if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) { - SPDLOG_ERROR("Assimp Error: {}", importer.GetErrorString()); - throw std::runtime_error("Failed to load model with Assimp"); - } - - directory_ = path.substr(0, path.find_last_of('/')); - - SPDLOG_INFO("Loaded model path: {}, Directory: {}, with meshes: {}, materials: {}", path, directory_, scene->mNumMeshes, scene->mNumMaterials); - - processNode(scene->mRootNode, scene); + Assimp::Importer importer; + const aiScene* scene = + importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs); + + // Check for errors in loading the model + // 检查加载模型时的错误 + if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || + !scene->mRootNode) { + SPDLOG_ERROR("Assimp Error: {}", importer.GetErrorString()); + throw std::runtime_error("Failed to load model with Assimp"); + } + + // Store the directory path of the model + // 存储模型的目录路径 + directory_ = path.substr(0, path.find_last_of('/')); + + SPDLOG_INFO( + "Loaded model path: {}, Directory: {}, with meshes: {}, materials: {}", + path, directory_, scene->mNumMeshes, scene->mNumMaterials); + + // Process the root node recursively + // 递归处理根节点 + processNode(scene->mRootNode, scene); } +// Recursively process nodes in the model +// 递归处理模型中的节点 void Model::processNode(aiNode* node, const aiScene* scene) { - for (unsigned int i = 0; i < node->mNumMeshes; i++) { - aiMesh* mesh = scene->mMeshes[node->mMeshes[i]]; - processMesh(mesh, scene); - } - - for (unsigned int i = 0; i < node->mNumChildren; i++) { - processNode(node->mChildren[i], scene); - } + // Process each mesh in the node + // 处理节点中的每个网格 + for (unsigned int i = 0; i < node->mNumMeshes; i++) { + aiMesh* mesh = scene->mMeshes[node->mMeshes[i]]; + processMesh(mesh, scene); + } + + // Recursively process each child node + // 递归处理每个子节点 + for (unsigned int i = 0; i < node->mNumChildren; i++) { + processNode(node->mChildren[i], scene); + } } +// Process a single mesh and extract vertices, normals, and faces +// 处理单个网格并提取顶点、法线和面 void Model::processMesh(aiMesh* mesh, const aiScene* scene) { - std::vector vertices; - - // Process vertices - for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { - glm::vec3 position( - mesh->mVertices[i].x, - mesh->mVertices[i].y, - mesh->mVertices[i].z - ); - glm::vec3 normal( - mesh->mNormals[i].x, - mesh->mNormals[i].y, - mesh->mNormals[i].z - ); - glm::vec2 texCoords(0.0f, 0.0f); - if (mesh->mTextureCoords[0]) { // Check if the mesh contains texture coordinates - texCoords = glm::vec2( - mesh->mTextureCoords[0][i].x, - mesh->mTextureCoords[0][i].y - ); - } - - Color color(255.f, 255.f, 255.f, 255.f); - - vertices.emplace_back(glm::vec4(position, 1.0f), normal, texCoords, color); + std::vector vertices; + + // Process vertices + // 处理顶点 + for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { + Vector3f position(mesh->mVertices[i].x, mesh->mVertices[i].y, + mesh->mVertices[i].z); + Vector3f normal(mesh->mNormals[i].x, mesh->mNormals[i].y, + mesh->mNormals[i].z); + Vector2f texCoords(0.0f, 0.0f); + // Check if the mesh has texture coordinates + // 检查网格是否有纹理坐标 + if (mesh->mTextureCoords[0]) { + texCoords = + Vector2f(mesh->mTextureCoords[0][i].x, mesh->mTextureCoords[0][i].y); } - // Process faces (assuming triangulation, so each face has 3 vertices) - for (unsigned int i = 0; i < mesh->mNumFaces; ++i) { - aiFace face = mesh->mFaces[i]; - if (face.mNumIndices == 3) { // Ensure we are working with triangles - Vertex v0 = vertices[face.mIndices[0]]; - Vertex v1 = vertices[face.mIndices[1]]; - Vertex v2 = vertices[face.mIndices[2]]; - - Material material = processMaterial(scene->mMaterials[mesh->mMaterialIndex]); - - faces_.emplace_back(v0, v1, v2, std::move(material)); - } + + Color color(255.f, 255.f, 255.f, 255.f); // Default color (white) + // 默认颜色(白色) + + vertices.emplace_back(Vector4f(position, 1.0f), normal, texCoords, color); + } + + // Process faces (assuming triangulation, so each face has 3 vertices) + // 处理面(假设三角化,因此每个面有3个顶点) + for (unsigned int i = 0; i < mesh->mNumFaces; ++i) { + aiFace face = mesh->mFaces[i]; + if (face.mNumIndices == 3) { // Triangle, 三角形 + Vertex v0 = vertices[face.mIndices[0]]; + Vertex v1 = vertices[face.mIndices[1]]; + Vertex v2 = vertices[face.mIndices[2]]; + + // Process the material associated with this mesh + // 处理与此网格关联的材质 + Material material = + processMaterial(scene->mMaterials[mesh->mMaterialIndex]); + + // Create a Face object and store it + // 创建一个 Face 对象并存储它 + faces_.emplace_back(v0, v1, v2, std::move(material)); } + } } +// Extract material properties from the Assimp material structure +// 从 Assimp 材质结构中提取材质属性 Material Model::processMaterial(aiMaterial* mat) { - Material material; + Material material; - // Extract ambient color - aiColor3D ambient(0.0f, 0.0f, 0.0f); - if (AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_AMBIENT, ambient)) { - material.ambient = glm::vec3(ambient.r, ambient.g, ambient.b); - } + aiColor3D ambient(0.0f, 0.0f, 0.0f); + if (AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_AMBIENT, ambient)) { + material.ambient = Vector3f(ambient.r, ambient.g, ambient.b); + } - // Extract diffuse color - aiColor3D diffuse(1.0f, 1.0f, 1.0f); // Default to white - if (AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_DIFFUSE, diffuse)) { - material.diffuse = glm::vec3(diffuse.r, diffuse.g, diffuse.b); - } + aiColor3D diffuse(1.0f, 1.0f, 1.0f); + if (AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_DIFFUSE, diffuse)) { + material.diffuse = Vector3f(diffuse.r, diffuse.g, diffuse.b); + } - // Extract specular color - aiColor3D specular(0.0f, 0.0f, 0.0f); - if (AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_SPECULAR, specular)) { - material.specular = glm::vec3(specular.r, specular.g, specular.b); - } + aiColor3D specular(0.0f, 0.0f, 0.0f); + if (AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_SPECULAR, specular)) { + material.specular = Vector3f(specular.r, specular.g, specular.b); + } - // Extract shininess - float shininess = 0.0f; - if (AI_SUCCESS == mat->Get(AI_MATKEY_SHININESS, shininess)) { - material.shininess = shininess; - } + float shininess = 0.0f; + if (AI_SUCCESS == mat->Get(AI_MATKEY_SHININESS, shininess)) { + material.shininess = shininess; + } - return material; + return material; } -void Model::transform(const glm::mat4 &tran) { - for (auto& face : faces_) { - face.transform(tran); - } +// Apply a transformation matrix to all faces in the model +// 对模型中的所有面应用变换矩阵 +void Model::transform(const Matrix4f& tran) { + for (auto& face : faces_) { + face.transform(tran); + } } } // namespace simple_renderer diff --git a/src/shader_base.cpp b/src/shader_base.cpp index 9d5f937..b5b1f39 100644 --- a/src/shader_base.cpp +++ b/src/shader_base.cpp @@ -22,9 +22,9 @@ ShaderVertexIn::ShaderVertexIn(const Face &face) : face_(face) {} ShaderVertexOut::ShaderVertexOut(const Face &face) : face_(face) {} -ShaderFragmentIn::ShaderFragmentIn(const glm::vec3 &barycentric_coord, - const glm::vec3 &normal, - const glm::vec3 &light, const Color &color0, +ShaderFragmentIn::ShaderFragmentIn(const Vector3f &barycentric_coord, + const Vector3f &normal, + const Vector3f &light, const Color &color0, const Color &color1, const Color &color2) : barycentric_coord_(barycentric_coord), normal_(normal), @@ -37,9 +37,9 @@ ShaderFragmentOut::ShaderFragmentOut(const bool &is_need_draw, const Color &color) : is_need_draw_(is_need_draw), color_(color) {} -ShaderData::ShaderData(const glm::mat4 &model_matrix, - const glm::mat4 &view_matrix, - const glm::mat4 &project_matrix) +ShaderData::ShaderData(const Matrix4f &model_matrix, + const Matrix4f &view_matrix, + const Matrix4f &project_matrix) : model_matrix_(model_matrix), view_matrix_(view_matrix), project_matrix_(project_matrix) {} diff --git a/src/simple_renderer.cpp b/src/simple_renderer.cpp index 93105ab..fafbc15 100755 --- a/src/simple_renderer.cpp +++ b/src/simple_renderer.cpp @@ -126,8 +126,7 @@ void SimpleRenderer::DrawLine(float x0, float y0, float x1, float y1, } void SimpleRenderer::DrawTriangle(const ShaderBase &shader, const Light &light, - const glm::vec3 &normal, - const Face &face) { + const Vector3f &normal, const Face &face) { auto v0 = face.vertex(0); auto v1 = face.vertex(1); auto v2 = face.vertex(2); @@ -135,17 +134,21 @@ void SimpleRenderer::DrawTriangle(const ShaderBase &shader, const Light &light, // 获取三角形的最小 box auto min = v0.position(); auto max = v1.position(); - auto max_x = std::max(face.vertex(0).position().x, - std::max(face.vertex(1).position().x, face.vertex(2).position().x)); - auto max_y = std::max(face.vertex(0).position().y, - std::max(face.vertex(1).position().y, face.vertex(2).position().y)); + auto max_x = std::max( + face.vertex(0).position().x, + std::max(face.vertex(1).position().x, face.vertex(2).position().x)); + auto max_y = std::max( + face.vertex(0).position().y, + std::max(face.vertex(1).position().y, face.vertex(2).position().y)); max.x = max_x > max.x ? max_x : max.x; max.y = max_y > max.y ? max_y : max.y; max.z = 0; - auto min_x = std::min(face.vertex(0).position().x, - std::min(face.vertex(1).position().x, face.vertex(2).position().x)); - auto min_y = std::min(face.vertex(0).position().y, - std::min(face.vertex(1).position().y, face.vertex(2).position().y)); + auto min_x = std::min( + face.vertex(0).position().x, + std::min(face.vertex(1).position().x, face.vertex(2).position().x)); + auto min_y = std::min( + face.vertex(0).position().y, + std::min(face.vertex(1).position().y, face.vertex(2).position().y)); min.x = min_x < min.x ? min_x : min.x; min.y = min_y < min.y ? min_y : min.y; min.z = 0; @@ -160,14 +163,14 @@ void SimpleRenderer::DrawTriangle(const ShaderBase &shader, const Light &light, } auto [is_inside, barycentric_coord] = GetBarycentricCoord( v0.position(), v1.position(), v2.position(), - glm::vec3(static_cast(x), static_cast(y), 0)); + Vector3f(static_cast(x), static_cast(y), 0)); // 如果点在三角形内再进行下一步 if (!is_inside) { continue; } // 计算该点的深度,通过重心坐标插值计算 - auto z = InterpolateDepth(v0.position().z, v1.position().z, v2.position().z, - barycentric_coord); + auto z = InterpolateDepth(v0.position().z, v1.position().z, + v2.position().z, barycentric_coord); // 深度在已有颜色之上 if (z < depth_buffer_[y * width_ + x]) { continue; @@ -202,12 +205,15 @@ void SimpleRenderer::DrawModel(const ShaderBase &shader, const Light &light, for (const auto &f : model.faces()) { /// @todo 巨大性能开销 auto face = shader.Vertex(ShaderVertexIn(f)).face_; - DrawLine(face.vertex(0).position().x, face.vertex(0).position().y, face.vertex(1).position().x, - face.vertex(1).position().y, Color::kRed); - DrawLine(face.vertex(1).position().x, face.vertex(1).position().y, face.vertex(2).position().x, - face.vertex(2).position().y, Color::kGreen); - DrawLine(face.vertex(2).position().x, face.vertex(2).position().y, face.vertex(0).position().x, - face.vertex(0).position().y, Color::kBlue); + DrawLine(face.vertex(0).position().x, face.vertex(0).position().y, + face.vertex(1).position().x, face.vertex(1).position().y, + Color::kRed); + DrawLine(face.vertex(1).position().x, face.vertex(1).position().y, + face.vertex(2).position().x, face.vertex(2).position().y, + Color::kGreen); + DrawLine(face.vertex(2).position().x, face.vertex(2).position().y, + face.vertex(0).position().x, face.vertex(0).position().y, + Color::kBlue); } } if (draw_triangle) { @@ -222,37 +228,37 @@ void SimpleRenderer::DrawModel(const ShaderBase &shader, const Light &light, } /// @todo 巨大性能开销 -auto SimpleRenderer::GetBarycentricCoord(const glm::vec3 &p0, const glm::vec3 &p1, - const glm::vec3 &p2, const glm::vec3 &pa) - -> std::pair { +auto SimpleRenderer::GetBarycentricCoord(const Vector3f &p0, const Vector3f &p1, + const Vector3f &p2, const Vector3f &pa) + -> std::pair { auto p1p0 = p1 - p0; auto p2p0 = p2 - p0; auto pap0 = pa - p0; auto deno = (p1p0.x * p2p0.y - p1p0.y * p2p0.x); if (std::abs(deno) < std::numeric_limits::epsilon()) { - return std::pair{false, glm::vec3()}; + return std::pair{false, Vector3f()}; } auto s = (p2p0.y * pap0.x - p2p0.x * pap0.y) / deno; if ((s > 1) || (s < 0)) { - return std::pair{false, glm::vec3()}; + return std::pair{false, Vector3f()}; } auto t = (p1p0.x * pap0.y - p1p0.y * pap0.x) / deno; if ((t > 1) || (t < 0)) { - return std::pair{false, glm::vec3()}; + return std::pair{false, Vector3f()}; } if ((1 - s - t > 1) || (1 - s - t < 0)) { - return std::pair{false, glm::vec3()}; + return std::pair{false, Vector3f()}; } - return std::pair{true, glm::vec3(1 - s - t, s, t)}; + return std::pair{true, Vector3f(1 - s - t, s, t)}; } auto SimpleRenderer::InterpolateDepth(float depth0, float depth1, float depth2, - const glm::vec3 &_barycentric_coord) + const Vector3f &_barycentric_coord) -> float { auto depth = depth0 * _barycentric_coord.x; depth += depth1 * _barycentric_coord.y; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index fa647ac..e8267a4 100755 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -14,50 +14,38 @@ enable_testing() include(GoogleTest) include_directories( - ${SimpleRenderer_SOURCE_DIR}/include + ${SimpleRenderer_SOURCE_DIR}/src/include ) list(APPEND DEFAULT_TEST_COMPILE_OPTIONS - ${DEFAULT_COMPILE_OPTIONS} - --coverage + ${DEFAULT_COMPILE_OPTIONS} + --coverage ) list(APPEND DEFAULT_TEST_LINK_OPTIONS - --coverage - $<$: - # -fsanitize=leak - > - # -fsanitize=address - -fno-omit-frame-pointer + --coverage + $<$: + # -fsanitize=leak + > + # -fsanitize=address + -fno-omit-frame-pointer ) link_libraries( - ${DEFAULT_LINK_LIB} - gtest_main - ${glog_LIBRARIES} - SimpleRenderer + ${DEFAULT_LINK_LIB} + gtest_main + ${glog_LIBRARIES} + SimpleRenderer ) -# Check if the platform is macOS -if(APPLE) - # Enable RPATH support on macOS - set(CMAKE_MACOSX_RPATH 1) - # Set the RPATH to look for frameworks relative to the executable path - set(CMAKE_INSTALL_RPATH "/Library/Frameworks") - - # Ensure that RPATH is used in the build - set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) -endif() - - -# add_subdirectory(unit_test) +add_subdirectory(unit_test) #add_subdirectory(integration_test) add_subdirectory(system_test) -# add_coverage_target( -# DEPENDS unit_test -# SOURCE_DIR ${SimpleRenderer_SOURCE_DIR} -# BINARY_DIR ${SimpleRenderer_BINARY_DIR} -# EXCLUDE_DIR ${SimpleRenderer_SOURCE_DIR}/3rd/* -# ) +add_coverage_target( + DEPENDS unit_test + SOURCE_DIR ${SimpleRenderer_SOURCE_DIR} + BINARY_DIR ${SimpleRenderer_BINARY_DIR} + EXCLUDE_DIR ${SimpleRenderer_SOURCE_DIR}/3rd/* +) \ No newline at end of file diff --git a/test/system_test/CMakeLists.txt b/test/system_test/CMakeLists.txt index 6d3b0f5..3e976e3 100755 --- a/test/system_test/CMakeLists.txt +++ b/test/system_test/CMakeLists.txt @@ -23,4 +23,4 @@ target_compile_options(system_test PRIVATE target_link_options(system_test PRIVATE ${DEFAULT_TEST_LINK_OPTIONS} -) +) \ No newline at end of file diff --git a/test/system_test/camera.h b/test/system_test/camera.h index 2694bdd..d64693d 100644 --- a/test/system_test/camera.h +++ b/test/system_test/camera.h @@ -21,7 +21,7 @@ #include #include "color.h" -#include "log_math.hpp" +#include "math.hpp" namespace simple_renderer { @@ -33,9 +33,9 @@ class Camera { /// 光照名称 std::string name_ = "default light name"; /// 位置 - glm::vec3 pos_; + Vector3f pos_; /// 方向 - glm::vec3 dir_; + Vector3f dir_; /** * 构造函数 diff --git a/test/system_test/main.cpp b/test/system_test/main.cpp index 013382c..d1024a8 100755 --- a/test/system_test/main.cpp +++ b/test/system_test/main.cpp @@ -59,16 +59,18 @@ int main(int argc, char **argv) { // objs.emplace_back(obj_path + "/african_head.obj"); objs.emplace_back(obj_path + "/utah-teapot/utah-teapot.obj"); - - auto matrix = - glm::mat4(1.0f); - glm::mat4 scale_matrix = glm::scale(glm::mat4(1.0f), glm::vec3(10.0f, 10.0f, 10.0f)); - -// Translation matrix - glm::mat4 translation_matrix = glm::translate(glm::mat4(1.0f), glm::vec3(kWidth / 2.0f, kHeight / 2.0f, 0.0f)); - - // Combined transformation matrix - matrix = translation_matrix * scale_matrix; + auto matrix = simple_renderer::Matrix4f(1.0f); + simple_renderer::Matrix4f scale_matrix = + glm::scale(simple_renderer::Matrix4f(1.0f), + simple_renderer::Vector3f(10.0f, 10.0f, 10.0f)); + + // Translation matrix + simple_renderer::Matrix4f translation_matrix = glm::translate( + simple_renderer::Matrix4f(1.0f), + simple_renderer::Vector3f(kWidth / 2.0f, kHeight / 2.0f, 0.0f)); + + // Combined transformation matrix + matrix = translation_matrix * scale_matrix; // 矩阵运算的顺序 // 归一化 diff --git a/test/unit_test/matrix_test.cpp b/test/unit_test/matrix_test.cpp index 045f4ba..4ddf650 100644 --- a/test/unit_test/matrix_test.cpp +++ b/test/unit_test/matrix_test.cpp @@ -15,8 +15,7 @@ * */ -#include "log_math.hpp" - #include "gtest/gtest.h" +#include "math.hpp" TEST(ttt1, todo1) { EXPECT_EQ(nullptr, nullptr); } From 787740cb4664a17e66887ec19be6dd73cf8ff2df Mon Sep 17 00:00:00 2001 From: ZhuohaoHe Date: Fri, 9 Aug 2024 17:33:01 -0400 Subject: [PATCH 16/17] update 3rd.cmake & workflow.yml by adding Signed-off-by: ZhuohaoHe --- .github/workflows/workflow.yml | 4 ++-- README.md | 2 +- cmake/3rd.cmake | 10 ---------- 3 files changed, 3 insertions(+), 13 deletions(-) diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index abedbab..6d24737 100755 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -26,7 +26,7 @@ jobs: run: | sudo apt update sudo apt install --fix-missing -y doxygen graphviz clang-format clang-tidy cppcheck lcov - sudo apt install --fix-missing -y gcc g++ libsdl2-dev libsdl2-ttf-dev libomp-dev libspdlog-dev + sudo apt install --fix-missing -y gcc g++ libsdl2-dev libsdl2-ttf-dev libomp-dev libspdlog-dev libassimp-dev - name: Build run: | @@ -48,7 +48,7 @@ jobs: run: | sudo apt update sudo apt install --fix-missing -y doxygen graphviz clang-format clang-tidy cppcheck lcov - sudo apt install --fix-missing -y gcc g++ libsdl2-dev libsdl2-ttf-dev libomp-dev libspdlog-dev + sudo apt install --fix-missing -y gcc g++ libsdl2-dev libsdl2-ttf-dev libomp-dev libspdlog-dev libassimp-dev - name: Build run: | diff --git a/README.md b/README.md index 1ccd0cd..8339ee0 100755 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ A software renderer ## 依赖 ```shell -sudo apt install doxygen graphviz clang-format clang-tidy cppcheck lcov gcc g++ libsdl2-dev libsdl2-ttf-dev libomp-dev libspdlog-dev cmake vim +sudo apt install doxygen graphviz clang-format clang-tidy cppcheck lcov gcc g++ libsdl2-dev libsdl2-ttf-dev libomp-dev libspdlog-dev cmake vim libassimp-dev ``` ## 使用 diff --git a/cmake/3rd.cmake b/cmake/3rd.cmake index 7c06507..9c3fe69 100644 --- a/cmake/3rd.cmake +++ b/cmake/3rd.cmake @@ -69,16 +69,6 @@ CPMAddPackage( "SDL_WERROR OFF" ) -CPMAddPackage( - NAME assimp - GIT_REPOSITORY https://github.com/assimp/assimp.git - GIT_TAG v5.4.1 - OPTIONS - "ASSIMP_BUILD_TESTS OFF" - "ASSIMP_BUILD_ASSIMP_TOOLS OFF" - "ASSIMP_BUILD_SAMPLES OFF" -) - # https://github.com/g-truc/glm CPMAddPackage( NAME glm From 0703564f7f2049e2230b8884590a23531f89d72c Mon Sep 17 00:00:00 2001 From: ZhuohaoHe Date: Mon, 26 Aug 2024 11:10:20 -0400 Subject: [PATCH 17/17] Update gitignore and grud in header file Signed-off-by: ZhuohaoHe --- .gitignore | 2 +- src/include/config.h | 38 -------------------------------------- src/include/face.hpp | 5 ++++- src/include/material.hpp | 7 +++++-- src/include/math.hpp | 5 ++++- src/include/vertex.hpp | 7 +++++-- 6 files changed, 19 insertions(+), 45 deletions(-) delete mode 100644 src/include/config.h diff --git a/.gitignore b/.gitignore index da25727..c52ec00 100755 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,4 @@ tools/opensbi/build .idea 3rd Doxyfile -include/config.h +src/include/config.h \ No newline at end of file diff --git a/src/include/config.h b/src/include/config.h deleted file mode 100644 index fcc39ed..0000000 --- a/src/include/config.h +++ /dev/null @@ -1,38 +0,0 @@ - -/** - * @file config.h - * @brief 项目配置 - * @author Zone.N (Zone.Niuzh@hotmail.com) - * @version 1.0 - * @date 2023-08-24 - * @copyright MIT LICENSE - * https://github.com/Simple-XX/SimpleRenderer - * @par change log: - * - *
DateAuthorDescription - *
2023-08-24Zone.N创建文件 - *
- */ - -#ifndef SIMPLERENDER_SRC_INCLUDE_CONFIG_H_ -#define SIMPLERENDER_SRC_INCLUDE_CONFIG_H_ - -#include -#include - -namespace simple_renderer { - -/// 线程数 -static constexpr const size_t kNProc = 8; - -/// 日志文件路径 -static const std::string kLogFilePath = - std::string("/Users/hezhohao/Programming/GitRepo/SimpleRenderer/build/bin/logs/SimpleRendererLog.log"); -/// 日志文件大小 -static constexpr const size_t kLogFileMaxSize = 1024*1024*4; -/// 日志文件数量 -static constexpr const size_t kLogFileMaxCount = 8; - -} // namespace simple_renderer - -#endif /* SIMPLERENDER_SRC_INCLUDE_CONFIG_H_ */ diff --git a/src/include/face.hpp b/src/include/face.hpp index 1c0e16f..bd5de4e 100644 --- a/src/include/face.hpp +++ b/src/include/face.hpp @@ -1,4 +1,5 @@ -#pragma once +#ifndef SIMPLERENDER_SRC_INCLUDE_FACE_HPP_ +#define SIMPLERENDER_SRC_INCLUDE_FACE_HPP_ #include @@ -76,3 +77,5 @@ class Face { }; } // namespace simple_renderer + +#endif \ No newline at end of file diff --git a/src/include/material.hpp b/src/include/material.hpp index cc4cece..c637548 100644 --- a/src/include/material.hpp +++ b/src/include/material.hpp @@ -1,4 +1,5 @@ -#pragma once +#ifndef SIMPLERENDER_SRC_INCLUDE_MATERIAL_HPP_ +#define SIMPLERENDER_SRC_INCLUDE_MATERIAL_HPP_ #include @@ -36,4 +37,6 @@ class Material { Vector3f specular; }; -} // namespace simple_renderer \ No newline at end of file +} // namespace simple_renderer + +#endif \ No newline at end of file diff --git a/src/include/math.hpp b/src/include/math.hpp index eb7d3f2..6f5a8eb 100644 --- a/src/include/math.hpp +++ b/src/include/math.hpp @@ -1,4 +1,5 @@ -#pragma once +#ifndef SIMPLERENDER_SRC_INCLUDE_MATH_HPP_ +#define SIMPLERENDER_SRC_INCLUDE_MATH_HPP_ #include @@ -56,3 +57,5 @@ struct fmt::formatter : fmt::formatter { return fmt::format_to(ctx.out(), "\n{}", matrix_str); } }; + +#endif diff --git a/src/include/vertex.hpp b/src/include/vertex.hpp index 1cd3084..924d8fe 100644 --- a/src/include/vertex.hpp +++ b/src/include/vertex.hpp @@ -1,4 +1,5 @@ -#pragma once +#ifndef SIMPLERENDER_SRC_INCLUDE_VERTEX_HPP_ +#define SIMPLERENDER_SRC_INCLUDE_VERTEX_HPP_ #include @@ -63,4 +64,6 @@ class Vertex { Color color_; }; -} // namespace simple_renderer \ No newline at end of file +} // namespace simple_renderer + +#endif \ No newline at end of file