@woosh/meep-engine 2.39.44 → 2.40.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.
@@ -5,6 +5,8 @@ import { assert } from "../../../../core/assert.js";
5
5
  import { noop } from "../../../../core/function/Functions.js";
6
6
  import { TerrainFlags } from "./TerrainFlags.js";
7
7
  import { ImageRGBADataLoader } from "../../../asset/loaders/image/ImageRGBADataLoader.js";
8
+ import { Transform } from "../../transform/Transform.js";
9
+ import { MATRIX_4_IDENTITY } from "../../../../core/geom/3d/matrix/MATRIX_4_IDENTITY.js";
8
10
 
9
11
  /**
10
12
  *
@@ -157,9 +159,12 @@ class TerrainSystem extends System {
157
159
  this.__time_delta = timeDelta;
158
160
 
159
161
 
160
- if (dataset !== null) {
161
- dataset.traverseComponents(Terrain, this.__visitTerrainComponent, this);
162
+ if (dataset === null) {
163
+ return;
162
164
  }
165
+
166
+
167
+ dataset.traverseComponents(Terrain, this.__visitTerrainComponent, this);
163
168
  }
164
169
 
165
170
  /**
@@ -171,13 +176,26 @@ class TerrainSystem extends System {
171
176
  __visitTerrainComponent(terrain, entity) {
172
177
  const em = this.entityManager;
173
178
 
174
- const dataset = em.dataset;
179
+ const ecd = em.dataset;
180
+
181
+ /**
182
+ *
183
+ * @type {Transform|undefined}
184
+ */
185
+ const transform = ecd.getComponent(entity, Transform);
186
+
187
+ if (transform !== undefined) {
188
+ // terrain has a transform
189
+ terrain.transform = transform.matrix;
190
+ }else{
191
+ terrain.transform = MATRIX_4_IDENTITY;
192
+ }
175
193
 
176
194
  terrain.update(this.__time_delta);
177
195
 
178
196
  //do frustum culling
179
197
  if (terrain.frustumCulled) {
180
- TerrainSystem.traverseVisibleTiles(dataset, terrain, ensureTileBuilt);
198
+ TerrainSystem.traverseVisibleTiles(ecd, terrain, ensureTileBuilt);
181
199
  }
182
200
  }
183
201
 
@@ -18,13 +18,14 @@ import ThreeFactory from '../../../graphics/three/ThreeFactory.js';
18
18
 
19
19
  import { LeafNode } from '../../../../core/bvh2/LeafNode.js';
20
20
 
21
- import BVHFromBufferGeometry from '../../../graphics/geometry/bvh/buffered/BVHFromBufferGeometry.js';
22
-
23
21
  import IndexedBinaryBVH from '../../../../core/bvh2/binary/IndexedBinaryBVH.js';
24
22
  import { BVHGeometryRaycaster } from "../../../graphics/geometry/bvh/buffered/BVHGeometryRaycaster.js";
25
23
  import ObservedInteger from "../../../../core/model/ObservedInteger.js";
26
24
  import { SurfacePoint3 } from "../../../../core/geom/3d/SurfacePoint3.js";
27
25
  import Signal from "../../../../core/events/signal/Signal.js";
26
+ import { mat4 } from "gl-matrix";
27
+ import { AABB3 } from "../../../../core/bvh2/aabb3/AABB3.js";
28
+ import { NumericInterval } from "../../../../core/math/interval/NumericInterval.js";
28
29
 
29
30
  function extractFaceIndexFromLeaf(leaf) {
30
31
  return leaf;
@@ -92,11 +93,17 @@ class TerrainTile {
92
93
  this.isBuildInProgress = false;
93
94
  this.referenceCount = 0;
94
95
 
96
+ /**
97
+ *
98
+ * @type {Signal<TerrainTile>}
99
+ */
95
100
  this.onBuilt = new Signal();
96
101
  this.onDestroyed = new Signal();
97
102
 
98
- this.buildCallbacks = [];
99
-
103
+ /**
104
+ * @private
105
+ * @type {{bottomLeft: boolean, top: boolean, left: boolean, bottom: boolean, bottomRight: boolean, topLeft: boolean, topRight: boolean, right: boolean}}
106
+ */
100
107
  this.stitching = {
101
108
  top: false,
102
109
  bottom: false,
@@ -110,27 +117,34 @@ class TerrainTile {
110
117
  bottomRight: false
111
118
  };
112
119
 
120
+ /**
121
+ * Initial estimate of height bounds for this tile
122
+ * Untransformed by transform matrix
123
+ * @type {NumericInterval}
124
+ * @private
125
+ */
126
+ this.__initial_height_range = new NumericInterval(Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY);
127
+
113
128
  this.raycaster = new BVHGeometryRaycaster();
114
129
  //Binary BVH form doesn't have distinct leaf objects and stores face indices directly, this requires a special face index extractor that treats leaves as indices directly.
115
130
  this.raycaster.extractFaceIndexFromLeaf = extractFaceIndexFromLeaf;
116
131
  }
117
132
 
118
133
  /**
119
- * @returns {Promise}
134
+ *
135
+ * @return {number[]}
120
136
  */
121
- promiseBuilt() {
122
-
137
+ get transform() {
138
+ return this.mesh.matrixWorld.elements;
123
139
  }
124
140
 
125
141
  /**
126
142
  *
127
- * @param {number} x
128
- * @param {number} y
129
- * @param {function} callback
130
- * @param {function} missCallback
143
+ * @param {number[]|Float32Array|mat4} m4
131
144
  */
132
- raycastVertical(x, y, callback, missCallback) {
133
- return this.raycaster.raycastVertical(x, y, callback, missCallback)
145
+ set transform(m4) {
146
+ mat4.copy(this.mesh.matrixWorld.elements, m4);
147
+ this.computeBoundingBox();
134
148
  }
135
149
 
136
150
  /**
@@ -188,7 +202,7 @@ class TerrainTile {
188
202
  }
189
203
 
190
204
  /**
191
- *
205
+ * Stitch vertex normals along the edges of the tile set
192
206
  * @param {TerrainTile|undefined} top
193
207
  * @param {TerrainTile|undefined} bottom
194
208
  * @param {TerrainTile|undefined} left
@@ -254,7 +268,9 @@ class TerrainTile {
254
268
  bottom.getVertexNormal(i, v0);
255
269
  top.getVertexNormal(otherOffset + i, v1);
256
270
 
257
- v0.add(v1).normalize();
271
+ v0.add(v1);
272
+ v0.normalize();
273
+
258
274
  bottom.setVertexNormal(i, v0);
259
275
  top.setVertexNormal(otherOffset + i, v0);
260
276
  }
@@ -316,7 +332,9 @@ class TerrainTile {
316
332
  right.getVertexNormal(index0, v0);
317
333
  left.getVertexNormal(index1, v1);
318
334
 
319
- v0.add(v1).normalize();
335
+ v0.add(v1);
336
+ v0.normalize();
337
+
320
338
  right.setVertexNormal(index0, v0);
321
339
  left.setVertexNormal(index1, v0);
322
340
  }
@@ -361,7 +379,11 @@ class TerrainTile {
361
379
  topRight.getVertexNormal(tCornerIndex, v2);
362
380
  bottomLeft.getVertexNormal(lCornerIndex, v3);
363
381
 
364
- v0.add(v1).add(v2).add(v3).normalize();
382
+ v0.add(v1);
383
+ v0.add(v2);
384
+ v0.add(v3);
385
+ v0.normalize();
386
+
365
387
  topLeft.setVertexNormal(tlCornerIndex, v0);
366
388
  bottomRight.setVertexNormal(cornerIndex, v0);
367
389
  topRight.setVertexNormal(tCornerIndex, v0);
@@ -404,118 +426,76 @@ class TerrainTile {
404
426
  stitchSides();
405
427
  }
406
428
 
407
- stitchNormals(top, left, topLeft) {
408
- const v0 = new Vector3(),
409
- v1 = new Vector3();
410
- if (top !== null && left !== null && topLeft !== null) {
411
-
412
- const v2 = new Vector3();
413
- const v3 = new Vector3();
414
- //fix corner
415
- const tlCornerIndex = (topLeft.size.x * topLeft.resolution.getValue()) * (topLeft.size.y * topLeft.resolution.getValue()) - 1;
416
- const cornerIndex = 0;
417
- const tCornerIndex = top.size.x * top.resolution.getValue() * (top.size.y * top.resolution.getValue() - 1);
418
- const lCornerIndex = left.size.x * left.resolution.getValue() - 1;
419
-
420
- topLeft.getVertexNormal(tlCornerIndex, v0);
421
- this.getVertexNormal(cornerIndex, v1);
422
- top.getVertexNormal(tCornerIndex, v2);
423
- left.getVertexNormal(lCornerIndex, v3);
424
-
425
- v0.add(v1).add(v2).add(v3).normalize();
426
- topLeft.setVertexNormal(tlCornerIndex, v0);
427
- this.setVertexNormal(cornerIndex, v0);
428
- top.setVertexNormal(tCornerIndex, v0);
429
- left.setVertexNormal(lCornerIndex, v0);
430
- }
431
- let i, l;
432
- let otherOffset;
433
- let otherResolution;
434
- const thisResolution = this.resolution.getValue();
435
- if (top !== null) {
436
- otherResolution = top.resolution.getValue();
437
- otherOffset = top.size.x * otherResolution * (top.size.y * otherResolution - 1);
438
- for (i = 0, l = this.size.x * thisResolution; i < l; i++) {
439
- this.getVertexNormal(i, v0);
440
- top.getVertexNormal(otherOffset + i, v1);
441
-
442
- v0.add(v1).normalize();
443
- this.setVertexNormal(i, v0);
444
- top.setVertexNormal(otherOffset + i, v0);
445
- }
446
- }
447
- if (left !== null) {
448
- otherResolution = left.resolution.getValue();
449
- otherOffset = left.size.x * otherResolution - 1;
450
- const otherMultiplier = left.size.x * otherResolution;
451
- const thisMultiplier = this.size.x * thisResolution;
452
- for (i = 0, l = this.size.y * thisResolution; i < l; i++) {
453
-
454
- const index0 = i * thisMultiplier;
455
- const index1 = otherOffset + i * otherMultiplier;
456
-
457
- this.getVertexNormal(index0, v0);
458
- left.getVertexNormal(index1, v1);
459
-
460
- v0.add(v1).normalize();
461
- this.setVertexNormal(index0, v0);
462
- left.setVertexNormal(index1, v0);
463
- }
464
- }
465
- }
466
-
467
429
  computeBoundingBox() {
430
+ /**
431
+ * @type {ThreeBox3}
432
+ */
433
+ let bb;
434
+
468
435
  const geometry = this.geometry;
469
- //check for bvh
470
- const bvh = this.bvh;
471
- if (bvh !== null) {
472
- geometry.boundingBox = new ThreeBox3(new ThreeVector3(bvh.x0, bvh.y0, bvh.z0), new ThreeVector3(bvh.x1, bvh.y1, bvh.z1));
473
436
 
474
- const dX = bvh.x1 - bvh.x0;
475
- const dY = bvh.y1 - bvh.y0;
476
- const dZ = bvh.z1 - bvh.z0;
437
+ if (geometry === null) {
438
+ // no geometry present yet
477
439
 
478
- const radius = Math.sqrt(dX * dX + dY * dY + dZ * dZ) / 2;
440
+ const position = this.position;
441
+ const scale = this.scale;
442
+ const size = this.size;
479
443
 
480
- const center = new ThreeVector3(bvh.x0 + dX / 2, bvh.y0 + dY / 2, bvh.z0 + dZ / 2);
444
+ const initial_height_range = this.__initial_height_range;
481
445
 
482
- geometry.boundingSphere = new ThreeSphere(center, radius);
483
- }
484
- //pull bounding box from geometry
485
- let bb = geometry.boundingBox;
486
- if (bb === null) {
487
- geometry.computeBoundingBox();
488
- bb = geometry.boundingBox;
489
- }
490
- this.boundingBox.setBounds(bb.min.x, bb.min.y, bb.min.z, bb.max.x, bb.max.y, bb.max.z);
491
- }
446
+ const min = new ThreeVector3(position.x * scale.x, initial_height_range.min, position.y * scale.y);
447
+ const max = new ThreeVector3(min.x + size.x * scale.x, initial_height_range.max, min.z + size.y * scale.y);
492
448
 
493
- generateBufferedGeometryBVH() {
494
- const geometry = this.geometry;
495
- // console.profile('build bvh');
496
- this.bvh = BVHFromBufferGeometry.buildUnsortedBinaryBVH(geometry);
497
- // console.profileEnd('build bvh');
498
- }
449
+ bb = new ThreeBox3(
450
+ min,
451
+ max
452
+ );
499
453
 
500
- unload() {
501
- this.isBuilt = false;
454
+ } else {
502
455
 
503
- this.geometry = null;
504
- this.bvh = null;
456
+ //check for bvh
457
+ const bvh = this.bvh;
458
+ if (bvh !== null) {
459
+ geometry.boundingBox = new ThreeBox3(new ThreeVector3(bvh.x0, bvh.y0, bvh.z0), new ThreeVector3(bvh.x1, bvh.y1, bvh.z1));
460
+
461
+ const dX = bvh.x1 - bvh.x0;
462
+ const dY = bvh.y1 - bvh.y0;
463
+ const dZ = bvh.z1 - bvh.z0;
464
+
465
+ const radius = Math.sqrt(dX * dX + dY * dY + dZ * dZ) / 2;
466
+
467
+ const center = new ThreeVector3(bvh.x0 + dX / 2, bvh.y0 + dY / 2, bvh.z0 + dZ / 2);
468
+
469
+ geometry.boundingSphere = new ThreeSphere(center, radius);
470
+ }
471
+ //pull bounding box from geometry
505
472
 
506
- const stitching = this.stitching;
473
+ bb = geometry.boundingBox;
474
+ if (bb === null) {
475
+ geometry.computeBoundingBox();
476
+ bb = geometry.boundingBox;
477
+ }
478
+ }
507
479
 
508
- stitching.top = false;
509
- stitching.bottom = false;
480
+ const x0 = bb.min.x;
481
+ const y0 = bb.min.y;
482
+ const z0 = bb.min.z;
510
483
 
511
- stitching.left = false;
512
- stitching.right = false;
484
+ const x1 = bb.max.x;
485
+ const y1 = bb.max.y;
486
+ const z1 = bb.max.z;
487
+
488
+ const geometry_bb = new AABB3(
489
+ x0, y0, z0,
490
+ x1, y1, z1
491
+ );
513
492
 
514
- stitching.topLeft = false;
515
- stitching.topRight = false;
493
+ geometry_bb.applyMatrix4(this.transform);
516
494
 
517
- stitching.bottomLeft = false;
518
- stitching.bottomRight = false;
495
+ this.boundingBox.setBounds(
496
+ geometry_bb.x0, geometry_bb.y0, geometry_bb.z0,
497
+ geometry_bb.x1, geometry_bb.y1, geometry_bb.z1
498
+ );
519
499
  }
520
500
 
521
501
  /**
@@ -523,23 +503,17 @@ class TerrainTile {
523
503
  * @param {number} min_height
524
504
  * @param {number} max_height
525
505
  */
526
- createInitialBounds(min_height, max_height) {
527
- const offset = this.position.clone().multiply(this.scale);
528
-
529
- const size = this.size.clone().multiply(this.scale);
530
-
531
- const max = offset.clone().add(size);
532
-
533
- this.boundingBox.setBounds(
534
- offset.x, min_height, offset.y,
535
- max.x, max_height, max.y
536
- );
506
+ setInitialHeightBounds(min_height, max_height) {
507
+ this.__initial_height_range.set(min_height, max_height);
537
508
  }
538
509
 
539
510
  dispose() {
540
511
  if (this.geometry !== null) {
541
512
  this.geometry.dispose();
513
+ this.geometry = null;
542
514
  }
515
+
516
+ this.isBuilt = false;
543
517
  }
544
518
 
545
519
  build(tileData) {
@@ -549,7 +523,9 @@ class TerrainTile {
549
523
  const tileDataGeometry = tileData.geometry;
550
524
 
551
525
  const g = new ThreeBufferGeometry();
526
+
552
527
  g.setIndex(new ThreeBufferAttribute(tileDataGeometry.indices, 1));
528
+
553
529
  g.setAttribute('position', new ThreeBufferAttribute(tileDataGeometry.vertices, 3));
554
530
  g.setAttribute('normal', new ThreeBufferAttribute(tileDataGeometry.normals, 3));
555
531
  g.setAttribute('uv', new ThreeBufferAttribute(tileDataGeometry.uvs, 2));
@@ -571,11 +547,6 @@ class TerrainTile {
571
547
  }
572
548
 
573
549
 
574
- //set bounding box
575
- // console.time('bb');
576
- this.computeBoundingBox();
577
- // console.timeEnd('bb');
578
-
579
550
  const mesh = this.mesh;
580
551
 
581
552
  mesh.geometry = g;
@@ -583,6 +554,11 @@ class TerrainTile {
583
554
  mesh.receiveShadow = true;
584
555
  mesh.castShadow = true;
585
556
 
557
+ //set bounding box
558
+ // console.time('bb');
559
+ this.computeBoundingBox();
560
+ // console.timeEnd('bb');
561
+
586
562
  // console.timeEnd('total');
587
563
  // console.groupEnd();
588
564