@woosh/meep-engine 2.133.3 → 2.134.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/build/bundle-worker-image-decoder.js +1 -1
  2. package/package.json +2 -2
  3. package/src/core/binary/BinaryBuffer.d.ts +20 -0
  4. package/src/core/binary/BinaryBuffer.d.ts.map +1 -1
  5. package/src/core/binary/BinaryBuffer.js +50 -0
  6. package/src/core/binary/BitSet.d.ts +6 -0
  7. package/src/core/binary/BitSet.d.ts.map +1 -1
  8. package/src/core/binary/BitSet.js +38 -1
  9. package/src/core/binary/operations/bitCount.d.ts.map +1 -1
  10. package/src/core/binary/operations/bitCount.js +11 -6
  11. package/src/core/geom/3d/aabb/AABB3.d.ts +7 -1
  12. package/src/core/geom/3d/aabb/AABB3.d.ts.map +1 -1
  13. package/src/core/geom/3d/aabb/AABB3.js +14 -1
  14. package/src/core/geom/3d/topology/simplify/EdgeCollapseCandidate.d.ts +4 -4
  15. package/src/core/geom/3d/topology/simplify/EdgeCollapseCandidate.d.ts.map +1 -1
  16. package/src/core/geom/3d/topology/simplify/EdgeCollapseCandidate.js +2 -2
  17. package/src/core/geom/3d/topology/simplify/build_edge_collapse_candidates.d.ts +2 -2
  18. package/src/core/geom/3d/topology/simplify/build_edge_collapse_candidates.d.ts.map +1 -1
  19. package/src/core/geom/3d/topology/simplify/build_edge_collapse_candidates.js +1 -1
  20. package/src/core/geom/3d/topology/simplify/computeEdgeCollapseCost.d.ts +2 -2
  21. package/src/core/geom/3d/topology/simplify/computeEdgeCollapseCost.d.ts.map +1 -1
  22. package/src/core/geom/3d/topology/simplify/computeEdgeCollapseCost.js +1 -1
  23. package/src/core/geom/3d/topology/simplify/decimate_edge_collapse_snap.d.ts +4 -4
  24. package/src/core/geom/3d/topology/simplify/decimate_edge_collapse_snap.d.ts.map +1 -1
  25. package/src/core/geom/3d/topology/simplify/decimate_edge_collapse_snap.js +3 -3
  26. package/src/core/geom/3d/topology/simplify/quadratic/{Quadratic3.d.ts → Quadric3.d.ts} +55 -29
  27. package/src/core/geom/3d/topology/simplify/quadratic/Quadric3.d.ts.map +1 -0
  28. package/src/core/geom/3d/topology/simplify/quadratic/Quadric3.js +307 -0
  29. package/src/core/geom/3d/topology/simplify/quadratic/build_vertex_quadratics.d.ts +7 -7
  30. package/src/core/geom/3d/topology/simplify/quadratic/build_vertex_quadratics.d.ts.map +1 -1
  31. package/src/core/geom/3d/topology/simplify/quadratic/build_vertex_quadratics.js +39 -13
  32. package/src/core/geom/3d/topology/simplify/quadratic/compute_edge_collapse_cost_quadratic.d.ts +2 -2
  33. package/src/core/geom/3d/topology/simplify/quadratic/compute_edge_collapse_cost_quadratic.d.ts.map +1 -1
  34. package/src/core/geom/3d/topology/simplify/quadratic/compute_edge_collapse_cost_quadratic.js +1 -1
  35. package/src/core/geom/3d/topology/simplify/simplifyTopoMesh.d.ts +2 -2
  36. package/src/core/geom/3d/topology/simplify/simplifyTopoMesh.d.ts.map +1 -1
  37. package/src/core/geom/3d/topology/simplify/simplifyTopoMesh.js +2 -2
  38. package/src/core/geom/3d/topology/simplify/simplifyTopoMesh2.d.ts +4 -4
  39. package/src/core/geom/3d/topology/simplify/simplifyTopoMesh2.d.ts.map +1 -1
  40. package/src/core/geom/3d/topology/simplify/simplifyTopoMesh2.js +5 -5
  41. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_face_normals.d.ts +8 -0
  42. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_face_normals.d.ts.map +1 -0
  43. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_face_normals.js +56 -0
  44. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadratics.d.ts +14 -0
  45. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadratics.d.ts.map +1 -0
  46. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadratics.js +95 -0
  47. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts +17 -0
  48. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts.map +1 -0
  49. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.js +352 -0
  50. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_collapse.d.ts +21 -0
  51. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_collapse.d.ts.map +1 -0
  52. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_collapse.js +52 -0
  53. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill_parallels.d.ts +16 -0
  54. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill_parallels.d.ts.map +1 -0
  55. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill_parallels.js +90 -0
  56. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_fuse_duplicate_edges.d.ts +19 -0
  57. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_fuse_duplicate_edges.d.ts.map +1 -0
  58. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_fuse_duplicate_edges.js +83 -0
  59. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vert_fuse_duplicate_edges.d.ts +22 -0
  60. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vert_fuse_duplicate_edges.d.ts.map +1 -0
  61. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vert_fuse_duplicate_edges.js +148 -0
  62. package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_incenter.js +4 -4
  63. package/src/core/geom/3d/topology/struct/binary/query/bt_faces_shared_loop.d.ts +15 -0
  64. package/src/core/geom/3d/topology/struct/binary/query/bt_faces_shared_loop.d.ts.map +1 -0
  65. package/src/core/geom/3d/topology/struct/binary/query/bt_faces_shared_loop.js +48 -0
  66. package/src/engine/ecs/terrain/ecs/Terrain.d.ts.map +1 -1
  67. package/src/engine/ecs/terrain/ecs/Terrain.js +6 -1
  68. package/src/engine/ecs/terrain/ecs/layers/TerrainLayer.d.ts.map +1 -1
  69. package/src/engine/ecs/terrain/ecs/layers/TerrainLayer.js +10 -9
  70. package/src/engine/ecs/terrain/ecs/layers/TerrainLayers.d.ts.map +1 -1
  71. package/src/engine/ecs/terrain/ecs/layers/TerrainLayers.js +14 -11
  72. package/src/engine/graphics/ecs/water/WaterSystem.d.ts.map +1 -1
  73. package/src/engine/graphics/ecs/water/WaterSystem.js +3 -0
  74. package/src/engine/graphics/material/SplatMaterial.d.ts.map +1 -1
  75. package/src/engine/graphics/material/SplatMaterial.js +2 -4
  76. package/src/engine/graphics/shaders/TerrainShader.js +4 -11
  77. package/src/engine/navigation/mesh/NavigationMesh.d.ts +6 -4
  78. package/src/engine/navigation/mesh/NavigationMesh.d.ts.map +1 -1
  79. package/src/engine/navigation/mesh/NavigationMesh.js +212 -190
  80. package/src/engine/navigation/mesh/build/navmesh_build_topology.d.ts.map +1 -1
  81. package/src/engine/navigation/mesh/build/navmesh_build_topology.js +20 -7
  82. package/src/engine/navigation/mesh/bvh_query_nearest_face.d.ts +15 -0
  83. package/src/engine/navigation/mesh/bvh_query_nearest_face.d.ts.map +1 -0
  84. package/src/engine/navigation/mesh/bvh_query_nearest_face.js +131 -0
  85. package/src/engine/physics/gjk/gjk.d.ts +16 -0
  86. package/src/engine/physics/gjk/gjk.d.ts.map +1 -0
  87. package/src/engine/physics/gjk/gjk.js +378 -0
  88. package/src/core/geom/3d/topology/simplify/quadratic/Quadratic3.d.ts.map +0 -1
  89. package/src/core/geom/3d/topology/simplify/quadratic/Quadratic3.js +0 -302
@@ -1,190 +1,212 @@
1
- import { BVH } from "../../../core/bvh2/bvh3/BVH.js";
2
- import { array_copy } from "../../../core/collection/array/array_copy.js";
3
- import { BinaryTopology, NULL_POINTER } from "../../../core/geom/3d/topology/struct/binary/BinaryTopology.js";
4
- import Vector3 from "../../../core/geom/Vector3.js";
5
- import { bt_mesh_face_find_path } from "./bt_mesh_face_find_path.js";
6
- import { navmesh_build_topology } from "./build/navmesh_build_topology.js";
7
- import { bvh_build_from_bt_mesh } from "./bvh_build_from_bt_mesh.js";
8
- import { funnel_string_pull } from "./funnel_string_pull.js";
9
-
10
- const scratch_array_u32 = new Uint32Array(1024);
11
-
12
- const scratch_portal_vertices = new Uint32Array(1024 * 2);
13
-
14
- const scratch_portal_normals = new Float32Array(1024 * 3);
15
-
16
- const scratch_vertices = new Float32Array(1024 * 3 * 3);
17
-
18
- /**
19
- *
20
- * @param {number} x
21
- * @param {number} y
22
- * @param {number} z
23
- * @param {BinaryTopology} topology
24
- * @param {BVH} bvh
25
- * @returns {number} face id, or {@link NULL_POINTER} if not found
26
- */
27
- function query_nearest_face(
28
- x, y, z,
29
- topology,
30
- bvh,
31
- ) {
32
-
33
- throw new Error('Not implemented');
34
- }
35
-
36
- export class NavigationMesh {
37
-
38
- topology = new BinaryTopology();
39
-
40
- /**
41
- * Used for raycasts and neighborhood search.
42
- * @type {BVH}
43
- */
44
- bvh = new BVH();
45
-
46
- /**
47
- * Build from given scene geometry
48
- * @param {BinaryTopology} source
49
- * @param {number} [agent_radius]
50
- * @param {number} [agent_height]
51
- * @param {number} [agent_max_climb] In radians, how steep of an angle can the agent go up by
52
- * @param {Vector3} [up] Defines world's "UP" direction, this is what the agent will respect for climbing constraint
53
- */
54
- build({
55
- source,
56
- agent_radius = 0,
57
- agent_height = 0,
58
- agent_max_climb = Math.PI / 4,
59
- up = Vector3.up,
60
- }) {
61
-
62
- navmesh_build_topology({
63
- destination: this.topology,
64
- source,
65
- agent_radius,
66
- agent_height,
67
- agent_max_climb,
68
- up,
69
- });
70
-
71
- bvh_build_from_bt_mesh(this.bvh, this.topology);
72
- }
73
-
74
-
75
- /**
76
- *
77
- * @param {Float32Array} output
78
- * @param {number} start_x
79
- * @param {number} start_y
80
- * @param {number} start_z
81
- * @param {number} goal_x
82
- * @param {number} goal_y
83
- * @param {number} goal_z
84
- * @returns {number}
85
- */
86
- find_path(
87
- output,
88
- start_x, start_y, start_z,
89
- goal_x, goal_y, goal_z
90
- ) {
91
-
92
- const mesh = this.topology;
93
-
94
- const start_face_id = query_nearest_face(start_x, start_y, start_z, mesh, this.bvh);
95
-
96
- if (start_face_id === NULL_POINTER) {
97
- // probably topology is empty
98
- return 0;
99
- }
100
-
101
- const goal_face_id = query_nearest_face(goal_x, goal_y, goal_z, mesh, this.bvh);
102
-
103
- if (goal_face_id === NULL_POINTER) {
104
- // should never happen
105
- return 0;
106
- }
107
-
108
- if (goal_face_id === start_face_id) {
109
- // path within the same triangle
110
-
111
- output[0] = start_x;
112
- output[1] = start_y;
113
- output[2] = start_z;
114
-
115
- output[3] = goal_x;
116
- output[4] = goal_y;
117
- output[5] = goal_z;
118
-
119
- return 2;
120
- }
121
-
122
- const face_path_length = bt_mesh_face_find_path(scratch_array_u32, start_face_id, goal_face_id, mesh);
123
-
124
- // build portals
125
- // ==================
126
-
127
- // initialize vertex data pool
128
- scratch_vertices[0] = start_x;
129
- scratch_vertices[1] = start_y;
130
- scratch_vertices[2] = start_z;
131
-
132
- scratch_vertices[3] = goal_x;
133
- scratch_vertices[4] = goal_y;
134
- scratch_vertices[5] = goal_z;
135
-
136
-
137
- // add start portal
138
- scratch_portal_vertices[0] = 0;
139
- scratch_portal_vertices[1] = 0;
140
-
141
- mesh.face_read_normal(scratch_portal_normals, 0, start_face_id);
142
-
143
- let portal_index = 1;
144
-
145
- for (let i = 0; i < face_path_length; i++) {
146
-
147
- const face_id = scratch_array_u32[i];
148
-
149
- // TODO IMPLEMENTATION OF PORTAL SEQUENCE GOES HERE
150
-
151
- }
152
-
153
- // add goal portal
154
- scratch_portal_vertices[portal_index] = 1;
155
- scratch_portal_vertices[portal_index + 1] = 0;
156
-
157
- // copy last portal normal
158
- array_copy(
159
- scratch_portal_normals, (portal_index - 1) * 2,
160
- scratch_portal_normals, portal_index * 2,
161
- 3
162
- );
163
-
164
- portal_index++;
165
-
166
- // execute string pulling
167
- const path_vertex_count = funnel_string_pull(
168
- scratch_array_u32,
169
- 0,
170
- scratch_portal_vertices,
171
- scratch_portal_normals,
172
- portal_index,
173
- scratch_vertices,
174
- );
175
-
176
- // build the final path
177
- for (let i = 0; i < path_vertex_count; i++) {
178
- const vertex_index = scratch_array_u32[i];
179
-
180
- output[i * 3] = scratch_vertices[vertex_index * 3];
181
- output[i * 3 + 1] = scratch_vertices[vertex_index * 3 + 1];
182
- output[i * 3 + 2] = scratch_vertices[vertex_index * 3 + 2];
183
-
184
- }
185
-
186
- return path_vertex_count;
187
-
188
- }
189
-
190
- }
1
+ import { BVH } from "../../../core/bvh2/bvh3/BVH.js";
2
+ import { BinaryTopology, NULL_POINTER } from "../../../core/geom/3d/topology/struct/binary/BinaryTopology.js";
3
+ import { bt_faces_shared_loop } from "../../../core/geom/3d/topology/struct/binary/query/bt_faces_shared_loop.js";
4
+ import Vector3 from "../../../core/geom/Vector3.js";
5
+ import { bt_mesh_face_find_path } from "./bt_mesh_face_find_path.js";
6
+ import { navmesh_build_topology } from "./build/navmesh_build_topology.js";
7
+ import { bvh_build_from_bt_mesh } from "./bvh_build_from_bt_mesh.js";
8
+ import { bvh_query_nearest_face } from "./bvh_query_nearest_face.js";
9
+ import { funnel_string_pull } from "./funnel_string_pull.js";
10
+
11
+ /**
12
+ * Hard cap on the number of faces we traverse in a single path query.
13
+ * Limits scratch buffer sizes; paths longer than this are truncated by the A* search.
14
+ * @type {number}
15
+ */
16
+ const MAX_FACE_PATH_LENGTH = 1024;
17
+
18
+ // face path IDs or (later) final path vertex indices
19
+ const scratch_array_u32 = new Uint32Array(MAX_FACE_PATH_LENGTH);
20
+
21
+ // one more portal than face-path length (start portal + one between each consecutive pair of faces + goal portal)
22
+ const MAX_PORTAL_COUNT = MAX_FACE_PATH_LENGTH + 1;
23
+
24
+ // [left0, right0, left1, right1, ...]
25
+ const scratch_portal_vertices = new Uint32Array(MAX_PORTAL_COUNT * 2);
26
+
27
+ // flat XYZ triples, one per portal
28
+ const scratch_portal_normals = new Float32Array(MAX_PORTAL_COUNT * 3);
29
+
30
+ // flat XYZ triples; indices 0 and 1 are start/goal, then 2 vertices per intermediate portal
31
+ const scratch_vertices = new Float32Array((2 + (MAX_PORTAL_COUNT - 2) * 2) * 3);
32
+
33
+ export class NavigationMesh {
34
+
35
+ topology = new BinaryTopology();
36
+
37
+ /**
38
+ * Used for raycasts and neighborhood search.
39
+ * @type {BVH}
40
+ */
41
+ bvh = new BVH();
42
+
43
+ /**
44
+ * Build from given scene geometry
45
+ * @param {BinaryTopology} source
46
+ * @param {number} [agent_radius]
47
+ * @param {number} [agent_height]
48
+ * @param {number} [agent_max_climb_angle] In radians, how steep of an angle can the agent go up by
49
+ * @param {Vector3} [up] Defines world's "UP" direction, this is what the agent will respect for climbing constraint
50
+ */
51
+ build({
52
+ source,
53
+ agent_radius = 0,
54
+ agent_height = 0,
55
+ agent_max_climb_angle = Math.PI / 4,
56
+ up = Vector3.up,
57
+ }) {
58
+
59
+ navmesh_build_topology({
60
+ destination: this.topology,
61
+ source,
62
+ agent_radius,
63
+ agent_height,
64
+ agent_max_climb_angle,
65
+ up,
66
+ });
67
+
68
+ bvh_build_from_bt_mesh(this.bvh, this.topology);
69
+ }
70
+
71
+
72
+ /**
73
+ * Compute a walkable path between the two points.
74
+ * The result is a sequence of 3d points written into `output`. First point matches start, last point matches goal (snapped onto the mesh).
75
+ *
76
+ * @param {Float32Array} output packed XYZ triples
77
+ * @param {number} start_x
78
+ * @param {number} start_y
79
+ * @param {number} start_z
80
+ * @param {number} goal_x
81
+ * @param {number} goal_y
82
+ * @param {number} goal_z
83
+ * @returns {number} number of 3d points written to `output` (0 if no path was found)
84
+ */
85
+ find_path(
86
+ output,
87
+ start_x, start_y, start_z,
88
+ goal_x, goal_y, goal_z
89
+ ) {
90
+
91
+ const mesh = this.topology;
92
+ const bvh = this.bvh;
93
+
94
+ const start_face_id = bvh_query_nearest_face(bvh, mesh, start_x, start_y, start_z);
95
+
96
+ if (start_face_id === NULL_POINTER) {
97
+ // probably topology is empty
98
+ return 0;
99
+ }
100
+
101
+ const goal_face_id = bvh_query_nearest_face(bvh, mesh, goal_x, goal_y, goal_z);
102
+
103
+ if (goal_face_id === NULL_POINTER) {
104
+ // should never happen if we got the start face
105
+ return 0;
106
+ }
107
+
108
+ if (goal_face_id === start_face_id) {
109
+ // path within the same triangle
110
+
111
+ output[0] = start_x;
112
+ output[1] = start_y;
113
+ output[2] = start_z;
114
+
115
+ output[3] = goal_x;
116
+ output[4] = goal_y;
117
+ output[5] = goal_z;
118
+
119
+ return 2;
120
+ }
121
+
122
+ const face_path_length = bt_mesh_face_find_path(scratch_array_u32, start_face_id, goal_face_id, mesh);
123
+
124
+ if (face_path_length === 0) {
125
+ // no face path exists (disconnected topology)
126
+ return 0;
127
+ }
128
+
129
+ // build portals
130
+ // ==================
131
+
132
+ // initialize vertex data pool, vertex index 0 = start, vertex index 1 = goal
133
+ scratch_vertices[0] = start_x;
134
+ scratch_vertices[1] = start_y;
135
+ scratch_vertices[2] = start_z;
136
+
137
+ scratch_vertices[3] = goal_x;
138
+ scratch_vertices[4] = goal_y;
139
+ scratch_vertices[5] = goal_z;
140
+
141
+ let next_vertex_index = 2;
142
+
143
+ // start portal, degenerate portal at the start point, exiting the start face
144
+ scratch_portal_vertices[0] = 0;
145
+ scratch_portal_vertices[1] = 0;
146
+
147
+ mesh.face_read_normal(scratch_portal_normals, 0, start_face_id);
148
+
149
+ let portal_index = 1;
150
+
151
+ // intermediate portals sit on the shared edge between two consecutive faces along the path;
152
+ // the edge is read in the winding order of the face we are exiting, giving a directed (left, right) pair
153
+ for (let i = 1; i < face_path_length; i++) {
154
+
155
+ const face_from = scratch_array_u32[i - 1];
156
+ const face_to = scratch_array_u32[i];
157
+
158
+ const loop = bt_faces_shared_loop(mesh, face_from, face_to);
159
+
160
+ const left_vertex = mesh.loop_read_vertex(loop);
161
+ const right_vertex = mesh.loop_read_vertex(mesh.loop_read_next(loop));
162
+
163
+ const left_index = next_vertex_index++;
164
+ const right_index = next_vertex_index++;
165
+
166
+ mesh.vertex_read_coordinate(scratch_vertices, left_index * 3, left_vertex);
167
+ mesh.vertex_read_coordinate(scratch_vertices, right_index * 3, right_vertex);
168
+
169
+ const portal_address = portal_index * 2;
170
+ scratch_portal_vertices[portal_address] = left_index;
171
+ scratch_portal_vertices[portal_address + 1] = right_index;
172
+
173
+ mesh.face_read_normal(scratch_portal_normals, portal_index * 3, face_from);
174
+
175
+ portal_index++;
176
+ }
177
+
178
+ // goal portal, degenerate at the goal point, uses the normal of the face containing the goal
179
+ const goal_portal_address = portal_index * 2;
180
+
181
+ scratch_portal_vertices[goal_portal_address] = 1;
182
+ scratch_portal_vertices[goal_portal_address + 1] = 1;
183
+
184
+ mesh.face_read_normal(scratch_portal_normals, portal_index * 3, goal_face_id);
185
+
186
+ portal_index++;
187
+
188
+ // execute string pulling
189
+ const path_vertex_count = funnel_string_pull(
190
+ scratch_array_u32,
191
+ 0,
192
+ scratch_portal_vertices,
193
+ scratch_portal_normals,
194
+ portal_index,
195
+ scratch_vertices,
196
+ );
197
+
198
+ // build the final path
199
+ for (let i = 0; i < path_vertex_count; i++) {
200
+ const vertex_index = scratch_array_u32[i];
201
+
202
+ output[i * 3] = scratch_vertices[vertex_index * 3];
203
+ output[i * 3 + 1] = scratch_vertices[vertex_index * 3 + 1];
204
+ output[i * 3 + 2] = scratch_vertices[vertex_index * 3 + 2];
205
+
206
+ }
207
+
208
+ return path_vertex_count;
209
+
210
+ }
211
+
212
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"navmesh_build_topology.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/navigation/mesh/build/navmesh_build_topology.js"],"names":[],"mappings":"AAgCA;;;;;;;;;;GAUG;AACH,wKATW,cAAc,QAoJxB;+BApL8B,mEAAmE"}
1
+ {"version":3,"file":"navmesh_build_topology.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/navigation/mesh/build/navmesh_build_topology.js"],"names":[],"mappings":"AAsCA;;;;;;;;;;GAUG;AACH,wKATW,cAAc,QA2JxB;+BAjM8B,mEAAmE"}
@@ -4,6 +4,9 @@ import { BinaryTopology } from "../../../../core/geom/3d/topology/struct/binary/
4
4
  import {
5
5
  bt_mesh_cleanup_faceless_references
6
6
  } from "../../../../core/geom/3d/topology/struct/binary/io/bt_mesh_cleanup_faceless_references.js";
7
+ import {
8
+ bt_mesh_compute_face_normals
9
+ } from "../../../../core/geom/3d/topology/struct/binary/io/bt_mesh_compute_face_normals.js";
7
10
 
8
11
  import {
9
12
  bt_mesh_face_decouple_islands
@@ -15,6 +18,9 @@ import {
15
18
  bt_mesh_from_unindexed_geometry
16
19
  } from "../../../../core/geom/3d/topology/struct/binary/io/bt_mesh_from_unindexed_geometry.js";
17
20
  import { bt_mesh_triangulate } from "../../../../core/geom/3d/topology/struct/binary/io/bt_mesh_triangulate.js";
21
+ import {
22
+ bt_mesh_fuse_duplicate_edges
23
+ } from "../../../../core/geom/3d/topology/struct/binary/io/edge/bt_mesh_fuse_duplicate_edges.js";
18
24
  import {
19
25
  bt_merge_verts_by_distance
20
26
  } from "../../../../core/geom/3d/topology/struct/binary/io/vertex/bt_merge_verts_by_distance.js";
@@ -149,18 +155,22 @@ export function navmesh_build_topology({
149
155
 
150
156
  const mesh = new BinaryTopology();
151
157
 
152
- // build topology
158
+ // raw_triangles may have stale tail data from filtering steps above (e.g. height clearance);
159
+ // bt_mesh_from_unindexed_geometry reads the whole array, so trim to the live range first.
160
+ raw_triangles.length = triangle_count * 9;
161
+
153
162
  bt_mesh_from_unindexed_geometry(mesh, raw_triangles);
154
163
 
164
+ // fuse coincident positions so neighbouring triangles share a vertex id...
165
+ bt_merge_verts_by_distance(mesh, 1e-6);
166
+
167
+ // ...then fuse the resulting duplicate edges so they share an edge id too,
168
+ // which is what the loop-based neighbour queries rely on
169
+ bt_mesh_fuse_duplicate_edges(mesh);
170
+
155
171
  const mesh_bounds = new Float32Array(6);
156
172
  bvh.node_get_aabb(bvh.root, mesh_bounds);
157
173
 
158
- // dedupe vertices
159
- bt_merge_verts_by_distance(
160
- mesh,
161
- 1e-6
162
- );
163
-
164
174
  const islands = bt_mesh_compute_face_islands(mesh);
165
175
 
166
176
  // enabled us to modify islands independently
@@ -176,6 +186,9 @@ export function navmesh_build_topology({
176
186
  // remove dangling references
177
187
  bt_mesh_cleanup_faceless_references(mesh);
178
188
 
189
+ // face normals are consumed by navigation queries (string-pulling portal normals), populate them now
190
+ bt_mesh_compute_face_normals(mesh);
191
+
179
192
  // write out to destination
180
193
  destination.copy(mesh);
181
194
  }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Find the face of `mesh` whose surface is closest to the given point.
3
+ * Expects `bvh` to have been built by {@link bvh_build_from_bt_mesh}, so each leaf's user data is a face ID.
4
+ * Faces are expected to be triangles (as produced by the navmesh build pipeline).
5
+ *
6
+ * @param {BVH} bvh
7
+ * @param {BinaryTopology} mesh
8
+ * @param {number} x
9
+ * @param {number} y
10
+ * @param {number} z
11
+ * @param {number} [max_distance=Infinity] optional cutoff, only faces within this distance are considered
12
+ * @returns {number} face ID of the nearest face, or {@link NULL_POINTER} if no face was found within the cutoff
13
+ */
14
+ export function bvh_query_nearest_face(bvh: BVH, mesh: BinaryTopology, x: number, y: number, z: number, max_distance?: number): number;
15
+ //# sourceMappingURL=bvh_query_nearest_face.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bvh_query_nearest_face.d.ts","sourceRoot":"","sources":["../../../../../src/engine/navigation/mesh/bvh_query_nearest_face.js"],"names":[],"mappings":"AAwBA;;;;;;;;;;;;GAYG;AACH,0EANW,MAAM,KACN,MAAM,KACN,MAAM,iBACN,MAAM,GACJ,MAAM,CA+FlB"}
@@ -0,0 +1,131 @@
1
+ import { assert } from "../../../core/assert.js";
2
+ import {
3
+ COLUMN_CHILD_1,
4
+ COLUMN_CHILD_2,
5
+ COLUMN_USER_DATA,
6
+ ELEMENT_WORD_COUNT,
7
+ NULL_NODE
8
+ } from "../../../core/bvh2/bvh3/BVH.js";
9
+ import { SCRATCH_UINT32_TRAVERSAL_STACK } from "../../../core/collection/SCRATCH_UINT32_TRAVERSAL_STACK.js";
10
+ import {
11
+ aabb3_unsigned_distance_sqr_to_point
12
+ } from "../../../core/geom/3d/aabb/aabb3_unsigned_distance_sqr_to_point.js";
13
+ import { NULL_POINTER } from "../../../core/geom/3d/topology/struct/binary/BinaryTopology.js";
14
+ import {
15
+ computeTriangleClosestPointToPointBarycentric
16
+ } from "../../../core/geom/3d/triangle/computeTriangleClosestPointToPointBarycentric.js";
17
+
18
+ const stack = SCRATCH_UINT32_TRAVERSAL_STACK;
19
+
20
+ const scratch_barycentric = new Float32Array(2);
21
+ const scratch_coord_a = new Float32Array(3);
22
+ const scratch_coord_b = new Float32Array(3);
23
+ const scratch_coord_c = new Float32Array(3);
24
+
25
+ /**
26
+ * Find the face of `mesh` whose surface is closest to the given point.
27
+ * Expects `bvh` to have been built by {@link bvh_build_from_bt_mesh}, so each leaf's user data is a face ID.
28
+ * Faces are expected to be triangles (as produced by the navmesh build pipeline).
29
+ *
30
+ * @param {BVH} bvh
31
+ * @param {BinaryTopology} mesh
32
+ * @param {number} x
33
+ * @param {number} y
34
+ * @param {number} z
35
+ * @param {number} [max_distance=Infinity] optional cutoff, only faces within this distance are considered
36
+ * @returns {number} face ID of the nearest face, or {@link NULL_POINTER} if no face was found within the cutoff
37
+ */
38
+ export function bvh_query_nearest_face(bvh, mesh, x, y, z, max_distance = Infinity) {
39
+ assert.defined(bvh, "bvh");
40
+ assert.defined(mesh, "mesh");
41
+ assert.equal(mesh.isBinaryTopology, true, "mesh.isBinaryTopology !== true");
42
+
43
+ const root = bvh.root;
44
+
45
+ if (root === NULL_NODE) {
46
+ return NULL_POINTER;
47
+ }
48
+
49
+ const stack_top = stack.pointer++;
50
+
51
+ stack[stack_top] = root;
52
+
53
+ let best_face = NULL_POINTER;
54
+ let best_distance_sqr = max_distance * max_distance;
55
+
56
+ const float32 = bvh.__data_float32;
57
+ const uint32 = bvh.__data_uint32;
58
+
59
+ do {
60
+ stack.pointer--;
61
+
62
+ const node = stack[stack.pointer];
63
+ const address = node * ELEMENT_WORD_COUNT;
64
+
65
+ // lower bound on distance via AABB
66
+ const aabb_distance_sqr = aabb3_unsigned_distance_sqr_to_point(
67
+ float32[address], float32[address + 1], float32[address + 2],
68
+ float32[address + 3], float32[address + 4], float32[address + 5],
69
+ x, y, z
70
+ );
71
+
72
+ if (aabb_distance_sqr >= best_distance_sqr) {
73
+ // this subtree cannot contain a closer face
74
+ continue;
75
+ }
76
+
77
+ const child_1 = uint32[address + COLUMN_CHILD_1];
78
+
79
+ if (child_1 !== NULL_NODE) {
80
+ // internal node, descend into both children
81
+ stack[stack.pointer++] = child_1;
82
+ stack[stack.pointer++] = uint32[address + COLUMN_CHILD_2];
83
+ continue;
84
+ }
85
+
86
+ // leaf node: refine with actual triangle distance
87
+ const face_id = uint32[address + COLUMN_USER_DATA];
88
+
89
+ const loop_a = mesh.face_read_loop(face_id);
90
+
91
+ if (loop_a === NULL_POINTER) {
92
+ continue;
93
+ }
94
+
95
+ const loop_b = mesh.loop_read_next(loop_a);
96
+ const loop_c = mesh.loop_read_next(loop_b);
97
+
98
+ mesh.vertex_read_coordinate(scratch_coord_a, 0, mesh.loop_read_vertex(loop_a));
99
+ mesh.vertex_read_coordinate(scratch_coord_b, 0, mesh.loop_read_vertex(loop_b));
100
+ mesh.vertex_read_coordinate(scratch_coord_c, 0, mesh.loop_read_vertex(loop_c));
101
+
102
+ computeTriangleClosestPointToPointBarycentric(
103
+ scratch_barycentric, 0,
104
+ x, y, z,
105
+ scratch_coord_a[0], scratch_coord_a[1], scratch_coord_a[2],
106
+ scratch_coord_b[0], scratch_coord_b[1], scratch_coord_b[2],
107
+ scratch_coord_c[0], scratch_coord_c[1], scratch_coord_c[2]
108
+ );
109
+
110
+ const weight_a = scratch_barycentric[0];
111
+ const weight_b = scratch_barycentric[1];
112
+ const weight_c = 1 - weight_a - weight_b;
113
+
114
+ const contact_x = scratch_coord_a[0] * weight_a + scratch_coord_b[0] * weight_b + scratch_coord_c[0] * weight_c;
115
+ const contact_y = scratch_coord_a[1] * weight_a + scratch_coord_b[1] * weight_b + scratch_coord_c[1] * weight_c;
116
+ const contact_z = scratch_coord_a[2] * weight_a + scratch_coord_b[2] * weight_b + scratch_coord_c[2] * weight_c;
117
+
118
+ const dx = contact_x - x;
119
+ const dy = contact_y - y;
120
+ const dz = contact_z - z;
121
+
122
+ const triangle_distance_sqr = dx * dx + dy * dy + dz * dz;
123
+
124
+ if (triangle_distance_sqr < best_distance_sqr) {
125
+ best_distance_sqr = triangle_distance_sqr;
126
+ best_face = face_id;
127
+ }
128
+ } while (stack.pointer > stack_top);
129
+
130
+ return best_face;
131
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * GJK intersection test for two convex shapes.
3
+ *
4
+ * Determines whether two convex shapes overlap by iteratively building a simplex
5
+ * in the Minkowski difference space. If the origin is enclosed by the simplex,
6
+ * the shapes intersect.
7
+ *
8
+ * Adapted from https://github.com/kevinmoran/GJK/blob/master/GJK.h
9
+ *
10
+ * @param {number[]|Float32Array} simplex Working buffer for simplex vertices (4 vec3s). Must have length >= 12.
11
+ * @param {AbstractShape3D} shape_a
12
+ * @param {AbstractShape3D} shape_b
13
+ * @returns {boolean} true if the shapes intersect
14
+ */
15
+ export function gjk(simplex: number[] | Float32Array, shape_a: AbstractShape3D, shape_b: AbstractShape3D): boolean;
16
+ //# sourceMappingURL=gjk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gjk.d.ts","sourceRoot":"","sources":["../../../../../src/engine/physics/gjk/gjk.js"],"names":[],"mappings":"AAmDA;;;;;;;;;;;;;GAaG;AACH,6BALW,MAAM,EAAE,GAAC,YAAY,uDAGnB,OAAO,CAkGnB"}