@woosh/meep-engine 2.133.5 → 2.134.1
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.
- package/build/bundle-worker-image-decoder.js +1 -1
- package/package.json +1 -1
- package/src/core/binary/BinaryBuffer.d.ts +20 -0
- package/src/core/binary/BinaryBuffer.d.ts.map +1 -1
- package/src/core/binary/BinaryBuffer.js +50 -0
- package/src/core/geom/3d/topology/simplify/EdgeCollapseCandidate.d.ts +4 -4
- package/src/core/geom/3d/topology/simplify/EdgeCollapseCandidate.d.ts.map +1 -1
- package/src/core/geom/3d/topology/simplify/EdgeCollapseCandidate.js +2 -2
- package/src/core/geom/3d/topology/simplify/build_edge_collapse_candidates.d.ts +2 -2
- package/src/core/geom/3d/topology/simplify/build_edge_collapse_candidates.d.ts.map +1 -1
- package/src/core/geom/3d/topology/simplify/build_edge_collapse_candidates.js +1 -1
- package/src/core/geom/3d/topology/simplify/computeEdgeCollapseCost.d.ts +2 -2
- package/src/core/geom/3d/topology/simplify/computeEdgeCollapseCost.d.ts.map +1 -1
- package/src/core/geom/3d/topology/simplify/computeEdgeCollapseCost.js +1 -1
- package/src/core/geom/3d/topology/simplify/decimate_edge_collapse_snap.d.ts +4 -4
- package/src/core/geom/3d/topology/simplify/decimate_edge_collapse_snap.d.ts.map +1 -1
- package/src/core/geom/3d/topology/simplify/decimate_edge_collapse_snap.js +3 -3
- package/src/core/geom/3d/topology/simplify/quadratic/{Quadratic3.d.ts → Quadric3.d.ts} +55 -29
- package/src/core/geom/3d/topology/simplify/quadratic/Quadric3.d.ts.map +1 -0
- package/src/core/geom/3d/topology/simplify/quadratic/Quadric3.js +307 -0
- package/src/core/geom/3d/topology/simplify/quadratic/build_vertex_quadratics.d.ts +7 -7
- package/src/core/geom/3d/topology/simplify/quadratic/build_vertex_quadratics.d.ts.map +1 -1
- package/src/core/geom/3d/topology/simplify/quadratic/build_vertex_quadratics.js +39 -13
- package/src/core/geom/3d/topology/simplify/quadratic/compute_edge_collapse_cost_quadratic.d.ts +2 -2
- package/src/core/geom/3d/topology/simplify/quadratic/compute_edge_collapse_cost_quadratic.d.ts.map +1 -1
- package/src/core/geom/3d/topology/simplify/quadratic/compute_edge_collapse_cost_quadratic.js +1 -1
- package/src/core/geom/3d/topology/simplify/simplifyTopoMesh.d.ts +2 -2
- package/src/core/geom/3d/topology/simplify/simplifyTopoMesh.d.ts.map +1 -1
- package/src/core/geom/3d/topology/simplify/simplifyTopoMesh.js +2 -2
- package/src/core/geom/3d/topology/simplify/simplifyTopoMesh2.d.ts +4 -4
- package/src/core/geom/3d/topology/simplify/simplifyTopoMesh2.d.ts.map +1 -1
- package/src/core/geom/3d/topology/simplify/simplifyTopoMesh2.js +5 -5
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_face_normals.d.ts +8 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_face_normals.d.ts.map +1 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_face_normals.js +56 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadratics.d.ts +14 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadratics.d.ts.map +1 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadratics.js +95 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts +17 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts.map +1 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.js +352 -0
- package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_collapse.d.ts +21 -0
- package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_collapse.d.ts.map +1 -0
- package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_collapse.js +52 -0
- package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill_parallels.d.ts +16 -0
- package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill_parallels.d.ts.map +1 -0
- package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill_parallels.js +90 -0
- package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_fuse_duplicate_edges.d.ts +19 -0
- package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_fuse_duplicate_edges.d.ts.map +1 -0
- package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_fuse_duplicate_edges.js +83 -0
- package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vert_fuse_duplicate_edges.d.ts +22 -0
- package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vert_fuse_duplicate_edges.d.ts.map +1 -0
- package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vert_fuse_duplicate_edges.js +148 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_incenter.js +4 -4
- package/src/core/geom/3d/topology/struct/binary/query/bt_faces_shared_loop.d.ts +15 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_faces_shared_loop.d.ts.map +1 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_faces_shared_loop.js +48 -0
- package/src/core/graph/coloring/colorizeGraphMCS.js +1 -1
- package/src/core/graph/convert_graph_to_dot_string.d.ts.map +1 -1
- package/src/core/graph/convert_graph_to_dot_string.js +2 -1
- package/src/core/graph/graph_compute_distance_matrix.d.ts +18 -1
- package/src/core/graph/graph_compute_distance_matrix.d.ts.map +1 -1
- package/src/core/graph/graph_compute_distance_matrix.js +21 -2
- package/src/core/graph/graph_compute_laplacian_matrix.d.ts.map +1 -1
- package/src/core/graph/graph_compute_laplacian_matrix.js +2 -1
- package/src/core/graph/graph_k_means_cluster.d.ts +10 -3
- package/src/core/graph/graph_k_means_cluster.d.ts.map +1 -1
- package/src/core/graph/graph_k_means_cluster.js +250 -123
- package/src/core/graph/layout/CircleLayout.js +6 -6
- package/src/core/graph/layout/Connection.js +1 -1
- package/src/core/graph/layout/box/aabb2_force_into_container.d.ts.map +1 -1
- package/src/core/graph/layout/box/aabb2_force_into_container.js +4 -2
- package/src/core/math/statistics/computeStatisticalMedian.js +1 -1
- package/src/engine/navigation/mesh/NavigationMesh.d.ts +6 -4
- package/src/engine/navigation/mesh/NavigationMesh.d.ts.map +1 -1
- package/src/engine/navigation/mesh/NavigationMesh.js +212 -190
- package/src/engine/navigation/mesh/build/navmesh_build_topology.d.ts.map +1 -1
- package/src/engine/navigation/mesh/build/navmesh_build_topology.js +20 -7
- package/src/engine/navigation/mesh/bvh_query_nearest_face.d.ts +15 -0
- package/src/engine/navigation/mesh/bvh_query_nearest_face.d.ts.map +1 -0
- package/src/engine/navigation/mesh/bvh_query_nearest_face.js +131 -0
- package/src/core/geom/3d/topology/simplify/quadratic/Quadratic3.d.ts.map +0 -1
- 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 {
|
|
3
|
-
import {
|
|
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 {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
)
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
*
|
|
48
|
-
* @param {
|
|
49
|
-
* @param {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
*
|
|
77
|
-
* @param {
|
|
78
|
-
* @param {number}
|
|
79
|
-
* @param {number}
|
|
80
|
-
* @param {number}
|
|
81
|
-
* @param {number}
|
|
82
|
-
* @param {number}
|
|
83
|
-
* @
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
const start_face_id =
|
|
95
|
-
|
|
96
|
-
if (start_face_id === NULL_POINTER) {
|
|
97
|
-
// probably topology is empty
|
|
98
|
-
return 0;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const goal_face_id =
|
|
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
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
scratch_vertices[
|
|
134
|
-
scratch_vertices[
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
scratch_portal_vertices
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
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":"
|
|
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
|
-
//
|
|
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
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Quadratic3.d.ts","sourceRoot":"","sources":["../../../../../../../../src/core/geom/3d/topology/simplify/quadratic/Quadratic3.js"],"names":[],"mappings":"AASA;;;GAGG;AACH;IAGI,WAAO;IACP,WAAO;IACP,WAAO;IACP,WAAO;IAGP,WAAO;IACP,WAAO;IACP,WAAO;IAGP,WAAO;IACP,WAAO;IAGP,WAAO;IAGP;;;OAGG;IACH,kBAFW,UAAU,MAAM,CAAC,GAAC,MAAM,EAAE,GAAC,YAAY,QAMjD;IAED;;;OAGG;IACH,eAFW,UAAU,MAAM,CAAC,GAAC,MAAM,EAAE,GAAC,YAAY,QAcjD;IAED;;;;;OAKG;IACH,sBAJW,UAAU,MAAM,CAAC,GAAC,MAAM,EAAE,GAAC,YAAY,WACvC,MAAM,GACJ,OAAO,CAkCnB;IAED;;;;;;OAMG;IACH,kBALW,MAAM,KACN,MAAM,KACN,MAAM,KACN,MAAM,QAgBhB;IAED;;;OAGG;IACH,sCAmBC;IAED;;;;;;OAMG;IACH,YALW,MAAM,KACN,MAAM,KACN,MAAM,GACJ,MAAM,CASlB;IAED;;;;;;;OAOG;IACH,cAHW,MAAM,EAAE,GACN,OAAO,CAgBnB;IAED;;;OAGG;IACH,OAFW,UAAU,QAuBpB;IAED;;;OAGG;IACH,kBAFW,MAAM,QAoBhB;IAED;;;OAGG;IACH,SAFa,UAAU,CAQtB;IAED;;;OAGG;IACH,YAFW,UAAU,QAqBpB;IAED;;OAEG;IACH,cAmBC;CACJ"}
|