@woosh/meep-engine 2.33.74 → 2.34.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.
Files changed (52) hide show
  1. package/core/collection/Set.js +0 -61
  2. package/core/collection/array/arrayIndexByEquality.js +20 -0
  3. package/core/collection/array/arraySetDiff.js +42 -0
  4. package/core/collection/array/arraySetSortingDiff.js +67 -0
  5. package/core/collection/array/arraySetSortingDiff.spec.js +74 -0
  6. package/core/collection/array/array_filter_by_multiple.js +36 -0
  7. package/core/collection/array/weightedRandomFromArray.js +9 -5
  8. package/core/collection/list/FilteredListProjection.js +1 -1
  9. package/core/collection/list/List.js +2 -1
  10. package/core/geom/3d/topology/compareEdges.js +16 -0
  11. package/core/geom/3d/topology/compareFaces.js +9 -0
  12. package/core/geom/3d/topology/compareVertices.js +9 -0
  13. package/core/geom/3d/topology/computeTopoMeshVertexDuplicates.js +25 -6
  14. package/core/geom/3d/topology/expandConnectivityByLocality.js +35 -19
  15. package/core/geom/Vector2.js +7 -2
  16. package/core/geom/Vector3.js +2 -2
  17. package/core/geom/v3_angle_between.js +3 -1
  18. package/editor/view/ecs/components/items/ItemContainerController.stories.js +1 -1
  19. package/engine/asset/loaders/image/ImageDecoderWorker.js +3 -2
  20. package/engine/asset/loaders/image/ImageRGBADataAsset.js +2 -6
  21. package/engine/asset/loaders/image/ImageRGBADataLoader.js +18 -2
  22. package/engine/asset/loaders/image/codec/NativeImageDecoder.js +2 -1
  23. package/engine/asset/loaders/image/png/PNG.js +3 -2
  24. package/engine/asset/loaders/image/png/PNGReader.js +1 -0
  25. package/engine/ecs/EntityComponentDataset.js +1 -1
  26. package/engine/ecs/terrain/ecs/splat/SplatMapping.js +39 -26
  27. package/engine/graphics/ecs/camera/topdown/TopDownCameraController.js +3 -4
  28. package/engine/graphics/ecs/highlight/system/MeshHighlightSystem.d.ts +3 -2
  29. package/engine/graphics/ecs/highlight/system/RenderableHighlightSystem.d.ts +3 -1
  30. package/engine/graphics/ecs/highlight/system/ShadedGeometryHighlightSystem.d.ts +8 -0
  31. package/engine/graphics/ecs/highlight/system/ShadedGeometryHighlightSystem.js +180 -0
  32. package/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +74 -16
  33. package/engine/graphics/ecs/mesh-v2/ShadedGeometryFlags.js +7 -0
  34. package/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.js +9 -0
  35. package/engine/graphics/ecs/mesh-v2/prototypeShadedGeometry.js +4 -2
  36. package/engine/graphics/micron/build/buildMicronGeometryFromBufferGeometry.js +41 -1
  37. package/engine/graphics/micron/plugin/MicronRenderPlugin.js +10 -1
  38. package/engine/graphics/particles/particular/engine/parameter/ParticleParameter.js +7 -2
  39. package/engine/graphics/particles/particular/engine/utils/volume/prototypeParticleVolume.js +3 -2
  40. package/engine/graphics/render/forward_plus/query/query_bvh_frustum_from_texture.js +7 -3
  41. package/engine/graphics/texture/sampler/Sampler2D.js +2 -0
  42. package/engine/graphics/texture/sampler/downsampleSampler2D.js +3 -1
  43. package/engine/graphics/texture/sampler/genericResampleSampler2D.js +67 -0
  44. package/engine/graphics/texture/sampler/scaleSampler2D.js +29 -35
  45. package/engine/graphics/texture/sampler/upsampleSampler2D.js +47 -0
  46. package/generation/filtering/numeric/CellFilterReadGridLayer.js +2 -2
  47. package/generation/filtering/numeric/math/CellFilterSaturate.js +24 -0
  48. package/package.json +1 -1
  49. package/samples/terrain/from_image.js +289 -0
  50. package/samples/terrain/from_image_2.js +219 -0
  51. package/view/elements/radial/RadialMenu.js +1 -1
  52. package/generation/theme/TerrainThemeApplicator.js +0 -6
@@ -23,7 +23,7 @@ export class ImageRGBADataLoader extends AssetLoader {
23
23
  /**
24
24
  *
25
25
  * @param {string} path
26
- * @returns {Promise<{data:ArrayBuffer, width: number, height:number, itemSize: number}>}
26
+ * @returns {Promise<{data:ArrayBuffer, width: number, height:number, itemSize: number, bitDepth:number}>}
27
27
  * @private
28
28
  */
29
29
  async __decode_via_worker(path) {
@@ -45,7 +45,23 @@ export class ImageRGBADataLoader extends AssetLoader {
45
45
 
46
46
  const bitmap = await this.__decode_via_worker(path);
47
47
 
48
- return new ImageRGBADataAsset(new Uint8Array(bitmap.data), bitmap.width, bitmap.height, bitmap.itemSize);
48
+
49
+ let data;
50
+
51
+ switch (bitmap.bitDepth) {
52
+ case 8:
53
+
54
+ data = new Uint8Array(bitmap.data);
55
+ break
56
+ case 16:
57
+ data = new Uint16Array(bitmap.data);
58
+ break;
59
+ default:
60
+ throw new Error(`Unsupported bit depth '${bitmap.bitDepth}'`);
61
+ }
62
+
63
+
64
+ return new ImageRGBADataAsset(data, bitmap.width, bitmap.height, bitmap.itemSize);
49
65
  }
50
66
 
51
67
  load(path, success, failure, progress) {
@@ -46,7 +46,8 @@ export class NativeImageDecoder extends Codec {
46
46
  data: rgba_data,
47
47
  width: width,
48
48
  height: height,
49
- itemSize: 4
49
+ itemSize: 4,
50
+ bitDepth: 8
50
51
  };
51
52
  }
52
53
  }
@@ -364,7 +364,7 @@ PNG.prototype.getUint8Data_case3 = function () {
364
364
  }
365
365
 
366
366
  /**
367
- * @returns {{itemSize:number, data:Uint8Array}}
367
+ * @returns {{itemSize:number, data:Uint8Array, bitDepth: number}}
368
368
  */
369
369
  PNG.prototype.getUint8Data = function () {
370
370
  let data;
@@ -397,6 +397,7 @@ PNG.prototype.getUint8Data = function () {
397
397
 
398
398
  return {
399
399
  data,
400
- itemSize
400
+ itemSize,
401
+ bitDepth: this.bitDepth
401
402
  };
402
403
  };
@@ -61,6 +61,7 @@ PNGReader.prototype.decodeHeader = function () {
61
61
 
62
62
  buffer.readBytes(header, 0, 8)
63
63
 
64
+ // see https://www.w3.org/TR/PNG-Structure.html
64
65
  if (!isArrayEqualStrict(header, [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A])) {
65
66
  throw new Error('invalid PNGReader file (bad signature)');
66
67
  }
@@ -5,8 +5,8 @@ import Signal, {
5
5
  findSignalHandlerIndexByHandleAndContext
6
6
  } from "../../core/events/signal/Signal.js";
7
7
  import { EventType } from "./EntityManager.js";
8
- import { arraySetDiff } from "../../core/collection/Set.js";
9
8
  import { SignalHandler } from "../../core/events/signal/SignalHandler.js";
9
+ import { arraySetDiff } from "../../core/collection/array/arraySetDiff.js";
10
10
 
11
11
  /**
12
12
  *
@@ -46,32 +46,7 @@ export function loadLegacyTerrainSplats(description, mapping, am) {
46
46
 
47
47
  mapping.resize(width, height, 4);
48
48
 
49
-
50
- const weightData = mapping.weightData;
51
-
52
- const dataOffset = index * width * height;
53
-
54
- const sourceWidth = source.width;
55
- const sourceHeight = source.height;
56
-
57
- const source_max_y = sourceHeight - 1;
58
- const source_max_x = sourceWidth - 1;
59
-
60
- for (let y = 0; y < height; y++) {
61
- const v = y / height;
62
-
63
- for (let x = 0; x < width; x++) {
64
-
65
- const u = x / width;
66
-
67
- const targetIndex = y * width + x;
68
- const targetAddress = dataOffset + targetIndex;
69
-
70
- const value = source.sampleChannelBilinear(u * source_max_x, v * source_max_y, 0);
71
-
72
- weightData[targetAddress] = value;
73
- }
74
- }
49
+ mapping.writeLayerFromSampler(source, index, 0);
75
50
 
76
51
  });
77
52
  }
@@ -146,6 +121,44 @@ export class SplatMapping {
146
121
  this.materialTexture = new DataTexture(new Uint8Array(width * height * 4), width, height);
147
122
  }
148
123
 
124
+ /**
125
+ *
126
+ * @param {Sampler2D} source
127
+ * @param {number} index
128
+ * @param {number} channel
129
+ */
130
+ writeLayerFromSampler(source, index, channel = 0) {
131
+ const weightData = this.weightData;
132
+
133
+ const width = this.size.x;
134
+ const height = this.size.y;
135
+
136
+ const dataOffset = index * width * height;
137
+
138
+ const sourceWidth = source.width;
139
+ const sourceHeight = source.height;
140
+
141
+ const source_max_y = sourceHeight - 1;
142
+ const source_max_x = sourceWidth - 1;
143
+
144
+ for (let y = 0; y < height; y++) {
145
+ const v = y / height;
146
+
147
+ for (let x = 0; x < width; x++) {
148
+
149
+ const u = x / width;
150
+
151
+ const targetIndex = y * width + x;
152
+ const targetAddress = dataOffset + targetIndex;
153
+
154
+ const value = source.sampleChannelBilinear(u * source_max_x, v * source_max_y, channel);
155
+
156
+ weightData[targetAddress] = value;
157
+ }
158
+ }
159
+
160
+ }
161
+
149
162
  /**
150
163
  *
151
164
  * @param {Uint8Array} source
@@ -6,12 +6,11 @@
6
6
  import Vector3 from '../../../../../core/geom/Vector3.js';
7
7
  import { assert } from "../../../../../core/assert.js";
8
8
  import { lerp } from "../../../../../core/math/lerp.js";
9
- import { Euler, Matrix4 } from "three";
9
+ import { Matrix4 } from "three";
10
10
  import { normalize_angle_rad } from "../../../../../core/geom/normalize_angle_rad.js";
11
11
  import { eulerAnglesFromMatrix } from "../../../../../core/geom/3d/eulerAnglesFromMatrix.js";
12
12
 
13
13
  const m4 = new Matrix4();
14
- const euler = new Euler();
15
14
  const angles = [];
16
15
 
17
16
  const panOffset = new Vector3();
@@ -30,10 +29,10 @@ export function rotate_from_view(displacement_x, displacement_y, input, output)
30
29
  const i_yaw = normalize_angle_rad(input.yaw);
31
30
  const i_roll = normalize_angle_rad(input.roll);
32
31
 
33
- const d_roll = (i_roll >= Math.PI || i_roll <= -Math.PI) ? -1 : 1;
32
+ const d_roll = (i_roll >= (Math.PI / 2 - 0.0001) || i_roll <= -(Math.PI / 2 - 0.0001)) ? -1 : 1;
34
33
 
35
34
  // flip rotation axis when pitch is over 90deg in either direction, that is UP vector is pointing down
36
- const d_yaw = d_roll * ((i_pitch > Math.PI || i_pitch < -Math.PI) ? -1 : 1) * displacement_x;
35
+ const d_yaw = d_roll * ((i_pitch > Math.PI || i_pitch < 0) ? -1 : 1) * displacement_x;
37
36
 
38
37
  output.yaw = i_yaw + d_yaw;
39
38
  output.pitch = i_pitch - displacement_y;
@@ -1,7 +1,8 @@
1
1
  import {System} from "../../../../ecs/System";
2
- import {GraphicsEngine} from "../../../GraphicsEngine";
3
2
  import Engine from "../../../../Engine";
3
+ import Highlight from "../Highlight";
4
+ import Mesh from "../../mesh/Mesh";
4
5
 
5
- export default class MeshHighlightSystem extends System {
6
+ export default class MeshHighlightSystem extends System<Highlight, Mesh> {
6
7
  constructor(engine: Engine)
7
8
  }
@@ -1,6 +1,8 @@
1
1
  import {System} from "../../../../ecs/System";
2
2
  import Engine from "../../../../Engine";
3
+ import Highlight from "../Highlight";
4
+ import Renderable from "../../../../ecs/components/Renderable";
3
5
 
4
- export class RenderableHighlightSystem extends System {
6
+ export class RenderableHighlightSystem extends System<Highlight, Renderable> {
5
7
  constructor(engine: Engine)
6
8
  }
@@ -0,0 +1,8 @@
1
+ import {System} from "../../../../ecs/System";
2
+ import {ShadedGeometry} from "../../mesh-v2/ShadedGeometry";
3
+ import Highlight from "../Highlight";
4
+ import Engine from "../../../../Engine";
5
+
6
+ export class ShadedGeometryHighlightSystem extends System<Highlight, ShadedGeometry> {
7
+ constructor(engine: Engine)
8
+ }
@@ -0,0 +1,180 @@
1
+ import { System } from "../../../../ecs/System.js";
2
+ import { HighlightRenderElementSource } from "../plugin/HighlightRenderElementSource.js";
3
+ import Highlight from "../Highlight.js";
4
+ import { OutlineRenderPlugin } from "../plugin/OutlineRenderPlugin.js";
5
+ import { ShadedGeometry } from "../../mesh-v2/ShadedGeometry.js";
6
+
7
+ class Supplier extends HighlightRenderElementSource {
8
+ /**
9
+ *
10
+ * @param {ShadedGeometryHighlightSystem} system
11
+ */
12
+ constructor(system) {
13
+ super();
14
+
15
+ /**
16
+ *
17
+ * @type {ShadedGeometryHighlightSystem}
18
+ * @private
19
+ */
20
+ this.__system = system;
21
+
22
+ /**
23
+ *
24
+ * @type {ObjectPoolFactory<HighlightRenderElement>}
25
+ * @private
26
+ */
27
+ this.__pool = null;
28
+ /**
29
+ *
30
+ * @type {HighlightRenderGroup}
31
+ * @private
32
+ */
33
+ this.__group = null;
34
+ }
35
+
36
+ collect(pool, group) {
37
+
38
+ this.__pool = pool;
39
+ this.__group = group;
40
+
41
+ const system = this.__system;
42
+
43
+ /**
44
+ *
45
+ * @type {EntityManager}
46
+ */
47
+ const em = system.entityManager;
48
+
49
+ const dataset = em.dataset;
50
+
51
+ if (dataset === null) {
52
+ return;
53
+ }
54
+
55
+ dataset.traverseEntities([Highlight, ShadedGeometry], this.__visit, this);
56
+ }
57
+
58
+ /**
59
+ *
60
+ * @param {Highlight} highlight
61
+ * @param {ShadedGeometry} sg
62
+ * @param {number} entity
63
+ * @private
64
+ */
65
+ __visit(highlight, sg, entity) {
66
+
67
+ // TODO cull by visibility
68
+
69
+ // if (!sg.getFlag(ShadedGeometryFlags.InView)) {
70
+ // return;
71
+ // }
72
+
73
+ const elements = highlight.elements;
74
+
75
+ if (elements.isEmpty()) {
76
+ // no elements
77
+ return;
78
+ }
79
+
80
+ const object = sg.__cached_object;
81
+
82
+ if (object === null) {
83
+ // no renderable primitive
84
+ return;
85
+ }
86
+
87
+ const renderElement = this.__pool.create();
88
+
89
+ renderElement.definitions = elements.asArray();
90
+ renderElement.object = object;
91
+
92
+ this.__group.elements.add(renderElement);
93
+ }
94
+ }
95
+
96
+ export class ShadedGeometryHighlightSystem extends System {
97
+ /**
98
+ *
99
+ * @param {Engine} engine
100
+ * @constructor
101
+ */
102
+ constructor(engine) {
103
+ super();
104
+
105
+ /**
106
+ *
107
+ * @type {Engine}
108
+ * @private
109
+ */
110
+ this.__engine = engine;
111
+
112
+ this.dependencies = [Highlight, ShadedGeometry];
113
+
114
+ this.__element_source = new Supplier(this);
115
+
116
+ /**
117
+ *
118
+ * @type {Reference<OutlineRenderPlugin>}
119
+ * @private
120
+ */
121
+ this.__plugin_renderer_ref = null;
122
+
123
+ }
124
+
125
+ /**
126
+ *
127
+ * @param {EntityManager} entityManager
128
+ * @param {function} readyCallback
129
+ * @param {function} errorCallback
130
+ */
131
+ shutdown(entityManager, readyCallback, errorCallback) {
132
+ try {
133
+
134
+ if (this.__plugin_renderer_ref !== null) {
135
+
136
+ this.__plugin_renderer_ref.getValue().removeSource(this.__element_source);
137
+
138
+ this.__plugin_renderer_ref.release();
139
+
140
+ this.__plugin_renderer_ref = null;
141
+ }
142
+
143
+ readyCallback();
144
+ } catch (e) {
145
+ errorCallback();
146
+ }
147
+ }
148
+
149
+ /**
150
+ *
151
+ * @param {EntityManager} entityManager
152
+ * @param {function} readyCallback
153
+ * @param {function} errorCallback
154
+ */
155
+ startup(entityManager, readyCallback, errorCallback) {
156
+ /**
157
+ *
158
+ * @type {EntityManager}
159
+ */
160
+ this.entityManager = entityManager;
161
+
162
+ const engine = this.__engine;
163
+
164
+ engine.plugins.acquire(OutlineRenderPlugin)
165
+ .then(ref => {
166
+
167
+ this.__plugin_renderer_ref = ref;
168
+
169
+ /**
170
+ *
171
+ * @type {OutlineRenderPlugin}
172
+ */
173
+ const plugin = ref.getValue();
174
+
175
+ plugin.addSource(this.__element_source);
176
+
177
+ }, errorCallback)
178
+ .then(readyCallback);
179
+ }
180
+ }
@@ -53,6 +53,60 @@ export class ShadedGeometry {
53
53
  * @private
54
54
  */
55
55
  this.__transform = null;
56
+
57
+ /**
58
+ *
59
+ * @type {number}
60
+ */
61
+ this.flags = 0;
62
+ }
63
+
64
+ /**
65
+ *
66
+ * @param {number|ShadedGeometryFlags} flag
67
+ * @returns {void}
68
+ */
69
+ setFlag(flag) {
70
+ this.flags |= flag;
71
+ }
72
+
73
+ /**
74
+ *
75
+ * @param {number|ShadedGeometryFlags} flag
76
+ * @returns {void}
77
+ */
78
+ clearFlag(flag) {
79
+ this.flags &= ~flag;
80
+ }
81
+
82
+ /**
83
+ *
84
+ * @param {number|ShadedGeometryFlags} flag
85
+ * @param {boolean} value
86
+ */
87
+ writeFlag(flag, value) {
88
+ if (value) {
89
+ this.setFlag(flag);
90
+ } else {
91
+ this.clearFlag(flag);
92
+ }
93
+ }
94
+
95
+ /**
96
+ *
97
+ * @param {number|ShadedGeometryFlags} flag
98
+ * @returns {boolean}
99
+ */
100
+ getFlag(flag) {
101
+ return (this.flags & flag) === flag;
102
+ }
103
+
104
+ /**
105
+ * Current cached entity that this component is attached to
106
+ * @return {number}
107
+ */
108
+ get entity() {
109
+ return this.__entity;
56
110
  }
57
111
 
58
112
  /**
@@ -91,7 +145,7 @@ export class ShadedGeometry {
91
145
  *
92
146
  * @param {THREE.BufferGeometry} geometry
93
147
  * @param {THREE.Material} material
94
- * @param draw_mode
148
+ * @param {DrawMode} [draw_mode]
95
149
  */
96
150
  from(geometry, material, draw_mode = DrawMode.Triangles) {
97
151
  this.geometry = geometry;
@@ -113,38 +167,42 @@ export class ShadedGeometry {
113
167
 
114
168
  /**
115
169
  *
116
- * @param geometry
117
- * @param material
118
- * @param mode
170
+ * @param {THREE.BufferGeometry} geometry
171
+ * @param {THREE.Material} material
172
+ * @param {DrawMode} [draw_mode]
119
173
  * @return {ShadedGeometry}
120
174
  */
121
- static from(geometry, material, mode) {
175
+ static from(geometry, material, draw_mode) {
122
176
  const r = new ShadedGeometry();
123
177
 
124
- r.from(geometry, material, mode);
178
+ r.from(geometry, material, draw_mode);
125
179
 
126
180
  return r;
127
181
  }
128
182
 
129
183
  updateTransform() {
184
+ const object_3d = this.__cached_object;
185
+
130
186
  // update matrix
131
- this.__cached_object.updateMatrix();
132
- this.__cached_object.updateMatrixWorld();
187
+ object_3d.updateMatrix();
188
+ object_3d.updateMatrixWorld();
133
189
 
134
190
  // update bounds
135
-
136
191
  const gbb = this.geometry.boundingBox;
137
192
 
193
+ const min = gbb.min;
194
+ const max = gbb.max;
195
+
138
196
  _aabb3.setBounds(
139
- gbb.min.x,
140
- gbb.min.y,
141
- gbb.min.z,
142
- gbb.max.x,
143
- gbb.max.y,
144
- gbb.max.z
197
+ min.x,
198
+ min.y,
199
+ min.z,
200
+ max.x,
201
+ max.y,
202
+ max.z
145
203
  );
146
204
 
147
- updateNodeByMatrix4AndBBB(this.__bvh_leaf, _aabb3, this.__cached_object.matrix.elements);
205
+ updateNodeByMatrix4AndBBB(this.__bvh_leaf, _aabb3, object_3d.matrix.elements);
148
206
  }
149
207
 
150
208
  /**
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @readonly
3
+ * @enum {number}
4
+ */
5
+ export const ShadedGeometryFlags = {
6
+ InView: 1
7
+ };
@@ -8,7 +8,16 @@ import { v3_distance_sqr } from "../../../../core/geom/v3_distance_sqr.js";
8
8
  import { mat4 } from "gl-matrix";
9
9
  import { returnTrue } from "../../../../core/function/Functions.js";
10
10
 
11
+ /**
12
+ *
13
+ * @type {BinaryNode|LeafNode[]}
14
+ */
11
15
  const traversal_stack = [];
16
+
17
+ /**
18
+ *
19
+ * @type {number}
20
+ */
12
21
  let traversal_cursor = 0;
13
22
 
14
23
  /**
@@ -13,12 +13,14 @@ const eh = new EngineHarness();
13
13
  */
14
14
  async function main(engine) {
15
15
 
16
- await engine.entityManager.addSystem(new ShadedGeometrySystem(engine));
16
+ const em = engine.entityManager;
17
+
18
+ await em.addSystem(new ShadedGeometrySystem(engine));
17
19
 
18
20
  EngineHarness.buildBasics({ engine })
19
21
 
20
22
 
21
- const ecd = engine.entityManager.dataset;
23
+ const ecd = em.dataset;
22
24
 
23
25
  new EntityBuilder()
24
26
  .add(new Transform())
@@ -13,6 +13,9 @@ import { build_geometry_info } from "./build_geometry_info.js";
13
13
  import { build_leaf_patches_metis } from "./clustering/build_leaf_patches_metis.js";
14
14
  import { compute_buffer_geometry_byte_size } from "../../geometry/buffered/compute_buffer_geometry_byte_size.js";
15
15
  import { deinterleaveBufferGeometry } from "../../geometry/buffered/deinterleaveBufferGeometry.js";
16
+ import { AABB3 } from "../../../../core/bvh2/aabb3/AABB3.js";
17
+ import { min2 } from "../../../../core/math/min2.js";
18
+ import { max2 } from "../../../../core/math/max2.js";
16
19
 
17
20
  /**
18
21
  * Returns current time in milliseconds
@@ -100,6 +103,38 @@ function attributes_from_buffer_geometry(buffer_geometry) {
100
103
 
101
104
  const PRINT_VERBOSE_STATS = false;
102
105
 
106
+ /**
107
+ *
108
+ * @param {AABB3} result
109
+ * @param {number[]|ArrayLike<number>} input
110
+ * @param {number} input_length
111
+ */
112
+ function aabb3_from_v3_array(result, input, input_length) {
113
+ let x0 = Infinity;
114
+ let y0 = Infinity;
115
+ let z0 = Infinity;
116
+
117
+ let x1 = -Infinity;
118
+ let y1 = -Infinity;
119
+ let z1 = -Infinity;
120
+
121
+ for (let i = 0; i < input_length; i += 3) {
122
+ const x = input[i];
123
+ const y = input[i + 1];
124
+ const z = input[i + 2];
125
+
126
+ x0 = min2(x, x0);
127
+ y0 = min2(y, y0);
128
+ z0 = min2(z, z0);
129
+
130
+ x1 = max2(x, x1);
131
+ y1 = max2(y, y1);
132
+ z1 = max2(z, z1);
133
+ }
134
+
135
+ result.setBounds(x0, y0, z0, x1, y1, z1);
136
+ }
137
+
103
138
  /**
104
139
  *
105
140
  * @param {THREE.BufferGeometry} input
@@ -118,7 +153,12 @@ export async function buildMicronGeometryFromBufferGeometry(input) {
118
153
  const vertex_position_array = position_attribute.array;
119
154
 
120
155
  topoMesh.build(vertex_position_array, face_index_array);
121
- expandConnectivityByLocality(topoMesh);
156
+
157
+ // compute aabb
158
+ const geometry_aabb = new AABB3();
159
+ aabb3_from_v3_array(geometry_aabb, vertex_position_array, vertex_position_array.length);
160
+
161
+ expandConnectivityByLocality(topoMesh, geometry_aabb);
122
162
 
123
163
  /**
124
164
  * Used to generate neighbourhood assignment
@@ -98,7 +98,16 @@ class GLTFAssetTransformer extends AssetTransformer {
98
98
 
99
99
  const base = computePathDirectory(ad.path);
100
100
 
101
- const micron_data = await this.__am.promise(`${base}/${micron_uri}`, ASSET_TYPE_ARRAY_BUFFER);
101
+ let micron_data;
102
+
103
+ const micron_path = `${base}/${micron_uri}`;
104
+
105
+ try {
106
+ micron_data = await this.__am.promise(micron_path, ASSET_TYPE_ARRAY_BUFFER);
107
+ } catch (e) {
108
+ console.error(`Failed to load micron geometry '${micron_path}' referenced in GLTF (will skip): ${e}`);
109
+ return;
110
+ }
102
111
 
103
112
  // deserialize micron data
104
113
  const buffer = BinaryBuffer.fromArrayBuffer(micron_data.create());
@@ -173,8 +173,12 @@ export class ParticleParameter {
173
173
  //lock default track
174
174
  this.defaultTrackValue.disableWriteMode();
175
175
 
176
- for (i = 0; i < this.trackCount; i++) {
177
- track = this.tracks.get(i);
176
+ const track_count = this.trackCount;
177
+ const tracks = this.tracks;
178
+
179
+ for (i = 0; i < track_count; i++) {
180
+
181
+ track = tracks.get(i);
178
182
 
179
183
  if (track === undefined) {
180
184
  //write the default track into the parameter
@@ -183,6 +187,7 @@ export class ParticleParameter {
183
187
  //lock track
184
188
  track.disableWriteMode();
185
189
  }
190
+
186
191
  }
187
192
 
188
193
  this.computeStatistics();