💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

238 lines
7.5 KiB

  1. /*
  2. * Copyright (C) 2023 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper source code.
  5. *
  6. * Antkeeper source code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper source code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <engine/geom/brep/brep-operations.hpp>
  20. #include <engine/math/vector.hpp>
  21. #include <engine/render/vertex-attribute-location.hpp>
  22. #include <engine/debug/log.hpp>
  23. #include <algorithm>
  24. #include <cmath>
  25. namespace geom {
  26. void generate_face_normals(brep_mesh& mesh)
  27. {
  28. const auto& vertex_positions = mesh.vertices().attributes().at<math::fvec3>("position");
  29. auto& face_normals = static_cast<brep_attribute<math::fvec3>&>(*mesh.faces().attributes().try_emplace<math::fvec3>("normal").first);
  30. for (brep_face* face: mesh.faces())
  31. {
  32. auto loop = face->loops().begin();
  33. const auto& a = vertex_positions[loop->vertex()->index()];
  34. const auto& b = vertex_positions[(++loop)->vertex()->index()];
  35. const auto& c = vertex_positions[(++loop)->vertex()->index()];
  36. face_normals[face->index()] = math::normalize(math::cross(b - a, c - a));
  37. }
  38. }
  39. void generate_vertex_normals(brep_mesh& mesh)
  40. {
  41. // Generate face normals if they don't exist
  42. if (!mesh.faces().attributes().contains("normal"))
  43. {
  44. generate_face_normals(mesh);
  45. }
  46. const auto& vertex_positions = mesh.vertices().attributes().at<math::fvec3>("position");
  47. const auto& face_normals = mesh.faces().attributes().at<math::fvec3>("normal");
  48. auto& vertex_normals = static_cast<brep_attribute<math::fvec3>&>(*mesh.vertices().attributes().try_emplace<math::fvec3>("normal").first);
  49. for (brep_vertex* vertex: mesh.vertices())
  50. {
  51. // Zero vertex normal
  52. auto& vertex_normal = vertex_normals[vertex->index()];
  53. vertex_normal = {};
  54. // Skip vertices with no edges
  55. if (vertex->edges().empty())
  56. {
  57. continue;
  58. }
  59. // Get vertex position
  60. const auto& vertex_position = vertex_positions[vertex->index()];
  61. // For each edge bounded by this vertex
  62. for (brep_edge* edge: vertex->edges())
  63. {
  64. // Skip edges with no associated face
  65. if (edge->loops().empty())
  66. {
  67. continue;
  68. }
  69. // Calculate direction vector of current edge
  70. const auto direction0 = math::normalize
  71. (
  72. vertex_positions[edge->vertices()[edge->vertices().front() == vertex]->index()] -
  73. vertex_position
  74. );
  75. // For each edge loop
  76. for (brep_loop* loop: edge->loops())
  77. {
  78. // Skip loops not originating at vertex
  79. if (loop->vertex() != vertex)
  80. {
  81. continue;
  82. }
  83. // Calculate direction vector of previous edge
  84. const auto direction1 = math::normalize
  85. (
  86. vertex_positions[loop->previous()->vertex()->index()] -
  87. vertex_position
  88. );
  89. // Find angle between two edges
  90. const auto cos_edge_angle = math::dot(direction0, direction1);
  91. const auto edge_angle = std::acos(cos_edge_angle);
  92. // Weigh face normal by edge angle and add to vertex normal
  93. vertex_normal += face_normals[loop->face()->index()] * edge_angle;
  94. }
  95. }
  96. // Normalize vertex normal
  97. const auto sqr_length = math::sqr_length(vertex_normal);
  98. if (sqr_length)
  99. {
  100. vertex_normal /= std::sqrt(sqr_length);
  101. }
  102. }
  103. }
  104. void generate_loop_barycentric(brep_mesh& mesh)
  105. {
  106. const auto& vertex_positions = mesh.vertices().attributes().at<math::fvec3>("position");
  107. auto& loop_barycentric = static_cast<brep_attribute<math::fvec3>&>(*mesh.loops().attributes().try_emplace<math::fvec3>("barycentric").first);
  108. for (brep_face* face: mesh.faces())
  109. {
  110. auto loop = face->loops().begin();
  111. loop_barycentric[loop->index()] = {1.0f, 0.0f, 0.0f};
  112. loop_barycentric[(++loop)->index()] = {0.0f, 1.0f, 0.0f};
  113. loop_barycentric[(++loop)->index()] = {0.0f, 0.0f, 1.0f};
  114. }
  115. }
  116. std::unique_ptr<render::model> generate_model(const brep_mesh& mesh, std::shared_ptr<render::material> material)
  117. {
  118. // Get vertex positions
  119. const geom::brep_attribute<math::fvec3>* vertex_positions = nullptr;
  120. if (auto attribute_it = mesh.vertices().attributes().find("position"); attribute_it != mesh.vertices().attributes().end())
  121. {
  122. vertex_positions = &static_cast<const geom::brep_attribute<math::fvec3>&>(*attribute_it);
  123. }
  124. // Get vertex normals
  125. const geom::brep_attribute<math::fvec3>* vertex_normals = nullptr;
  126. if (auto attribute_it = mesh.vertices().attributes().find("normal"); attribute_it != mesh.vertices().attributes().end())
  127. {
  128. vertex_normals = &static_cast<const geom::brep_attribute<math::fvec3>&>(*attribute_it);
  129. }
  130. // Allocate model
  131. auto model = std::make_unique<render::model>();
  132. // Init model bounds
  133. auto& bounds = model->get_bounds();
  134. bounds = {math::fvec3::infinity(), -math::fvec3::infinity()};
  135. // Construct model VAO
  136. std::size_t vertex_stride = 0;
  137. std::vector<gl::vertex_input_attribute> vertex_attributes;
  138. gl::vertex_input_attribute position_attribute{};
  139. if (vertex_positions)
  140. {
  141. position_attribute.location = render::vertex_attribute_location::position;
  142. position_attribute.binding = 0;
  143. position_attribute.format = gl::format::r32g32b32_sfloat;
  144. position_attribute.offset = 0;
  145. vertex_attributes.emplace_back(position_attribute);
  146. vertex_stride += 3 * sizeof(float);
  147. }
  148. gl::vertex_input_attribute normal_attribute{};
  149. if (vertex_normals)
  150. {
  151. normal_attribute.location = render::vertex_attribute_location::normal;
  152. normal_attribute.binding = 0;
  153. normal_attribute.format = gl::format::r32g32b32_sfloat;
  154. normal_attribute.offset = static_cast<std::uint32_t>(vertex_stride);
  155. vertex_attributes.emplace_back(normal_attribute);
  156. vertex_stride += 3 * sizeof(float);
  157. }
  158. auto& vao = model->get_vertex_array();
  159. vao = std::make_unique<gl::vertex_array>(vertex_attributes);
  160. // Interleave vertex data
  161. std::vector<std::byte> vertex_data(mesh.faces().size() * 3 * vertex_stride);
  162. if (vertex_positions)
  163. {
  164. std::byte* v = vertex_data.data() + position_attribute.offset;
  165. for (auto face: mesh.faces())
  166. {
  167. for (auto loop: face->loops())
  168. {
  169. const auto& position = (*vertex_positions)[loop->vertex()->index()];
  170. std::memcpy(v, position.data(), sizeof(float) * 3);
  171. v += vertex_stride;
  172. // Extend model bounds
  173. bounds.extend(position);
  174. }
  175. }
  176. }
  177. if (vertex_normals)
  178. {
  179. std::byte* v = vertex_data.data() + normal_attribute.offset;
  180. for (auto face: mesh.faces())
  181. {
  182. for (auto loop: face->loops())
  183. {
  184. const auto& normal = (*vertex_normals)[loop->vertex()->index()];
  185. std::memcpy(v, normal.data(), sizeof(float) * 3);
  186. v += vertex_stride;
  187. }
  188. }
  189. }
  190. // Construct model VBO
  191. auto& vbo = model->get_vertex_buffer();
  192. vbo = std::make_unique<gl::vertex_buffer>(gl::buffer_usage::static_draw, vertex_data);
  193. model->set_vertex_offset(0);
  194. model->set_vertex_stride(vertex_stride);
  195. // Create material group
  196. model->get_groups().resize(1);
  197. render::model_group& model_group = model->get_groups().front();
  198. model_group.id = {};
  199. model_group.material = material;
  200. model_group.primitive_topology = gl::primitive_topology::triangle_list;
  201. model_group.first_vertex = 0;
  202. model_group.vertex_count = static_cast<std::uint32_t>(mesh.faces().size() * 3);
  203. return model;
  204. }
  205. } // namespace geom