@woosh/meep-engine 2.163.2 → 2.163.3
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/package.json +1 -1
- package/src/core/geom/3d/equirectangular/equirectangular_direction_to_uv.d.ts +12 -0
- package/src/core/geom/3d/equirectangular/equirectangular_direction_to_uv.d.ts.map +1 -0
- package/src/core/geom/3d/equirectangular/equirectangular_direction_to_uv.js +18 -0
- package/src/core/geom/3d/equirectangular/equirectangular_uv_to_direction.d.ts +14 -0
- package/src/core/geom/3d/equirectangular/equirectangular_uv_to_direction.d.ts.map +1 -0
- package/src/core/geom/3d/equirectangular/equirectangular_uv_to_direction.js +24 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_face_island_erode.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_face_island_erode.js +368 -290
- package/src/core/geom/vec3/v3_uniform_sample_cone.d.ts +11 -0
- package/src/core/geom/vec3/v3_uniform_sample_cone.d.ts.map +1 -0
- package/src/core/geom/vec3/v3_uniform_sample_cone.js +21 -0
- package/src/core/math/physics/brdf/cone_cosine_from_roughness.d.ts +13 -0
- package/src/core/math/physics/brdf/cone_cosine_from_roughness.d.ts.map +1 -0
- package/src/core/math/physics/brdf/cone_cosine_from_roughness.js +28 -0
- package/src/core/math/physics/brdf/reflection_sample_weight.d.ts +18 -0
- package/src/core/math/physics/brdf/reflection_sample_weight.d.ts.map +1 -0
- package/src/core/math/physics/brdf/reflection_sample_weight.js +48 -0
- package/src/engine/graphics/GraphicsEngine.d.ts.map +1 -1
- package/src/engine/graphics/GraphicsEngine.js +52 -0
- package/src/engine/graphics/sh3/sky/hosek/make_environment_sky_hosek.d.ts +26 -0
- package/src/engine/graphics/sh3/sky/hosek/make_environment_sky_hosek.d.ts.map +1 -0
- package/src/engine/graphics/sh3/sky/hosek/make_environment_sky_hosek.js +49 -0
- package/src/engine/graphics/sh3/sky/hosek/render_hosek_sky_to_equirectangular.d.ts +26 -0
- package/src/engine/graphics/sh3/sky/hosek/render_hosek_sky_to_equirectangular.d.ts.map +1 -0
- package/src/engine/graphics/sh3/sky/hosek/render_hosek_sky_to_equirectangular.js +70 -0
- package/src/engine/graphics/sh3/sky/hosek/setup_environment_sky_from_ecd.d.ts +24 -0
- package/src/engine/graphics/sh3/sky/hosek/setup_environment_sky_from_ecd.d.ts.map +1 -0
- package/src/engine/graphics/sh3/sky/hosek/setup_environment_sky_from_ecd.js +51 -0
- package/src/engine/graphics/texture/EnvironmentTextureProjection.d.ts +9 -0
- package/src/engine/graphics/texture/EnvironmentTextureProjection.d.ts.map +1 -0
- package/src/engine/graphics/texture/EnvironmentTextureProjection.js +15 -0
- package/src/engine/graphics/texture/reflection/convolve_equirectangular_reflection.d.ts +44 -0
- package/src/engine/graphics/texture/reflection/convolve_equirectangular_reflection.d.ts.map +1 -0
- package/src/engine/graphics/texture/reflection/convolve_equirectangular_reflection.js +189 -0
- package/src/engine/graphics/texture/reflection/equirectangular_reflection_roughness.d.ts +25 -0
- package/src/engine/graphics/texture/reflection/equirectangular_reflection_roughness.d.ts.map +1 -0
- package/src/engine/graphics/texture/reflection/equirectangular_reflection_roughness.js +51 -0
- package/src/engine/graphics/texture/sampler/sampler2d_sample_equirectangular_direction.d.ts +15 -0
- package/src/engine/graphics/texture/sampler/sampler2d_sample_equirectangular_direction.d.ts.map +1 -0
- package/src/engine/graphics/texture/sampler/sampler2d_sample_equirectangular_direction.js +63 -0
- package/src/engine/navigation/mesh/build/bt_mesh_carve_height_clearance.d.ts +27 -0
- package/src/engine/navigation/mesh/build/bt_mesh_carve_height_clearance.d.ts.map +1 -0
- package/src/engine/navigation/mesh/build/bt_mesh_carve_height_clearance.js +323 -0
- package/src/engine/navigation/mesh/build/navmesh_build_topology.d.ts.map +1 -1
- package/src/engine/navigation/mesh/build/navmesh_build_topology.js +223 -226
- package/src/engine/.fuse_hidden0000001500000001 +0 -581
|
@@ -1,226 +1,223 @@
|
|
|
1
|
-
import { assert } from "../../../../core/assert.js";
|
|
2
|
-
import { BVH } from "../../../../core/bvh2/bvh3/BVH.js";
|
|
3
|
-
import { BinaryTopology } from "../../../../core/geom/3d/topology/struct/binary/BinaryTopology.js";
|
|
4
|
-
import {
|
|
5
|
-
bt_mesh_cleanup_faceless_references
|
|
6
|
-
} from "../../../../core/geom/3d/topology/struct/binary/io/bt_mesh_cleanup_faceless_references.js";
|
|
7
|
-
import {
|
|
8
|
-
bt_mesh_compact
|
|
9
|
-
} from "../../../../core/geom/3d/topology/struct/binary/io/bt_mesh_compact.js";
|
|
10
|
-
import {
|
|
11
|
-
bt_mesh_compute_face_normals
|
|
12
|
-
} from "../../../../core/geom/3d/topology/struct/binary/io/bt_mesh_compute_face_normals.js";
|
|
13
|
-
|
|
14
|
-
import {
|
|
15
|
-
bt_mesh_face_decouple_islands
|
|
16
|
-
} from "../../../../core/geom/3d/topology/struct/binary/io/bt_mesh_face_decouple_islands.js";
|
|
17
|
-
import {
|
|
18
|
-
bt_mesh_face_island_erode
|
|
19
|
-
} from "../../../../core/geom/3d/topology/struct/binary/io/bt_mesh_face_island_erode.js";
|
|
20
|
-
import {
|
|
21
|
-
bt_mesh_from_unindexed_geometry
|
|
22
|
-
} from "../../../../core/geom/3d/topology/struct/binary/io/bt_mesh_from_unindexed_geometry.js";
|
|
23
|
-
import { bt_mesh_triangulate } from "../../../../core/geom/3d/topology/struct/binary/io/bt_mesh_triangulate.js";
|
|
24
|
-
import {
|
|
25
|
-
bt_mesh_fuse_duplicate_edges
|
|
26
|
-
} from "../../../../core/geom/3d/topology/struct/binary/io/edge/bt_mesh_fuse_duplicate_edges.js";
|
|
27
|
-
import {
|
|
28
|
-
bt_merge_verts_by_distance
|
|
29
|
-
} from "../../../../core/geom/3d/topology/struct/binary/io/vertex/bt_merge_verts_by_distance.js";
|
|
30
|
-
import { bt_face_is_degenerate } from "../../../../core/geom/3d/topology/struct/binary/query/bt_face_is_degenerate.js";
|
|
31
|
-
import {
|
|
32
|
-
bt_mesh_bridge_islands
|
|
33
|
-
} from "../../../../core/geom/3d/topology/struct/binary/io/bt_mesh_bridge_islands.js";
|
|
34
|
-
import {
|
|
35
|
-
bt_mesh_compute_face_islands
|
|
36
|
-
} from "../../../../core/geom/3d/topology/struct/binary/query/bt_mesh_compute_face_islands.js";
|
|
37
|
-
import { v3_angle_between } from "../../../../core/geom/vec3/v3_angle_between.js";
|
|
38
|
-
import Vector3 from "../../../../core/geom/Vector3.js";
|
|
39
|
-
import { bvh_build_from_bt_mesh } from "../bvh_build_from_bt_mesh.js";
|
|
40
|
-
import { bvh_build_from_unindexed_triangles } from "./bvh_build_from_unindexed_triangles.js";
|
|
41
|
-
import {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Build from given scene geometry
|
|
46
|
-
* @param {BinaryTopology} destination
|
|
47
|
-
* @param {BinaryTopology} source Must be triangulated. Use {@link bt_mesh_triangulate} if needed.
|
|
48
|
-
* @param {number} [agent_radius]
|
|
49
|
-
* @param {number} [agent_height]
|
|
50
|
-
* @param {number} [agent_max_step_height] agent can bridge vertical gaps in topology, such as stepping up a stair
|
|
51
|
-
* @param {number} [agent_max_step_distance] agent can bridge lateral gaps in topology, such as stepping over a hole in the floor
|
|
52
|
-
* @param {number} [agent_max_climb_angle] In radians, how steep of an angle can the agent go up by
|
|
53
|
-
* @param {Vector3} [up] Defines world's "UP" direction, this is what the agent will respect for climbing constraint
|
|
54
|
-
*/
|
|
55
|
-
export function navmesh_build_topology({
|
|
56
|
-
destination,
|
|
57
|
-
source,
|
|
58
|
-
agent_radius = 0,
|
|
59
|
-
agent_height = 2,
|
|
60
|
-
agent_max_step_height = 0,
|
|
61
|
-
agent_max_step_distance = 0,
|
|
62
|
-
agent_max_climb_angle = Math.PI / 4,
|
|
63
|
-
up = Vector3.up,
|
|
64
|
-
}) {
|
|
65
|
-
|
|
66
|
-
assert.defined(destination, 'destination');
|
|
67
|
-
assert.defined(source, 'source');
|
|
68
|
-
|
|
69
|
-
assert.greaterThanOrEqual(agent_radius, 0, 'agent_radius');
|
|
70
|
-
assert.greaterThanOrEqual(agent_height, 0, 'agent_height');
|
|
71
|
-
assert.greaterThanOrEqual(agent_max_climb_angle, 0, 'agent_max_climb_angle');
|
|
72
|
-
assert.greaterThanOrEqual(agent_max_step_height, 0, 'agent_max_step_height');
|
|
73
|
-
assert.greaterThanOrEqual(agent_max_step_distance, 0, 'agent_max_step_distance');
|
|
74
|
-
|
|
75
|
-
// The walkable-angle filter below reads each source face's normal. Compute them defensively rather
|
|
76
|
-
// than relying on an undocumented "caller already populated normals" precondition - normals are
|
|
77
|
-
// derived data, so this is idempotent. NOTE: a single face normal cannot distinguish a correctly
|
|
78
|
-
// wound floor from a flipped one (or a ceiling), so the source is still required to have consistent
|
|
79
|
-
// outward winding; that remains an input contract we cannot recover from here.
|
|
80
|
-
bt_mesh_compute_face_normals(source);
|
|
81
|
-
|
|
82
|
-
const source_bvh = new BVH();
|
|
83
|
-
|
|
84
|
-
// prepare a BVH, we'll need it for height queries later on
|
|
85
|
-
bvh_build_from_bt_mesh(source_bvh, source);
|
|
86
|
-
|
|
87
|
-
const scratch_normal = new Float32Array(3);
|
|
88
|
-
|
|
89
|
-
// unpack topology into triangle soup
|
|
90
|
-
const source_face_count = source.faces.size;
|
|
91
|
-
|
|
92
|
-
// TODO add cleanup phase
|
|
93
|
-
// - fuse vertices of tiny triangles eliminating them
|
|
94
|
-
// - identify flat areas and re-triangulate them to remove unnecessary triangles
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
*
|
|
98
|
-
* @type {number[]}
|
|
99
|
-
*/
|
|
100
|
-
const raw_triangles = [];
|
|
101
|
-
let triangle_count = 0;
|
|
102
|
-
|
|
103
|
-
for (let face_id = 0; face_id < source_face_count; face_id++) {
|
|
104
|
-
|
|
105
|
-
source.face_read_normal(scratch_normal, 0, face_id);
|
|
106
|
-
|
|
107
|
-
const angle = v3_angle_between(up.x, up.y, up.z, scratch_normal[0], scratch_normal[1], scratch_normal[2]);
|
|
108
|
-
|
|
109
|
-
if (angle > agent_max_climb_angle) {
|
|
110
|
-
// discard
|
|
111
|
-
continue;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (bt_face_is_degenerate(source, face_id)) {
|
|
115
|
-
// discard
|
|
116
|
-
continue;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
let loop = source.face_read_loop(face_id);
|
|
120
|
-
const loop_start = loop;
|
|
121
|
-
|
|
122
|
-
let face_vertex_count = 0;
|
|
123
|
-
|
|
124
|
-
do {
|
|
125
|
-
|
|
126
|
-
assert.lessThan(face_vertex_count, 3, 'not a triangle');
|
|
127
|
-
|
|
128
|
-
const vertex = source.loop_read_vertex(loop);
|
|
129
|
-
|
|
130
|
-
const triangle_offset = triangle_count * 9;
|
|
131
|
-
|
|
132
|
-
source.vertex_read_coordinate(raw_triangles, triangle_offset + face_vertex_count * 3, vertex);
|
|
133
|
-
|
|
134
|
-
face_vertex_count++;
|
|
135
|
-
|
|
136
|
-
loop = source.loop_read_next(loop);
|
|
137
|
-
|
|
138
|
-
} while (loop !== loop_start)
|
|
139
|
-
|
|
140
|
-
triangle_count++;
|
|
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
|
-
//
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
//
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
//
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
//
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
//
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
//
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
}
|
|
1
|
+
import { assert } from "../../../../core/assert.js";
|
|
2
|
+
import { BVH } from "../../../../core/bvh2/bvh3/BVH.js";
|
|
3
|
+
import { BinaryTopology } from "../../../../core/geom/3d/topology/struct/binary/BinaryTopology.js";
|
|
4
|
+
import {
|
|
5
|
+
bt_mesh_cleanup_faceless_references
|
|
6
|
+
} from "../../../../core/geom/3d/topology/struct/binary/io/bt_mesh_cleanup_faceless_references.js";
|
|
7
|
+
import {
|
|
8
|
+
bt_mesh_compact
|
|
9
|
+
} from "../../../../core/geom/3d/topology/struct/binary/io/bt_mesh_compact.js";
|
|
10
|
+
import {
|
|
11
|
+
bt_mesh_compute_face_normals
|
|
12
|
+
} from "../../../../core/geom/3d/topology/struct/binary/io/bt_mesh_compute_face_normals.js";
|
|
13
|
+
|
|
14
|
+
import {
|
|
15
|
+
bt_mesh_face_decouple_islands
|
|
16
|
+
} from "../../../../core/geom/3d/topology/struct/binary/io/bt_mesh_face_decouple_islands.js";
|
|
17
|
+
import {
|
|
18
|
+
bt_mesh_face_island_erode
|
|
19
|
+
} from "../../../../core/geom/3d/topology/struct/binary/io/bt_mesh_face_island_erode.js";
|
|
20
|
+
import {
|
|
21
|
+
bt_mesh_from_unindexed_geometry
|
|
22
|
+
} from "../../../../core/geom/3d/topology/struct/binary/io/bt_mesh_from_unindexed_geometry.js";
|
|
23
|
+
import { bt_mesh_triangulate } from "../../../../core/geom/3d/topology/struct/binary/io/bt_mesh_triangulate.js";
|
|
24
|
+
import {
|
|
25
|
+
bt_mesh_fuse_duplicate_edges
|
|
26
|
+
} from "../../../../core/geom/3d/topology/struct/binary/io/edge/bt_mesh_fuse_duplicate_edges.js";
|
|
27
|
+
import {
|
|
28
|
+
bt_merge_verts_by_distance
|
|
29
|
+
} from "../../../../core/geom/3d/topology/struct/binary/io/vertex/bt_merge_verts_by_distance.js";
|
|
30
|
+
import { bt_face_is_degenerate } from "../../../../core/geom/3d/topology/struct/binary/query/bt_face_is_degenerate.js";
|
|
31
|
+
import {
|
|
32
|
+
bt_mesh_bridge_islands
|
|
33
|
+
} from "../../../../core/geom/3d/topology/struct/binary/io/bt_mesh_bridge_islands.js";
|
|
34
|
+
import {
|
|
35
|
+
bt_mesh_compute_face_islands
|
|
36
|
+
} from "../../../../core/geom/3d/topology/struct/binary/query/bt_mesh_compute_face_islands.js";
|
|
37
|
+
import { v3_angle_between } from "../../../../core/geom/vec3/v3_angle_between.js";
|
|
38
|
+
import Vector3 from "../../../../core/geom/Vector3.js";
|
|
39
|
+
import { bvh_build_from_bt_mesh } from "../bvh_build_from_bt_mesh.js";
|
|
40
|
+
import { bvh_build_from_unindexed_triangles } from "./bvh_build_from_unindexed_triangles.js";
|
|
41
|
+
import { bt_mesh_carve_height_clearance } from "./bt_mesh_carve_height_clearance.js";
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Build from given scene geometry
|
|
46
|
+
* @param {BinaryTopology} destination
|
|
47
|
+
* @param {BinaryTopology} source Must be triangulated. Use {@link bt_mesh_triangulate} if needed.
|
|
48
|
+
* @param {number} [agent_radius]
|
|
49
|
+
* @param {number} [agent_height]
|
|
50
|
+
* @param {number} [agent_max_step_height] agent can bridge vertical gaps in topology, such as stepping up a stair
|
|
51
|
+
* @param {number} [agent_max_step_distance] agent can bridge lateral gaps in topology, such as stepping over a hole in the floor
|
|
52
|
+
* @param {number} [agent_max_climb_angle] In radians, how steep of an angle can the agent go up by
|
|
53
|
+
* @param {Vector3} [up] Defines world's "UP" direction, this is what the agent will respect for climbing constraint
|
|
54
|
+
*/
|
|
55
|
+
export function navmesh_build_topology({
|
|
56
|
+
destination,
|
|
57
|
+
source,
|
|
58
|
+
agent_radius = 0,
|
|
59
|
+
agent_height = 2,
|
|
60
|
+
agent_max_step_height = 0,
|
|
61
|
+
agent_max_step_distance = 0,
|
|
62
|
+
agent_max_climb_angle = Math.PI / 4,
|
|
63
|
+
up = Vector3.up,
|
|
64
|
+
}) {
|
|
65
|
+
|
|
66
|
+
assert.defined(destination, 'destination');
|
|
67
|
+
assert.defined(source, 'source');
|
|
68
|
+
|
|
69
|
+
assert.greaterThanOrEqual(agent_radius, 0, 'agent_radius');
|
|
70
|
+
assert.greaterThanOrEqual(agent_height, 0, 'agent_height');
|
|
71
|
+
assert.greaterThanOrEqual(agent_max_climb_angle, 0, 'agent_max_climb_angle');
|
|
72
|
+
assert.greaterThanOrEqual(agent_max_step_height, 0, 'agent_max_step_height');
|
|
73
|
+
assert.greaterThanOrEqual(agent_max_step_distance, 0, 'agent_max_step_distance');
|
|
74
|
+
|
|
75
|
+
// The walkable-angle filter below reads each source face's normal. Compute them defensively rather
|
|
76
|
+
// than relying on an undocumented "caller already populated normals" precondition - normals are
|
|
77
|
+
// derived data, so this is idempotent. NOTE: a single face normal cannot distinguish a correctly
|
|
78
|
+
// wound floor from a flipped one (or a ceiling), so the source is still required to have consistent
|
|
79
|
+
// outward winding; that remains an input contract we cannot recover from here.
|
|
80
|
+
bt_mesh_compute_face_normals(source);
|
|
81
|
+
|
|
82
|
+
const source_bvh = new BVH();
|
|
83
|
+
|
|
84
|
+
// prepare a BVH, we'll need it for height queries later on
|
|
85
|
+
bvh_build_from_bt_mesh(source_bvh, source);
|
|
86
|
+
|
|
87
|
+
const scratch_normal = new Float32Array(3);
|
|
88
|
+
|
|
89
|
+
// unpack topology into triangle soup
|
|
90
|
+
const source_face_count = source.faces.size;
|
|
91
|
+
|
|
92
|
+
// TODO add cleanup phase
|
|
93
|
+
// - fuse vertices of tiny triangles eliminating them
|
|
94
|
+
// - identify flat areas and re-triangulate them to remove unnecessary triangles
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
*
|
|
98
|
+
* @type {number[]}
|
|
99
|
+
*/
|
|
100
|
+
const raw_triangles = [];
|
|
101
|
+
let triangle_count = 0;
|
|
102
|
+
|
|
103
|
+
for (let face_id = 0; face_id < source_face_count; face_id++) {
|
|
104
|
+
|
|
105
|
+
source.face_read_normal(scratch_normal, 0, face_id);
|
|
106
|
+
|
|
107
|
+
const angle = v3_angle_between(up.x, up.y, up.z, scratch_normal[0], scratch_normal[1], scratch_normal[2]);
|
|
108
|
+
|
|
109
|
+
if (angle > agent_max_climb_angle) {
|
|
110
|
+
// discard
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (bt_face_is_degenerate(source, face_id)) {
|
|
115
|
+
// discard
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
let loop = source.face_read_loop(face_id);
|
|
120
|
+
const loop_start = loop;
|
|
121
|
+
|
|
122
|
+
let face_vertex_count = 0;
|
|
123
|
+
|
|
124
|
+
do {
|
|
125
|
+
|
|
126
|
+
assert.lessThan(face_vertex_count, 3, 'not a triangle');
|
|
127
|
+
|
|
128
|
+
const vertex = source.loop_read_vertex(loop);
|
|
129
|
+
|
|
130
|
+
const triangle_offset = triangle_count * 9;
|
|
131
|
+
|
|
132
|
+
source.vertex_read_coordinate(raw_triangles, triangle_offset + face_vertex_count * 3, vertex);
|
|
133
|
+
|
|
134
|
+
face_vertex_count++;
|
|
135
|
+
|
|
136
|
+
loop = source.loop_read_next(loop);
|
|
137
|
+
|
|
138
|
+
} while (loop !== loop_start)
|
|
139
|
+
|
|
140
|
+
triangle_count++;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
{
|
|
144
|
+
const bvh = new BVH();
|
|
145
|
+
|
|
146
|
+
// first dump all triangles into a BVH for speed of access
|
|
147
|
+
bvh_build_from_unindexed_triangles(bvh, raw_triangles, triangle_count);
|
|
148
|
+
|
|
149
|
+
// find possible triangle edge connections, that is - where edges of 2 triangles touch, but don't match exactly.
|
|
150
|
+
// the touching edges will need to be cut and affected triangles split accordingly
|
|
151
|
+
|
|
152
|
+
const mesh = new BinaryTopology();
|
|
153
|
+
|
|
154
|
+
// raw_triangles may have stale tail data from filtering steps above (e.g. degenerate/steep);
|
|
155
|
+
// bt_mesh_from_unindexed_geometry reads the whole array, so trim to the live range first.
|
|
156
|
+
raw_triangles.length = triangle_count * 9;
|
|
157
|
+
|
|
158
|
+
bt_mesh_from_unindexed_geometry(mesh, raw_triangles);
|
|
159
|
+
|
|
160
|
+
// fuse coincident positions so neighbouring triangles share a vertex id...
|
|
161
|
+
bt_merge_verts_by_distance(mesh, 1e-6);
|
|
162
|
+
|
|
163
|
+
// ...then fuse the resulting duplicate edges so they share an edge id too,
|
|
164
|
+
// which is what the loop-based neighbour queries rely on
|
|
165
|
+
bt_mesh_fuse_duplicate_edges(mesh);
|
|
166
|
+
|
|
167
|
+
// Carve holes wherever an agent of the given height would not fit under overhead geometry.
|
|
168
|
+
// Done on the welded topology (rather than the raw soup) so the subdivision is conformal -
|
|
169
|
+
// bt_edge_split re-triangulates every face around a shared edge, so neighbours can never crack
|
|
170
|
+
// apart - and adaptive, hugging each obstacle's contour instead of tessellating whole triangles.
|
|
171
|
+
if (agent_height > 0) {
|
|
172
|
+
bt_mesh_carve_height_clearance({
|
|
173
|
+
mesh,
|
|
174
|
+
source,
|
|
175
|
+
source_bvh,
|
|
176
|
+
agent_height,
|
|
177
|
+
agent_radius,
|
|
178
|
+
up,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const islands = bt_mesh_compute_face_islands(mesh);
|
|
183
|
+
|
|
184
|
+
// enabled us to modify islands independently
|
|
185
|
+
bt_mesh_face_decouple_islands(mesh, islands);
|
|
186
|
+
|
|
187
|
+
// shrink islands to agent_radius
|
|
188
|
+
for (const island of islands) {
|
|
189
|
+
bt_mesh_face_island_erode(mesh, island, agent_radius);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// TODO attempt to reduce mesh complexity by re-triangulating flat areas or running a very constrained decimation
|
|
193
|
+
|
|
194
|
+
// remove dangling references
|
|
195
|
+
bt_mesh_cleanup_faceless_references(mesh);
|
|
196
|
+
|
|
197
|
+
// Island erosion (above) kills faces via the pool's free-list, leaving holes in the ID space.
|
|
198
|
+
// `faces.size` is a high-water mark, not a live count, so consumers that iterate `0..faces.size`
|
|
199
|
+
// (e.g. bvh_build_from_bt_mesh) would touch freed slots. Compact so every consumer sees a dense,
|
|
200
|
+
// hole-free topology - this is the single invariant downstream code relies on.
|
|
201
|
+
bt_mesh_compact(mesh);
|
|
202
|
+
|
|
203
|
+
// bridge across small steps / gaps so stair-separated or slightly-broken tiers are reachable.
|
|
204
|
+
// Opt-in: with both step params 0 (the default) the topology is left untouched.
|
|
205
|
+
if (agent_max_step_height > 0 || agent_max_step_distance > 0) {
|
|
206
|
+
bt_mesh_bridge_islands(mesh, {
|
|
207
|
+
max_step_height: agent_max_step_height,
|
|
208
|
+
max_step_distance: agent_max_step_distance,
|
|
209
|
+
up,
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
// bridging rebuilds via vertex-merge / edge-fuse, which can leave holes; re-densify
|
|
213
|
+
bt_mesh_compact(mesh);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// face normals are consumed by navigation queries (string-pulling portal normals), populate them now
|
|
217
|
+
bt_mesh_compute_face_normals(mesh);
|
|
218
|
+
|
|
219
|
+
// write out to destination
|
|
220
|
+
destination.copy(mesh);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
}
|