💿🐜 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.

180 lines
5.8 KiB

  1. /*
  2. * Copyright (C) 2021 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 "geom/mesh-accelerator.hpp"
  20. #include "geom/mesh-functions.hpp"
  21. #include "geom/morton.hpp"
  22. #include <bitset>
  23. namespace geom {
  24. mesh_accelerator::mesh_accelerator()
  25. {}
  26. void mesh_accelerator::build(const mesh& mesh)
  27. {
  28. // Clear octree and face map
  29. octree.clear();
  30. face_map.clear();
  31. // Calculate mesh dimensions
  32. aabb<float> bounds = calculate_bounds(mesh);
  33. float3 mesh_dimensions = bounds.max_point - bounds.min_point;
  34. center_offset = mesh_dimensions * 0.5f - (bounds.min_point + bounds.max_point) * 0.5f;
  35. // Calculate node dimensions at each octree depth
  36. for (auto i = 0; i <= octree32::max_depth; ++i)
  37. {
  38. node_dimensions[i] = mesh_dimensions * static_cast<float>((1.0f / std::pow(2, i)));
  39. }
  40. // Add faces to octree
  41. for (mesh::face* face: mesh.get_faces())
  42. {
  43. // Calculate face bounds
  44. float3 min_point = reinterpret_cast<const float3&>(face->edge->vertex->position);
  45. float3 max_point = min_point;
  46. mesh::edge* edge = face->edge;
  47. do
  48. {
  49. const auto& position = edge->vertex->position;
  50. for (int i = 0; i < 3; ++i)
  51. {
  52. min_point[i] = std::min<float>(min_point[i], position[i]);
  53. max_point[i] = std::max<float>(max_point[i], position[i]);
  54. }
  55. edge = edge->next;
  56. }
  57. while (edge != face->edge);
  58. // 1. Find max depth node of aabb min
  59. // 2. Find max depth node of aabb max
  60. // 3. Find common ancestor of the two nodes--that's the containing node.
  61. octree32::node_type min_node = find_node(min_point);
  62. octree32::node_type max_node = find_node(max_point);
  63. octree32::node_type containing_node = octree32::common_ancestor(min_node, max_node);
  64. // Insert containing node into octree
  65. octree.insert(containing_node);
  66. // Add face to face map
  67. face_map[containing_node].push_back(face);
  68. }
  69. }
  70. std::optional<mesh_accelerator::ray_query_result> mesh_accelerator::query_nearest(const ray<float>& ray) const
  71. {
  72. ray_query_result result;
  73. result.t = std::numeric_limits<float>::infinity();
  74. result.face = nullptr;
  75. query_nearest_recursive(result.t, result.face, octree.root, ray);
  76. if (result.face)
  77. return std::optional{result};
  78. return std::nullopt;
  79. }
  80. void mesh_accelerator::query_nearest_recursive(float& nearest_t, geom::mesh::face*& nearest_face, octree32::node_type node, const ray<float>& ray) const
  81. {
  82. // Get node bounds
  83. const aabb<float> node_bounds = get_node_bounds(node);
  84. // Test for intersection with node bounds
  85. auto aabb_intersection = ray_aabb_intersection(ray, node_bounds);
  86. // If ray passed through this node
  87. if (std::get<0>(aabb_intersection))
  88. {
  89. // Test all triangles in the node
  90. if (auto it = face_map.find(node); it != face_map.end())
  91. {
  92. const std::list<mesh::face*>& faces = it->second;
  93. for (mesh::face* face: faces)
  94. {
  95. // Get triangle coordinates
  96. const float3& a = reinterpret_cast<const float3&>(face->edge->vertex->position);
  97. const float3& b = reinterpret_cast<const float3&>(face->edge->next->vertex->position);
  98. const float3& c = reinterpret_cast<const float3&>(face->edge->previous->vertex->position);
  99. // Test for intersection with triangle
  100. auto triangle_intersection = ray_triangle_intersection(ray, a, b, c);
  101. if (std::get<0>(triangle_intersection))
  102. {
  103. float t = std::get<1>(triangle_intersection);
  104. if (t < nearest_t)
  105. {
  106. nearest_t = t;
  107. nearest_face = face;
  108. }
  109. }
  110. }
  111. }
  112. // Test all child nodes
  113. if (!octree.is_leaf(node))
  114. {
  115. for (int i = 0; i < 8; ++i)
  116. query_nearest_recursive(nearest_t, nearest_face, octree.child(node, i), ray);
  117. }
  118. }
  119. }
  120. aabb<float> mesh_accelerator::get_node_bounds(octree32::node_type node) const
  121. {
  122. // Decode Morton location of node
  123. std::uint32_t x, y, z;
  124. morton::decode(octree32::location(node), x, y, z);
  125. float3 node_location = float3{static_cast<float>(x), static_cast<float>(y), static_cast<float>(z)};
  126. // Get node dimensions at node depth
  127. const float3& dimensions = node_dimensions[octree32::depth(node)];
  128. // Calculate AABB
  129. float3 min_point = (node_location * dimensions) - center_offset;
  130. return aabb<float>{min_point, min_point + dimensions};
  131. }
  132. octree32::node_type mesh_accelerator::find_node(const float3& point) const
  133. {
  134. // Transform point to octree space
  135. float3 transformed_point = (point + center_offset);
  136. // Account for floating-point tolerance
  137. const float epsilon = 0.00001f;
  138. transformed_point.x = std::max<float>(0.0f, std::min<float>(node_dimensions[0].x - epsilon, transformed_point.x));
  139. transformed_point.y = std::max<float>(0.0f, std::min<float>(node_dimensions[0].y - epsilon, transformed_point.y));
  140. transformed_point.z = std::max<float>(0.0f, std::min<float>(node_dimensions[0].z - epsilon, transformed_point.z));
  141. // Transform point to max-depth node space
  142. transformed_point = transformed_point / node_dimensions[octree32::max_depth];
  143. // Encode transformed point as a Morton location code
  144. std::uint32_t location = morton::encode(
  145. static_cast<std::uint32_t>(transformed_point.x),
  146. static_cast<std::uint32_t>(transformed_point.y),
  147. static_cast<std::uint32_t>(transformed_point.z));
  148. // Return max depth node at the determined location
  149. return octree32::node(octree32::max_depth, location);
  150. }
  151. } // namespace geom