Antkeeper  0.0.1
mesh-collider.cpp
Go to the documentation of this file.
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 
21 #include <engine/debug/log.hpp>
24 #include <limits>
25 
26 namespace physics {
27 
28 mesh_collider::mesh_collider(std::shared_ptr<mesh_type> mesh)
29 {
30  set_mesh(mesh);
31 }
32 
33 void mesh_collider::set_mesh(std::shared_ptr<mesh_type> mesh)
34 {
35  m_mesh = mesh;
36  if (m_mesh)
37  {
38  // Store pointer to mesh vertex positions
39  m_vertex_positions = &m_mesh->vertices().attributes().at<math::fvec3>("position");
40 
41  // If mesh has no face normals
42  if (!m_mesh->faces().attributes().contains("normal"))
43  {
44  // Generate face normals
45  generate_face_normals(*m_mesh);
46  }
47 
49  // If mesh has no vertex normals
50  if (!m_mesh->vertices().attributes().contains("normal"))
51  {
52  // Generate vertex normals
53  generate_vertex_normals(*m_mesh);
54  }
55 
56  // Store pointer to mesh face normals
57  m_face_normals = &m_mesh->faces().attributes().at<math::fvec3>("normal");
58  }
59  else
60  {
61  m_vertex_positions = nullptr;
62  m_face_normals = nullptr;
63  }
64 
65  rebuild_bvh();
66 }
67 
69 {
70  if (m_mesh)
71  {
72  m_bvh.build(*m_mesh);
73  }
74  else
75  {
76  m_bvh.clear();
77  }
78 }
79 
80 std::optional<std::tuple<float, std::uint32_t, math::fvec3>> mesh_collider::intersection(const geom::ray<float, 3>& ray) const
81 {
82  if (!m_mesh)
83  {
84  return std::nullopt;
85  }
86 
87  bool triangle_hit = false;
88  float nearest_face_distance = std::numeric_limits<float>::infinity();
89  std::uint32_t nearest_face_index;
90 
91  // For each BVH leaf node that intersects ray
92  m_bvh.visit
93  (
94  ray,
95  [&](std::uint32_t index)
96  {
97  // If ray is facing backside of face
98  if (math::dot((*m_face_normals)[index], ray.direction) > 0.0f)
99  {
100  // Ignore face
101  return;
102  }
103 
104  // Get pointer to mesh face from BVH primitive index
105  geom::brep_face* face = m_mesh->faces()[index];
106 
107  // Get face vertex positions
108  auto loop = face->loops().begin();
109  const auto& a = (*m_vertex_positions)[loop->vertex()->index()];
110  const auto& b = (*m_vertex_positions)[(++loop)->vertex()->index()];
111  const auto& c = (*m_vertex_positions)[(++loop)->vertex()->index()];
112 
113  // If ray intersects face
114  if (const auto intersection = geom::intersection(ray, a, b, c))
115  {
116  // If distance to point of intersection is nearer than nearest intersection
117  float t = std::get<0>(*intersection);
118  if (t < nearest_face_distance)
119  {
120  // Update nearest intersection
121  nearest_face_distance = t;
122  nearest_face_index = index;
123 
124  triangle_hit = true;
125  }
126  }
127  }
128  );
129 
130  if (!triangle_hit)
131  {
132  return std::nullopt;
133  }
134 
135  return std::make_tuple(nearest_face_distance, nearest_face_index, (*m_face_normals)[nearest_face_index]);
136 }
137 
138 } // namespace physics
Portion of a shell bounded by loops.
Definition: brep-face.hpp:244
void clear()
Clears the BVH.
Definition: bvh.cpp:96
void build(std::span< const bvh_primitive > primitives)
Constructs a BVH from a set of primitives.
Definition: bvh.cpp:39
void visit(const geom::ray< float, 3 > &ray, const visitor_type &f) const
Visits the primitive indices of all BVH nodes that intersect a ray.
Definition: bvh.hpp:83
void set_mesh(std::shared_ptr< mesh_type > mesh)
Sets the collider's mesh.
constexpr mesh_collider() noexcept=default
Constructs an empty mesh collider.
std::optional< std::tuple< float, std::uint32_t, math::fvec3 > > intersection(const geom::ray< float, 3 > &ray) const
Finds the nearest point of intersection between a ray and this collision mesh.
void rebuild_bvh()
Rebuilds the BVH of the collision mesh faces.
constexpr std::optional< T > intersection(const ray< T, N > &ray, const hyperplane< T, N > &hyperplane) noexcept
Ray-hyperplane intersection test.
void generate_face_normals(brep_mesh &mesh)
Generates the math::fvec3 face attribute "normal" for a B-rep mesh.
void generate_vertex_normals(brep_mesh &mesh)
Generates the math::fvec3 vertex attribute "normal" for a B-rep mesh.
constexpr T dot(const quaternion< T > &a, const quaternion< T > &b) noexcept
Calculates the dot product of two quaternions.
Definition: quaternion.hpp:572
Physics.
Definition: constants.hpp:23
@ mesh
Mesh collider.
Half of a line proceeding from an initial point.
Definition: ray.hpp:38
vector_type direction
Ray direction vector.
Definition: ray.hpp:46
n-dimensional vector.
Definition: vector.hpp:44