Skip to main content

he3d_physics/
static_geometry.rs

1use alloc::collections::BTreeMap;
2use alloc::vec::Vec;
3
4use he3d_math::Vec3;
5
6use crate::aabb::Aabb;
7
8/// A stable handle to a piece of Static geometry registered in a
9/// [`crate::World`].
10/// 指向 [`crate::World`] 中某块 Static geometry 的稳定句柄。
11#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
12pub struct StaticMeshId {
13   index: u32,
14   generation: u32,
15}
16
17impl StaticMeshId {
18   /// Mint a handle. Only a World may do this.
19   /// 铸造句柄。只有 World 可以这样做。
20   pub(crate) const fn new(index: u32, generation: u32) -> Self {
21      Self { index, generation }
22   }
23
24   /// The slot this handle addresses within its World.
25   /// 此句柄在其 World 中寻址的槽位。
26   #[must_use]
27   pub const fn index(self) -> u32 {
28      self.index
29   }
30
31   /// The slot generation this handle was minted against.
32   /// 铸造此句柄时所对应的槽位代际。
33   #[must_use]
34   pub const fn generation(self) -> u32 {
35      self.generation
36   }
37}
38
39/// One registered triangle soup.
40/// 一块已注册的三角形汤。
41#[derive(Clone, Debug)]
42pub(crate) struct StaticMesh {
43   /// Flat vertex positions; every three consecutive entries form one triangle.
44   /// 扁平顶点位置;每三个连续条目构成一个三角形。
45   pub(crate) positions: Vec<Vec3>,
46   /// A bounding box per triangle, so a Body only tests what it can reach.
47   /// 每个三角形一个包围盒,使 Body 只测试它够得着的部分。
48   pub(crate) triangle_bounds: Vec<Aabb>,
49   /// Welded vertex ids, three per triangle.
50   /// 焊接后的顶点 id,每个三角形三个。
51   pub(crate) welded: Vec<[u32; 3]>,
52   /// The mesh's own bounding box.
53   /// 该网格自身的包围盒。
54   pub(crate) bounds: Aabb,
55}
56
57impl StaticMesh {
58   /// How many triangles the mesh holds.
59   pub(crate) fn triangle_count(&self) -> usize {
60      self.triangle_bounds.len()
61   }
62
63   /// The vertices of one triangle.
64   pub(crate) fn triangle(&self, index: usize) -> [Vec3; 3] {
65      let base = index * 3;
66      [
67         self.positions[base],
68         self.positions[base + 1],
69         self.positions[base + 2],
70      ]
71   }
72}
73
74/// The shared topology of every registered Static mesh in one World.
75/// 一个 World 中所有已注册 Static mesh 的共享拓扑。
76///
77/// Vertices are welded by exact position across **all** meshes, so an edge lying
78/// between two separate meshes is still recognised as an Internal edge. That is
79/// what keeps a Body sliding across streamed terrain from catching on the seam
80/// between two tiles — per-mesh welding would leave every tile boundary as a real
81/// edge.
82/// 顶点按精确位置在**所有** mesh 之间焊接,因此位于两个独立 mesh 之间的边仍被识别为
83/// Internal edge。这正是让划过流式地形的 Body 不会卡在瓦片接缝上的原因——逐 mesh 焊接
84/// 会让每条瓦片边界都成为真实的边。
85#[derive(Clone, Debug, Default)]
86pub(crate) struct StaticTopology {
87   /// Exact position bits to welded vertex id.
88   welded: BTreeMap<[u32; 3], u32>,
89   /// How many live triangle corners use each welded vertex.
90   vertex_use: BTreeMap<u32, u32>,
91   /// How many triangles use each welded edge, keyed by the ordered vertex pair.
92   edge_use: BTreeMap<(u32, u32), u32>,
93   /// The next unused welded vertex id. Ids are never reused.
94   next_vertex: u32,
95}
96
97impl StaticTopology {
98   /// Weld one position and return its vertex id.
99   pub(crate) fn weld(&mut self, position: Vec3) -> u32 {
100      let key = position_key(position);
101      if let Some(&id) = self.welded.get(&key) {
102         return id;
103      }
104      let id = self.next_vertex;
105      self.next_vertex = self.next_vertex.wrapping_add(1);
106      self.welded.insert(key, id);
107      id
108   }
109
110   /// Register one triangle's welded corners, counting its edges.
111   pub(crate) fn add_triangle(&mut self, welded: [u32; 3]) {
112      for vertex in welded {
113         *self.vertex_use.entry(vertex).or_insert(0) += 1;
114      }
115      for edge in edges_of(welded) {
116         *self.edge_use.entry(edge).or_insert(0) += 1;
117      }
118   }
119
120   /// Release one triangle's welded corners, dropping what nothing else uses.
121   pub(crate) fn remove_triangle(&mut self, welded: [u32; 3]) {
122      for vertex in welded {
123         if let Some(count) = self.vertex_use.get_mut(&vertex) {
124            *count = count.saturating_sub(1);
125            if *count == 0 {
126               self.vertex_use.remove(&vertex);
127            }
128         }
129      }
130      for edge in edges_of(welded) {
131         if let Some(count) = self.edge_use.get_mut(&edge) {
132            *count = count.saturating_sub(1);
133            if *count == 0 {
134               self.edge_use.remove(&edge);
135            }
136         }
137      }
138   }
139
140   /// Whether an edge between two welded vertices is shared by two triangles of
141   /// the shared topology, and is therefore an Internal edge.
142   ///
143   /// A Contact whose normal comes from such an edge is spurious: the two
144   /// triangles meet smoothly there, so there is no real edge for a Body to catch
145   /// on.
146   /// 两个焊接顶点之间的边是否被共享拓扑中的两个三角形共用,因而是一条 Internal edge。
147   /// 法线来自这种边的 Contact 是伪接触:两个三角形在那里平滑相接,并不存在可供 Body 卡住
148   /// 的真实棱。
149   pub(crate) fn is_internal_edge(&self, first: u32, second: u32) -> bool {
150      let key = if first <= second {
151         (first, second)
152      } else {
153         (second, first)
154      };
155      self.edge_use.get(&key).copied().unwrap_or(0) >= 2
156   }
157
158   /// How many distinct welded vertices the topology holds.
159   #[cfg(test)]
160   pub(crate) fn vertex_count(&self) -> usize {
161      self.welded.len()
162   }
163}
164
165/// The three edges of a triangle, each ordered so the two directions agree.
166fn edges_of(welded: [u32; 3]) -> [(u32, u32); 3] {
167   let ordered = |first: u32, second: u32| {
168      if first <= second {
169         (first, second)
170      } else {
171         (second, first)
172      }
173   };
174   [
175      ordered(welded[0], welded[1]),
176      ordered(welded[1], welded[2]),
177      ordered(welded[2], welded[0]),
178   ]
179}
180
181/// The exact bit pattern of a position, with negative zero folded onto zero so
182/// that the two spellings of the same point weld together.
183fn position_key(position: Vec3) -> [u32; 3] {
184   let canonical = |value: f32| {
185      if value == 0.0 {
186         0.0_f32.to_bits()
187      } else {
188         value.to_bits()
189      }
190   };
191   [
192      canonical(position.x),
193      canonical(position.y),
194      canonical(position.z),
195   ]
196}
197
198#[cfg(test)]
199mod tests {
200   use super::StaticTopology;
201   use he3d_math::Vec3;
202
203   #[test]
204   fn identical_positions_weld_to_one_vertex() {
205      let mut topology = StaticTopology::default();
206      let first = topology.weld(Vec3::new(1.0, 2.0, 3.0));
207      let second = topology.weld(Vec3::new(1.0, 2.0, 3.0));
208      assert_eq!(first, second);
209      assert_eq!(topology.vertex_count(), 1);
210   }
211
212   #[test]
213   fn negative_zero_welds_with_positive_zero() {
214      let mut topology = StaticTopology::default();
215      assert_eq!(
216         topology.weld(Vec3::new(0.0, 0.0, 0.0)),
217         topology.weld(Vec3::new(-0.0, -0.0, -0.0))
218      );
219   }
220
221   #[test]
222   fn an_edge_shared_by_two_triangles_is_internal() {
223      let mut topology = StaticTopology::default();
224      // Two triangles of a quad sharing the diagonal (1, 2).
225      topology.add_triangle([0, 1, 2]);
226      assert!(
227         !topology.is_internal_edge(1, 2),
228         "one triangle is a boundary"
229      );
230      topology.add_triangle([1, 3, 2]);
231      assert!(topology.is_internal_edge(1, 2));
232      assert!(!topology.is_internal_edge(0, 1));
233   }
234
235   #[test]
236   fn edges_weld_across_separate_meshes() {
237      let mut topology = StaticTopology::default();
238      // A mesh on the left of a seam.
239      topology.add_triangle([0, 1, 2]);
240      // A mesh on the right re-uses the same welded vertices along the seam.
241      topology.add_triangle([1, 3, 2]);
242      assert!(
243         topology.is_internal_edge(2, 1),
244         "the order of the pair must not matter"
245      );
246   }
247
248   #[test]
249   fn removing_a_triangle_releases_its_edges() {
250      let mut topology = StaticTopology::default();
251      topology.add_triangle([0, 1, 2]);
252      topology.add_triangle([1, 3, 2]);
253      assert!(topology.is_internal_edge(1, 2));
254      topology.remove_triangle([1, 3, 2]);
255      assert!(!topology.is_internal_edge(1, 2));
256   }
257
258   #[test]
259   fn welding_is_stable_across_add_and_remove() {
260      let mut topology = StaticTopology::default();
261      let id = topology.weld(Vec3::X);
262      topology.add_triangle([id, id, id]);
263      topology.remove_triangle([id, id, id]);
264      // The id survives, because welded ids are never reused or renumbered.
265      assert_eq!(topology.weld(Vec3::X), id);
266      assert_eq!(topology.vertex_count(), 1);
267   }
268}