@woosh/meep-engine 2.46.25 → 2.46.27

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 (30) hide show
  1. package/package.json +1 -1
  2. package/src/core/bvh2/binary/2/BinaryUint32BVH.js +9 -12
  3. package/src/core/bvh2/bvh3/EBBVHLeafProxy.js +60 -0
  4. package/src/core/bvh2/bvh3/ExplicitBinaryBoundingVolumeHierarchy.js +1 -0
  5. package/src/core/collection/HashMap.js +21 -5
  6. package/src/core/events/signal/Signal.js +3 -3
  7. package/src/core/geom/3d/cone/computeConeBoundingBox.js +7 -10
  8. package/src/core/geom/3d/ray/ray3_array_apply_matrix4.js +15 -13
  9. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +6 -24
  10. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.js +4 -25
  11. package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMeshSystem.js +2 -6
  12. package/src/engine/graphics/geometry/bvh/buffered/BVHGeometryRaycaster.js +1 -1
  13. package/src/engine/graphics/particles/particular/engine/parameter/ParameterLookupTable.d.ts +1 -1
  14. package/src/engine/graphics/particles/particular/engine/parameter/ParameterLookupTable.js +10 -43
  15. package/src/engine/graphics/render/forward_plus/LightManager.js +164 -56
  16. package/src/engine/graphics/render/forward_plus/{PointLightData.js → LightRenderMetadata.js} +18 -11
  17. package/src/engine/graphics/render/forward_plus/cluster/compute_light_data_hash.js +1 -1
  18. package/src/engine/graphics/render/forward_plus/model/AbstractLight.js +1 -1
  19. package/src/engine/graphics/render/forward_plus/model/Decal.js +1 -4
  20. package/src/engine/graphics/render/forward_plus/model/PointLight.js +6 -12
  21. package/src/engine/graphics/render/forward_plus/model/SpotLight.js +0 -4
  22. package/src/engine/graphics/render/forward_plus/plugin/ForwardPlusRenderingPlugin.d.ts +3 -0
  23. package/src/engine/graphics/render/forward_plus/plugin/ForwardPlusRenderingPlugin.js +12 -0
  24. package/src/engine/graphics/render/forward_plus/prototype/prototypeLightManager.js +3 -2
  25. package/src/engine/graphics/render/forward_plus/query/point_light_inside_volume.js +1 -1
  26. package/src/engine/graphics/render/forward_plus/query/query_bvh_frustum_from_objects.js +3 -3
  27. package/src/engine/graphics/sh3/path_tracer/PathTracedMesh.js +1 -1
  28. package/src/engine/graphics/texture/atlas/CachingTextureAtlas.js +0 -1
  29. package/src/engine/intelligence/behavior/util/BranchBehavior.js +102 -0
  30. package/src/engine/intelligence/behavior/util/SelectorBehavior.js +0 -83
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "description": "Fully featured ECS game engine written in JavaScript",
6
6
  "type": "module",
7
7
  "author": "Alexander Goldring",
8
- "version": "2.46.25",
8
+ "version": "2.46.27",
9
9
  "main": "build/meep.module.js",
10
10
  "module": "build/meep.module.js",
11
11
  "exports": {
@@ -119,10 +119,7 @@ function build_morton(data, address, matrix) {
119
119
 
120
120
  }
121
121
 
122
- const scratch_box_0 = [];
123
- const scratch_box_1 = [];
124
- const scratch_box_2 = [];
125
-
122
+ const scratch_box_0 = new Float32Array(18);
126
123
  const stack = [];
127
124
 
128
125
  export class BinaryUint32BVH {
@@ -294,16 +291,16 @@ export class BinaryUint32BVH {
294
291
  */
295
292
  __compute_bounds_area_of_3_boxes(a, b, c) {
296
293
  this.readBounds(a, scratch_box_0, 0);
297
- this.readBounds(b, scratch_box_1, 0);
298
- this.readBounds(c, scratch_box_2, 0);
294
+ this.readBounds(b, scratch_box_0, 6);
295
+ this.readBounds(c, scratch_box_0, 12);
299
296
 
300
- const x0 = min3(scratch_box_0[0], scratch_box_1[0], scratch_box_2[0]);
301
- const y0 = min3(scratch_box_0[1], scratch_box_1[1], scratch_box_2[1]);
302
- const z0 = min3(scratch_box_0[2], scratch_box_1[2], scratch_box_2[2]);
297
+ const x0 = min3(scratch_box_0[0], scratch_box_0[6], scratch_box_0[12]);
298
+ const y0 = min3(scratch_box_0[1], scratch_box_0[7], scratch_box_0[13]);
299
+ const z0 = min3(scratch_box_0[2], scratch_box_0[8], scratch_box_0[14]);
303
300
 
304
- const x1 = max3(scratch_box_0[3], scratch_box_1[3], scratch_box_2[3]);
305
- const y1 = max3(scratch_box_0[4], scratch_box_1[4], scratch_box_2[4]);
306
- const z1 = max3(scratch_box_0[5], scratch_box_1[5], scratch_box_2[5]);
301
+ const x1 = max3(scratch_box_0[3], scratch_box_0[9], scratch_box_0[15]);
302
+ const y1 = max3(scratch_box_0[4], scratch_box_0[10], scratch_box_0[16]);
303
+ const z1 = max3(scratch_box_0[5], scratch_box_0[11], scratch_box_0[17]);
307
304
 
308
305
  return aabb3_compute_half_surface_area(x0, y0, z0, x1, y1, z1);
309
306
  }
@@ -0,0 +1,60 @@
1
+ import { assert } from "../../assert.js";
2
+
3
+ /**
4
+ * A convenience class to work with BVH leaf nodes
5
+ */
6
+ export class EBBVHLeafProxy {
7
+ /**
8
+ *
9
+ * @type {ExplicitBinaryBoundingVolumeHierarchy|null}
10
+ */
11
+ #tree = null;
12
+
13
+ /**
14
+ *
15
+ * @type {number}
16
+ */
17
+ #node_id = -1;
18
+
19
+ /**
20
+ * @readonly
21
+ * @type {number[]}
22
+ */
23
+ bounds = new Float32Array(6);
24
+
25
+ get is_linked(){
26
+ return this.#node_id !== -1;
27
+ }
28
+
29
+ /**
30
+ *
31
+ * @param {ExplicitBinaryBoundingVolumeHierarchy} tree
32
+ * @param {number} data Must be a uint32
33
+ */
34
+ link(tree, data) {
35
+ assert.defined(tree, 'tree');
36
+ assert.isNonNegativeInteger(data, 'data');
37
+
38
+ this.#tree = tree;
39
+
40
+ const node_id = tree.allocate_node();
41
+
42
+ this.#node_id = node_id;
43
+
44
+ tree.node_set_aabb(node_id, this.bounds);
45
+ tree.node_set_user_data(node_id, data);
46
+ tree.insert_leaf(node_id);
47
+ }
48
+
49
+ unlink() {
50
+ this.#tree.remove_leaf(this.#node_id);
51
+ this.#tree.release_node(this.#node_id);
52
+
53
+ this.#node_id = -1;
54
+ this.#tree = null;
55
+ }
56
+
57
+ write_bounds() {
58
+ this.#tree.node_move_aabb(this.#node_id, this.bounds);
59
+ }
60
+ }
@@ -267,6 +267,7 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
267
267
  */
268
268
  node_set_user_data(id, value) {
269
269
  assert.isNonNegativeInteger(id, 'id');
270
+ assert.isNonNegativeInteger(value, 'value');
270
271
 
271
272
  this.__data_uint32[ELEMENT_WORD_COUNT * id + COLUMN_USER_DATA] = value;
272
273
  }
@@ -11,8 +11,9 @@ class MapEntry {
11
11
  *
12
12
  * @param {K} key
13
13
  * @param {V} value
14
+ * @param {number} hash
14
15
  */
15
- constructor(key, value) {
16
+ constructor(key, value, hash) {
16
17
  /**
17
18
  *
18
19
  * @type {K}
@@ -23,6 +24,12 @@ class MapEntry {
23
24
  * @type {V}
24
25
  */
25
26
  this.value = value;
27
+
28
+ /**
29
+ *
30
+ * @type {number}
31
+ */
32
+ this.hash = hash;
26
33
  }
27
34
  }
28
35
 
@@ -219,7 +226,11 @@ export class HashMap {
219
226
 
220
227
  const entryKey = entry.key;
221
228
 
222
- if (entryKey === key || this.keyEqualityFunction(entryKey, key)) {
229
+
230
+ if (
231
+ entry.hash === raw_hash
232
+ && (entryKey === key || this.keyEqualityFunction(entryKey, key))
233
+ ) {
223
234
 
224
235
  // found record with matching key, replace the value
225
236
 
@@ -234,7 +245,7 @@ export class HashMap {
234
245
 
235
246
  }
236
247
 
237
- bucket.push(new MapEntry(key, value));
248
+ bucket.push(new MapEntry(key, value,raw_hash));
238
249
 
239
250
  const old_size = this.size;
240
251
  const new_size = old_size + 1;
@@ -269,8 +280,10 @@ export class HashMap {
269
280
 
270
281
  const entryKey = entry.key;
271
282
 
272
- if (entryKey === key || this.keyEqualityFunction(entryKey, key)) {
273
-
283
+ if (
284
+ entry.hash === raw_hash
285
+ && (entryKey === key || this.keyEqualityFunction(entryKey, key))
286
+ ) {
274
287
  return entry.value;
275
288
 
276
289
  }
@@ -432,6 +445,9 @@ export class HashMap {
432
445
 
433
446
  //check hash
434
447
  const raw_hash = this.keyHashFunction(entry.key);
448
+
449
+ entry.hash = raw_hash;
450
+
435
451
  const actual_bucket_index = this.__compute_bucket_index(raw_hash);
436
452
 
437
453
 
@@ -147,7 +147,7 @@ export class Signal {
147
147
  * @param {*} [context]
148
148
  */
149
149
  addOne(h, context) {
150
- assert.equal(typeof h, "function", "Handler is not a function");
150
+ assert.isFunction( h, "handler");
151
151
 
152
152
  const handler = new SignalHandler(h, context);
153
153
 
@@ -195,8 +195,8 @@ export class Signal {
195
195
  * Remove all handlers
196
196
  */
197
197
  removeAll() {
198
- const signalHandlers = this.handlers;
199
- signalHandlers.splice(0, signalHandlers.length);
198
+ const handlers = this.handlers;
199
+ handlers.splice(0, handlers.length);
200
200
  }
201
201
 
202
202
  /**
@@ -4,7 +4,7 @@ import { v3_angle_between } from "../../v3_angle_between.js";
4
4
 
5
5
  /**
6
6
  * NOTE: used stackoverflow answer as a basis for circle part: https://stackoverflow.com/questions/2592011/bounding-boxes-for-circle-and-arcs-in-3d
7
- * @param {AABB3} result
7
+ * @param {number[]|ArrayLike<number>|Float32Array} result
8
8
  * @param {number} originX
9
9
  * @param {number} originY
10
10
  * @param {number} originZ
@@ -41,14 +41,11 @@ export function computeConeBoundingBox(result, originX, originY, originZ, direct
41
41
  const cz1 = centerZ + rZ;
42
42
 
43
43
  //combine bounds of the origin and base of the cone
44
- const x0 = min2(originX, cx0);
45
- const y0 = min2(originY, cy0);
46
- const z0 = min2(originZ, cz0);
44
+ result[0] = min2(originX, cx0);
45
+ result[1] = min2(originY, cy0);
46
+ result[2] = min2(originZ, cz0);
47
47
 
48
- const x1 = max2(originX, cx1);
49
- const y1 = max2(originY, cy1);
50
- const z1 = max2(originZ, cz1);
51
-
52
- //write result
53
- result.setBounds(x0, y0, z0, x1, y1, z1);
48
+ result[3] = max2(originX, cx1);
49
+ result[4] = max2(originY, cy1);
50
+ result[5] = max2(originZ, cz1);
54
51
  }
@@ -1,18 +1,20 @@
1
1
  /**
2
2
  *
3
3
  * @param {number[]|ArrayLike<number>|Float32Array} output 6 component vector, [origin_x, origin_y, origin_z, direction_x, direction_y, direction_z]
4
+ * @param {number} output_offset
4
5
  * @param {number[]|ArrayLike<number>|Float32Array} input 6 component vector, [origin_x, origin_y, origin_z, direction_x, direction_y, direction_z]
6
+ * @param {number} input_offset
5
7
  * @param {number[]|ArrayLike<number>|Float32Array} m4 4x4 matrix
6
8
  * @returns {boolean} false if matrix transformation is impossible, such as when scale of the matrix is 0
7
9
  */
8
- export function ray3_array_apply_matrix4(output, input, m4) {
9
- const origin_x = input[0];
10
- const origin_y = input[1];
11
- const origin_z = input[2];
10
+ export function ray3_array_apply_matrix4(output, output_offset, input, input_offset, m4) {
11
+ const origin_x = input[input_offset + 0];
12
+ const origin_y = input[input_offset + 1];
13
+ const origin_z = input[input_offset + 2];
12
14
 
13
- const direction_x = input[3];
14
- const direction_y = input[4];
15
- const direction_z = input[5];
15
+ const direction_x = input[input_offset + 3];
16
+ const direction_y = input[input_offset + 4];
17
+ const direction_z = input[input_offset + 5];
16
18
 
17
19
  // transform ray to local space (inlined for speed)
18
20
  const det = m4[3] * origin_x + m4[7] * origin_y + m4[11] * origin_z + m4[15];
@@ -44,13 +46,13 @@ export function ray3_array_apply_matrix4(output, input, m4) {
44
46
  const out_direction_normalized_y = out_direction_y * out_direction_magnitude_inverse;
45
47
  const out_direction_normalized_z = out_direction_z * out_direction_magnitude_inverse;
46
48
 
47
- output[0] = out_origin_x;
48
- output[1] = out_origin_y;
49
- output[2] = out_origin_z;
49
+ output[output_offset + 0] = out_origin_x;
50
+ output[output_offset + 1] = out_origin_y;
51
+ output[output_offset + 2] = out_origin_z;
50
52
 
51
- output[3] = out_direction_normalized_x;
52
- output[4] = out_direction_normalized_y;
53
- output[5] = out_direction_normalized_z;
53
+ output[output_offset + 3] = out_direction_normalized_x;
54
+ output[output_offset + 4] = out_direction_normalized_y;
55
+ output[output_offset + 5] = out_direction_normalized_z;
54
56
 
55
57
  return true;
56
58
  }
@@ -6,6 +6,7 @@ import { mat4 } from "gl-matrix";
6
6
  import { ray3_array_apply_matrix4 } from "../../../../core/geom/3d/ray/ray3_array_apply_matrix4.js";
7
7
  import { GeometrySpatialQueryAccelerator } from "../../geometry/buffered/query/GeometrySpatialQueryAccelerator.js";
8
8
  import { assert } from "../../../../core/assert.js";
9
+ import { EBBVHLeafProxy } from "../../../../core/bvh2/bvh3/EBBVHLeafProxy.js";
9
10
 
10
11
  /**
11
12
  * @readonly
@@ -55,26 +56,7 @@ export class ShadedGeometry {
55
56
  */
56
57
  this.depth_material = null;
57
58
 
58
- /**
59
- *
60
- * @type {number}
61
- * @private
62
- */
63
- this.__bvh_leaf_id = -1;
64
-
65
- /**
66
- *
67
- * @type {ExplicitBinaryBoundingVolumeHierarchy|null}
68
- * @private
69
- */
70
- this.__bvh_tree = null;
71
-
72
- /**
73
- * @readonly
74
- * @type {number[]|Float32Array}
75
- * @private
76
- */
77
- this.__bvh_aabb = new Float32Array(6);
59
+ this.__bvh_leaf = new EBBVHLeafProxy();
78
60
 
79
61
  /**
80
62
  * Transient, assigned in the system
@@ -240,7 +222,7 @@ export class ShadedGeometry {
240
222
  * @param {AABB3} destination
241
223
  */
242
224
  getBoundingBox(destination) {
243
- const aabb = this.__bvh_aabb;
225
+ const aabb = this.__bvh_leaf.bounds;
244
226
 
245
227
  destination.readFromArray(aabb);
246
228
  }
@@ -280,7 +262,7 @@ export class ShadedGeometry {
280
262
  updateTransform() {
281
263
  this.update_bounds();
282
264
 
283
- this.__bvh_tree.node_move_aabb(this.__bvh_leaf_id, this.__bvh_aabb);
265
+ this.__bvh_leaf.write_bounds();
284
266
  }
285
267
 
286
268
  update_bounds() {
@@ -317,7 +299,7 @@ export class ShadedGeometry {
317
299
  scratch_aabb3_array[4] = y1;
318
300
  scratch_aabb3_array[5] = z1;
319
301
 
320
- aabb3_matrix4_project(this.__bvh_aabb, scratch_aabb3_array, this.transform);
302
+ aabb3_matrix4_project(this.__bvh_leaf.bounds, scratch_aabb3_array, this.transform);
321
303
  }
322
304
 
323
305
  /**
@@ -333,7 +315,7 @@ export class ShadedGeometry {
333
315
  mat4.invert(scratch_m4, transform_matrix4);
334
316
 
335
317
  // transform ray to local space
336
- if (!ray3_array_apply_matrix4(scratch_ray_0, ray, scratch_m4)) {
318
+ if (!ray3_array_apply_matrix4(scratch_ray_0,0, ray,0, scratch_m4)) {
337
319
  // invalid transform matrix
338
320
  return false;
339
321
  }
@@ -289,25 +289,13 @@ export class ShadedGeometrySystem extends System {
289
289
 
290
290
  sg.update_bounds();
291
291
 
292
- t.position.onChanged.add(sg.updateTransform, sg);
293
- t.rotation.onChanged.add(sg.updateTransform, sg);
294
- t.scale.onChanged.add(sg.updateTransform, sg);
292
+ t.subscribeAllChanges(sg.updateTransform, sg);
295
293
 
296
294
  // remember entity for lookups
297
295
  sg.__entity = entity;
298
296
 
299
297
  // insert BVH entry
300
- const bvh = this.__bvh_binary;
301
-
302
- const bvh_node_id = bvh.allocate_node();
303
-
304
- bvh.node_set_aabb(bvh_node_id, sg.__bvh_aabb);
305
- bvh.node_set_user_data(bvh_node_id, entity);
306
- bvh.insert_leaf(bvh_node_id);
307
-
308
- sg.__bvh_tree = bvh;
309
- sg.__bvh_leaf_id = bvh_node_id;
310
-
298
+ sg.__bvh_leaf.link(this.__bvh_binary, entity);
311
299
 
312
300
  // update usage count
313
301
  const geometry_id = sg.geometry.id;
@@ -324,19 +312,10 @@ export class ShadedGeometrySystem extends System {
324
312
  * @param {number} entity
325
313
  */
326
314
  unlink(sg, t, entity) {
327
- t.position.onChanged.remove(sg.updateTransform, sg);
328
- t.rotation.onChanged.remove(sg.updateTransform, sg);
329
- t.scale.onChanged.remove(sg.updateTransform, sg);
315
+ t.unsubscribeAllChanges(sg.updateTransform, sg);
330
316
 
331
317
  // disconnect BVH
332
- const node_id = sg.__bvh_leaf_id;
333
-
334
- this.__bvh_binary.remove_leaf(node_id);
335
- this.__bvh_binary.release_node(node_id);
336
-
337
- // reset BVH references
338
- sg.__bvh_leaf_id = -1;
339
- sg.__bvh_tree = null;
318
+ sg.__bvh_leaf.unlink();
340
319
 
341
320
  const geometry_id = sg.geometry.id;
342
321
  const count_existing = this.__geometry_usage_counters.get(geometry_id);
@@ -162,15 +162,11 @@ export class SGMeshSystem extends System {
162
162
 
163
163
  entity_node.build(ecd);
164
164
 
165
- transform.position.onChanged.add(copy_transform);
166
- transform.rotation.onChanged.add(copy_transform);
167
- transform.scale.onChanged.add(copy_transform);
165
+ transform.subscribeAllChanges(copy_transform);
168
166
 
169
167
  entity_node.on.destroyed.addOne(() => {
170
168
 
171
- transform.position.onChanged.remove(copy_transform);
172
- transform.rotation.onChanged.remove(copy_transform);
173
- transform.scale.onChanged.remove(copy_transform);
169
+ transform.unsubscribeAllChanges(copy_transform);
174
170
 
175
171
  });
176
172
 
@@ -194,7 +194,7 @@ export class BVHGeometryRaycaster {
194
194
  directionX, directionY, directionZ
195
195
  );
196
196
 
197
- ray3_array_apply_matrix4(ray_tmp, ray_tmp, m4_tmp);
197
+ ray3_array_apply_matrix4(ray_tmp, 0,ray_tmp,0, m4_tmp);
198
198
 
199
199
  const _originX = ray_tmp[0];
200
200
  const _originY = ray_tmp[1];
@@ -11,5 +11,5 @@ export class ParameterLookupTable {
11
11
 
12
12
  write(value: number[], positions: number[]): void
13
13
 
14
- static from(itemSize: number, value: number[], positions: number[]): ParameterLookupTable
14
+ static from(itemSize: number, value: number[], positions?: number[]): ParameterLookupTable
15
15
  }
@@ -6,6 +6,7 @@ import { ParameterLookupTableFlags } from "./ParameterLookupTableFlags.js";
6
6
  import { ParameterLookupTableSerializationAdapter } from "../emitter/serde/ParameterLookupTableSerializationAdapter.js";
7
7
  import { computeHashIntegerArray } from "../../../../../../core/collection/array/computeHashIntegerArray.js";
8
8
  import { computeHashFloatArray } from "../../../../../../core/math/hash/computeHashFloatArray.js";
9
+ import { isArrayEqualStrict } from "../../../../../../core/collection/array/isArrayEqualStrict.js";
9
10
 
10
11
 
11
12
  export class ParameterLookupTable {
@@ -211,7 +212,7 @@ export class ParameterLookupTable {
211
212
 
212
213
  if (positions === undefined) {
213
214
 
214
- console.warn('positions are undefined, assuming uniform distribution');
215
+ //console.warn('positions are undefined, assuming uniform distribution');
215
216
  this.computeUniformPositions();
216
217
 
217
218
  } else {
@@ -309,52 +310,18 @@ export class ParameterLookupTable {
309
310
  * @returns {boolean}
310
311
  */
311
312
  equals(other) {
312
- if (this.itemSize !== other.itemSize) {
313
- return false;
314
- }
315
-
316
- const thisData = this.data;
317
- const otherData = other.data;
318
-
319
- const thisDataLength = thisData.length;
320
- const otherDataLength = otherData.length;
321
-
322
- if (thisDataLength !== otherDataLength) {
323
- return false;
313
+ if(this === other){
314
+ // identity shortcut
315
+ return true;
324
316
  }
325
317
 
326
- const thisPositions = this.positions;
327
- const otherPositions = other.positions;
328
-
329
- const thisPositionsLength = thisPositions.length;
330
- const otherPositionsLength = otherPositions.length;
331
-
332
- if (thisPositionsLength !== otherPositionsLength) {
318
+ if (this.itemSize !== other.itemSize) {
333
319
  return false;
334
320
  }
335
321
 
336
- let i;
337
-
338
- for (i = 0; i < thisPositionsLength; i++) {
339
- const pA = thisPositions[i];
340
- const pB = otherPositions[i];
341
-
342
- if (pA !== pB) {
343
- return false;
344
- }
345
- }
346
-
347
- for (i = 0; i < thisDataLength; i++) {
348
- const dA = thisData[i];
349
- const dB = otherData[i];
350
-
351
- if (dA !== dB) {
352
- return false;
353
- }
354
- }
355
-
356
- //equal
357
- return true;
322
+ return isArrayEqualStrict(this.data, other.data)
323
+ && isArrayEqualStrict(this.positions, other.positions)
324
+ ;
358
325
  }
359
326
 
360
327
  validate() {
@@ -408,7 +375,7 @@ export class ParameterLookupTable {
408
375
  static from(itemSize, values, positions) {
409
376
  const r = new ParameterLookupTable(itemSize);
410
377
 
411
- r.write(values, positions)
378
+ r.write(values, positions);
412
379
 
413
380
  return r;
414
381
  }