@woosh/meep-engine 2.33.37 → 2.33.38

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.
@@ -21,23 +21,29 @@ export function orient3d_fast(points, a, b, c, d) {
21
21
  const a3 = a * 3;
22
22
  const d3 = d * 3;
23
23
 
24
- const adx = points[a3] - points[d3];
24
+ const d_x = points[d3];
25
+
26
+ const adx = points[a3] - d_x;
25
27
 
26
28
  const b3 = b * 3;
27
29
 
28
- const bdx = points[b3] - points[d3];
30
+ const bdx = points[b3] - d_x;
29
31
 
30
32
  const c3 = c * 3;
31
33
 
32
- const cdx = points[c3] - points[d3];
34
+ const cdx = points[c3] - d_x;
35
+
36
+ const d_y = points[d3 + 1];
37
+
38
+ const ady = points[a3 + 1] - d_y;
39
+ const bdy = points[b3 + 1] - d_y;
40
+ const cdy = points[c3 + 1] - d_y;
33
41
 
34
- const ady = points[a3 + 1] - points[d3 + 1];
35
- const bdy = points[b3 + 1] - points[d3 + 1];
36
- const cdy = points[c3 + 1] - points[d3 + 1];
42
+ const d_z = points[d3 + 2];
37
43
 
38
- const adz = points[a3 + 2] - points[d3 + 2];
39
- const bdz = points[b3 + 2] - points[d3 + 2];
40
- const cdz = points[c3 + 2] - points[d3 + 2];
44
+ const adz = points[a3 + 2] - d_z;
45
+ const bdz = points[b3 + 2] - d_z;
46
+ const cdz = points[c3 + 2] - d_z;
41
47
 
42
48
  return adx * (bdy * cdz - bdz * cdy)
43
49
  + bdx * (cdy * adz - cdz * ady)
@@ -0,0 +1,43 @@
1
+ // Sample triangular depth map
2
+ // see CoD SIGGRAPH 2017 "Advances in Real-Time Graphics in Games" course
3
+ float GetDepthForTetrahedronProbe(float2 bary, uint4 encodedDepth)
4
+ {
5
+ float sampleY = floor(bary.y * 4.0f);
6
+ float sampleX = floor(bary.x * 4.0f);
7
+
8
+ int baseIndex = (int)(((11.0f - sampleY) * sampleY) * 0.5f + sampleX + 0.5f);
9
+ int lineLength = 5 - (int)sampleY;
10
+
11
+ float2 baseBary = float2(sampleX * 0.25f, sampleY * 0.25f);
12
+
13
+ int3 indices = int3(baseIndex + 1, baseIndex + lineLength, baseIndex);
14
+
15
+ float3 sampleBary;
16
+ sampleBary.x = (bary.x - baseBary.x) * 4.0f;
17
+ sampleBary.y = (bary.y - baseBary.y) * 4.0f;
18
+
19
+ if (sampleBary.x + sampleBary.y > 1.0f)
20
+ {
21
+ // above the diagonal
22
+ indices = int3(baseIndex + lineLength, baseIndex + 1, baseIndex + lineLength + 1);
23
+
24
+ float3 newSampleBary;
25
+ newSampleBary.x = -(sampleBary.y - 1.0f);
26
+ newSampleBary.y = -(sampleBary.x - 1.0f);
27
+ sampleBary = newSampleBary;
28
+ }
29
+
30
+ sampleBary.z = 1.0f - sampleBary.x - sampleBary.y;
31
+
32
+ float result = 0.0f;
33
+ for (int i=0; i<3; ++i)
34
+ {
35
+ uint currIndex = indices[i];
36
+ int intDepth = (encodedDepth[currIndex / 4] >> ((currIndex % 4) * 8)) & 0xFF;
37
+ float depth = (float)intDepth / 255.0f;
38
+
39
+ result += sampleBary[i] * depth;
40
+ }
41
+
42
+ return result;
43
+ }
@@ -1,199 +1,50 @@
1
1
  //
2
2
 
3
3
  import { compute_bounding_simplex_3d } from "./compute_bounding_simplex_3d.js";
4
- import { point_in_tetrahedron_circumsphere } from "./point_in_tetrahedron_circumsphere.js";
5
- import { tetrahedron_contains_point } from "./tetrahedron_contains_point.js";
6
- import { assert } from "../../../assert.js";
7
-
8
- /**
9
- * @readonly
10
- * @type {number}
11
- */
12
- const LAYOUT_TETRA_BYTE_SIZE = 9 * 4;
13
- const INVALID_NEIGHBOUR = 0xFFFFFFFF;
14
-
15
- /**
16
- *
17
- * Layout:
18
- * vertex_id_a :: uint
19
- * vertex_id_b :: uint
20
- * vertex_id_c :: uint
21
- * vertex_id_d :: uint
22
- * neighbour_a :: uint - neighbour tetrahedron, opposite to vertex A
23
- * neighbour_b :: uint - neighbour tetrahedron, opposite to vertex B
24
- * neighbour_c :: uint - neighbour tetrahedron, opposite to vertex C
25
- * neighbour_d :: uint - neighbour tetrahedron, opposite to vertex D
26
- * sub_determinant :: float - ?
27
- * Layout is similar to [1], but is interleaved for better cache locality
28
- */
29
- class TetrahedraCollection {
30
- constructor(initial_size) {
31
- this.__buffer = new ArrayBuffer(initial_size * 4 * 9);
32
-
33
- this.__view = new DataView(this.__buffer);
34
-
35
- this.__capacity = initial_size;
36
- this.__length = 0;
37
- }
38
-
39
- /**
40
- *
41
- * @param {number} tetra_index
42
- * @param {number} neighbour_index
43
- * @returns {number}
44
- */
45
- getNeighbour(tetra_index, neighbour_index) {
46
- const tetra_address = LAYOUT_TETRA_BYTE_SIZE * tetra_index;
47
- return this.__view.getUint32(tetra_address + (4 + neighbour_index) * 4);
48
- }
49
-
50
- /**
51
- *
52
- * @param {number[]|Float32Array} points
53
- * @param {number} a
54
- * @param {number} b
55
- * @param {number} c
56
- * @param {number} d
57
- */
58
- append(points, a, b, c, d) {
59
- const address = this.__length * LAYOUT_TETRA_BYTE_SIZE;
60
-
61
- // TODO check if there's enough room
62
-
63
- const view = this.__view;
64
-
65
- view.setUint32(address, a);
66
- view.setUint32(address + 4, b);
67
- view.setUint32(address + 8, c);
68
- view.setUint32(address + 12, d);
69
-
70
- // set neighbours
71
- view.setUint32(address + 16, INVALID_NEIGHBOUR);
72
- view.setUint32(address + 20, INVALID_NEIGHBOUR);
73
- view.setUint32(address + 24, INVALID_NEIGHBOUR);
74
- view.setUint32(address + 28, INVALID_NEIGHBOUR);
75
-
76
- this.__length++;
77
- }
78
-
79
- /**
80
- *
81
- * @param {number[]} points
82
- * @param {number} index
83
- * @returns {number} index of tetra or -1 if no containing tetra found
84
- */
85
- findTetraContainingPoint(points, index) {
86
- const data_view = this.__view;
87
-
88
- // TODO improve this
89
- const n = this.__length;
90
- for (let i = 0; i < n; i++) {
91
-
92
- const tet_address = i * LAYOUT_TETRA_BYTE_SIZE;
93
-
94
- const a = data_view.getUint32(tet_address);
95
- const b = data_view.getUint32(tet_address + 4);
96
- const c = data_view.getUint32(tet_address + 8);
97
- const d = data_view.getUint32(tet_address + 12);
98
-
99
- if (tetrahedron_contains_point(points, a, b, c, d, index)) {
100
- return i;
101
- }
102
- }
103
-
104
- return -1;
105
- }
106
-
107
- /**
108
- *
109
- * @param {number[]|Float32Array} points
110
- * @param {number} index
111
- */
112
- insertPoint(points, index) {
113
-
114
- // 1. walk to tetrahedron that contains this point
115
- const containing_tetra = this.findTetraContainingPoint(points, index);
116
-
117
- assert.isNonNegativeInteger(containing_tetra, 'containing_tetra');
118
-
119
- const cavity = [];
120
- const open_set = [
121
- containing_tetra
122
- ];
123
-
124
- const data_view = this.__view;
125
-
126
- // 2. find the Delaunay "cavity", a set of tetrahedrons who's circumsphere overlarlaps the point
127
- // perform breadth-first expansion on the containing tetra to identify the cavity
128
- while (open_set.length > 0) {
129
- const tetra = open_set.pop();
130
- cavity.push(tetra);
131
-
132
- // get neighbours
133
- for (let i = 0; i < 4; i++) {
134
- const neighbour = this.getNeighbour(tetra, i);
135
-
136
- if (
137
- (neighbour === INVALID_NEIGHBOUR) // no neighbour
138
- || cavity.includes(neighbour) // already visited
139
- || open_set.includes(neighbour) // already in open set
140
- ) {
141
-
142
- continue;
143
- }
144
-
145
- const neighbour_address = neighbour * LAYOUT_TETRA_BYTE_SIZE;
146
- const a = data_view.getUint32(neighbour_address);
147
- const b = data_view.getUint32(neighbour_address + 4);
148
- const c = data_view.getUint32(neighbour_address + 8);
149
- const d = data_view.getUint32(neighbour_address + 12);
150
-
151
- // check neighbour
152
- const is_in_sphere = point_in_tetrahedron_circumsphere(points, a, b, c, d, index);
153
-
154
- if (is_in_sphere) {
155
- open_set.push(neighbour);
156
- }
157
- }
158
- }
159
-
160
- // 3. remove the cavity tetrahedrons
161
-
162
- // 4. fill the cavity by creating new tetrahedrons connecting the point to the faces of cavity boundary
163
- }
164
- }
4
+ import { TetrahedraCollection } from "./tetrahedra_collection.js";
165
5
 
166
6
  /**
167
7
  * @see https://en.wikipedia.org/wiki/Bowyer%E2%80%93Watson_algorithm
168
8
  * @see [1] "One machine, one minute, three billion tetrahedra" by Célestin Marot et al
169
9
  * @param {number[]} input serialized set of 3d points (x,y,z)
170
- * @param {number} input_point_count
10
+ * @param {number} n number of points in the input
171
11
  */
172
- export function compute_delaunay_tetrahedral_mesh(input, input_point_count) {
12
+ export function compute_delaunay_tetrahedral_mesh(input, n) {
13
+ if (n < 4) {
14
+ // no mesh can be created, too few points
15
+ return;
16
+ }
17
+
173
18
  /**
174
19
  * According to [1] number of tetrahedra is around 6 times greater than number of input vertices, we use that fact to pre-allocate memory
20
+ * From the book of Cheng et al. 'Delaunay Mesh Generation' A triangulation of n vertices in R^3 has at most `ntet=(n^2 − 3n − 2)/2` tetrahedra,
21
+ * at most nedg=(n^2 − n)/2` edges (this is simply the 2-combination of n)
22
+ * and at most `ntri=n^2 − 3n = 2*ntet+2` triangles
23
+ *
24
+ * The +7 is for the initial "super" tetrahedron and 6 tetras for intermediate triangulation
175
25
  */
176
- const tetrahedrons = new TetrahedraCollection(input_point_count * 6.01);
26
+ const tetrahedron_count_upper_bound = Math.ceil((n * n - 3 * n - 2) / 2) + 7;
27
+ const tetrahedrons = new TetrahedraCollection(tetrahedron_count_upper_bound);
177
28
  // TODO apply spatial sort to point, to get better cache locality
178
29
 
179
30
  // compute bounds over the input
180
- const points = new Float32Array((input_point_count + 4) * 3);
31
+ const points = new Float32Array((n + 4) * 3);
181
32
 
182
33
  points.set(input);
183
34
 
184
35
  /*
185
36
  create super bounding volume
186
37
  */
187
- compute_bounding_simplex_3d(points, input_point_count * 3, points, input_point_count, 1);
38
+ compute_bounding_simplex_3d(points, n * 3, points, n, 1);
188
39
 
189
- tetrahedrons.append(points, input_point_count, input_point_count + 1, input_point_count + 2, input_point_count + 3);
40
+ tetrahedrons.append(points, n, n + 1, n + 2, n + 3);
190
41
 
191
42
  // add all points to the mesh
192
- for (let i = 0; i < input_point_count; i++) {
43
+ for (let i = 0; i < n; i++) {
193
44
  tetrahedrons.insertPoint(points, i);
194
45
  }
195
46
 
196
47
  // remove tetras formed by with the super bounding volume
197
- // TODO implement
48
+ tetrahedrons.removeTetrasConnectedToPoints(points, n, n + 3);
198
49
  }
199
50
 
@@ -3,3 +3,12 @@ import { compute_delaunay_tetrahedral_mesh } from "./compute_delaunay_tetrahedra
3
3
  test('single point', () => {
4
4
  compute_delaunay_tetrahedral_mesh([1, 2, 3], 1);
5
5
  });
6
+
7
+ test('exactly 4 points', () => {
8
+ compute_delaunay_tetrahedral_mesh([
9
+ -1, 0, 0,
10
+ 1, 0, 0,
11
+ 0.5, 1, 0,
12
+ 0.5, 0, 1
13
+ ], 4);
14
+ });
@@ -0,0 +1,279 @@
1
+ import { tetrahedron_contains_point } from "./tetrahedron_contains_point.js";
2
+ import { assert } from "../../../assert.js";
3
+ import { point_in_tetrahedron_circumsphere } from "./point_in_tetrahedron_circumsphere.js";
4
+ import { BitSet } from "../../../binary/BitSet.js";
5
+
6
+ /**
7
+ * @readonly
8
+ * @type {number}
9
+ */
10
+ const LAYOUT_TETRA_BYTE_SIZE = 9 * 4;
11
+ const INVALID_NEIGHBOUR = 0xFFFFFFFF;
12
+
13
+ class Cavity {
14
+ constructor() {
15
+ this.indices = [];
16
+ this.__size = 0;
17
+ }
18
+
19
+ /**
20
+ *
21
+ * @param {number} i
22
+ */
23
+ push(i) {
24
+ this.indices[this.__size++] = i;
25
+ }
26
+
27
+ /**
28
+ *
29
+ * @param {number} i
30
+ * @returns {boolean}
31
+ */
32
+ includes(i) {
33
+ const n = this.__size;
34
+ for (let j = 0; j < n; j++) {
35
+ if (this.indices[j] === i) {
36
+ return true;
37
+ }
38
+ }
39
+
40
+ return false;
41
+ }
42
+
43
+ reset() {
44
+ this.__size = 0;
45
+ }
46
+ }
47
+
48
+ const SCRATCH_CAVITY = new Cavity();
49
+
50
+ /**
51
+ *
52
+ * Layout:
53
+ * vertex_id_a :: uint
54
+ * vertex_id_b :: uint
55
+ * vertex_id_c :: uint
56
+ * vertex_id_d :: uint
57
+ * neighbour_a :: uint - neighbour tetrahedron, opposite to vertex A
58
+ * neighbour_b :: uint - neighbour tetrahedron, opposite to vertex B
59
+ * neighbour_c :: uint - neighbour tetrahedron, opposite to vertex C
60
+ * neighbour_d :: uint - neighbour tetrahedron, opposite to vertex D
61
+ * sub_determinant :: float - ?
62
+ * Layout is similar to [1], but is interleaved for better cache locality
63
+ */
64
+ export class TetrahedraCollection {
65
+ constructor(initial_size) {
66
+ this.__buffer = new ArrayBuffer(initial_size * 4 * 9);
67
+
68
+ this.__view = new DataView(this.__buffer);
69
+
70
+ this.__capacity = initial_size;
71
+ this.__length = 0;
72
+
73
+
74
+ /**
75
+ * Marks which indices are in use
76
+ * @type {BitSet}
77
+ * @private
78
+ */
79
+ this.__occupancy = new BitSet();
80
+ }
81
+
82
+ /**
83
+ *
84
+ * @param {number} tetra_index
85
+ * @param {number} neighbour_index
86
+ * @returns {number}
87
+ */
88
+ getNeighbour(tetra_index, neighbour_index) {
89
+ const tetra_address = LAYOUT_TETRA_BYTE_SIZE * tetra_index;
90
+ return this.__view.getUint32(tetra_address + (4 + neighbour_index) * 4);
91
+ }
92
+
93
+ /**
94
+ *
95
+ * @param {number[]|Float32Array} points
96
+ * @param {number} a
97
+ * @param {number} b
98
+ * @param {number} c
99
+ * @param {number} d
100
+ */
101
+ append(points, a, b, c, d) {
102
+ const tetra_index = this.__length;
103
+ const address = tetra_index * LAYOUT_TETRA_BYTE_SIZE;
104
+
105
+ // TODO check if there's enough room
106
+
107
+ const view = this.__view;
108
+
109
+ view.setUint32(address, a);
110
+ view.setUint32(address + 4, b);
111
+ view.setUint32(address + 8, c);
112
+ view.setUint32(address + 12, d);
113
+
114
+ // set neighbours
115
+ view.setUint32(address + 16, INVALID_NEIGHBOUR);
116
+ view.setUint32(address + 20, INVALID_NEIGHBOUR);
117
+ view.setUint32(address + 24, INVALID_NEIGHBOUR);
118
+ view.setUint32(address + 28, INVALID_NEIGHBOUR);
119
+
120
+ this.__occupancy.set(tetra_index, true);
121
+
122
+ this.__length++;
123
+ }
124
+
125
+ /**
126
+ * Remove tetrahedron
127
+ * @param {number} tera_index
128
+ */
129
+ remove(tera_index) {
130
+ this.__occupancy.clear(tera_index);
131
+ }
132
+
133
+ /**
134
+ * Remove tetrahedrons who's points touch the "super-tetrahedron's" points that was inserted originally
135
+ * These points are identified by an offset + count parameters
136
+ * @param {number[]|Float32Array} points
137
+ * @param {number} range_start
138
+ * @param {number} range_end
139
+ */
140
+ removeTetrasConnectedToPoints(points, range_start, range_end) {
141
+ const data_view = this.__view;
142
+
143
+ const n = this.__length;
144
+
145
+ let i = 0;
146
+ let j = 0;
147
+
148
+ for (; i < n; i++) {
149
+
150
+ const tet_address = i * LAYOUT_TETRA_BYTE_SIZE;
151
+
152
+ for (j = 0; j < 4; j++) {
153
+ const point_index = data_view.getUint32(tet_address + 4 * i);
154
+
155
+ if (point_index >= range_start && point_index <= range_end) {
156
+ // point index is in range, tetra should be removed
157
+ this.remove(i);
158
+ }
159
+ }
160
+ }
161
+ }
162
+
163
+ /**
164
+ *
165
+ * @param {number[]} points
166
+ * @param {number} index
167
+ * @returns {number} index of tetra or -1 if no containing tetra found
168
+ */
169
+ findTetraContainingPoint(points, index) {
170
+ const data_view = this.__view;
171
+
172
+ // TODO improve this
173
+ const n = this.__length;
174
+ for (let i = 0; i < n; i++) {
175
+
176
+ const tet_address = i * LAYOUT_TETRA_BYTE_SIZE;
177
+
178
+ const a = data_view.getUint32(tet_address);
179
+ const b = data_view.getUint32(tet_address + 4);
180
+ const c = data_view.getUint32(tet_address + 8);
181
+ const d = data_view.getUint32(tet_address + 12);
182
+
183
+ if (tetrahedron_contains_point(points, a, b, c, d, index)) {
184
+ return i;
185
+ }
186
+ }
187
+
188
+ return -1;
189
+ }
190
+
191
+ /**
192
+ *
193
+ * @param {Cavity} cavity
194
+ * @param {number[]|Float32Array} points
195
+ * @param {number} index
196
+ */
197
+ computeCavity(cavity, points, index) {
198
+
199
+ // 1.identify tetrahedron that contains this point
200
+ const containing_tetra = this.findTetraContainingPoint(points, index);
201
+
202
+ assert.isNonNegativeInteger(containing_tetra, 'containing_tetra');
203
+
204
+ cavity.reset();
205
+
206
+ /**
207
+ *
208
+ * @type {number[]}
209
+ */
210
+ const open_set = [
211
+ containing_tetra
212
+ ];
213
+
214
+ /**
215
+ *
216
+ * @type {number[]}
217
+ */
218
+ const closed_set = [];
219
+
220
+ const data_view = this.__view;
221
+
222
+ // 2. find the Delaunay "cavity", a set of tetrahedrons who's circumsphere overlarlaps the point
223
+ // perform breadth-first expansion on the containing tetra to identify the cavity
224
+ while (open_set.length > 0) {
225
+ const tetra = open_set.pop();
226
+ cavity.push(tetra);
227
+ closed_set.push(tetra);
228
+
229
+ // get neighbours
230
+ for (let i = 0; i < 4; i++) {
231
+ const neighbour = this.getNeighbour(tetra, i);
232
+
233
+ if (
234
+ (neighbour === INVALID_NEIGHBOUR) // no neighbour
235
+ || closed_set.includes(neighbour) // already visited
236
+ || open_set.includes(neighbour) // already in open set
237
+ ) {
238
+
239
+ continue;
240
+ }
241
+
242
+ const neighbour_address = neighbour * LAYOUT_TETRA_BYTE_SIZE;
243
+
244
+ const a = data_view.getUint32(neighbour_address);
245
+ const b = data_view.getUint32(neighbour_address + 4);
246
+ const c = data_view.getUint32(neighbour_address + 8);
247
+ const d = data_view.getUint32(neighbour_address + 12);
248
+
249
+ // check neighbour
250
+ const is_in_sphere = point_in_tetrahedron_circumsphere(points, a, b, c, d, index);
251
+
252
+ if (is_in_sphere) {
253
+ open_set.push(neighbour);
254
+ } else {
255
+ // move directly to closed set
256
+ closed_set.push(neighbour);
257
+ }
258
+
259
+
260
+ }
261
+ }
262
+ }
263
+
264
+ /**
265
+ *
266
+ * @param {number[]|Float32Array} points
267
+ * @param {number} index
268
+ */
269
+ insertPoint(points, index) {
270
+ // Compute the cavity, that is the set of tetrahedra that need to be removed and rebuilt
271
+ this.computeCavity(SCRATCH_CAVITY, points, index);
272
+
273
+ // identify cavity "edge" - the set of tetras that are neighbours of the tetras that form the cavity
274
+
275
+ // 3. remove the cavity tetrahedrons
276
+
277
+ // 4. fill the cavity by creating new tetrahedrons connecting the point to the faces of cavity boundary
278
+ }
279
+ }
@@ -100,20 +100,20 @@ export class ActionProcessor {
100
100
  */
101
101
  clear() {
102
102
  // drop all of the history
103
- this.dropHistory(0);
103
+ this.dropHistory(Infinity);
104
104
  }
105
105
 
106
106
  /**
107
- * Drop records beyond a given limit. records are dropped in batches between marks.
107
+ * Drop number of records from the history
108
108
  *
109
109
  * NOTE valid use-cases for this method from the outside are: 1) memory management and 1) removing access to a set of previous actions
110
110
  * NOTE this method is used internally by {@link #mark} method
111
111
  *
112
112
  * @example if there are 2 marks A at record 9 and B at record 11, and requested limit is 10 - 9 records will be kept as records 10 and 11 belong to the same batch and will be removed together.
113
- * @param {number} limit maximum number of records to keep
113
+ * @param {number} drop_count maximum number of records to drop
114
114
  */
115
- dropHistory(limit) {
116
- const recordsToDrop = Math.min(limit, this.history.length);
115
+ dropHistory(drop_count) {
116
+ const recordsToDrop = Math.min(drop_count, this.history.length);
117
117
  if (recordsToDrop <= 0) {
118
118
  return;
119
119
  }
@@ -144,6 +144,9 @@ export class ActionProcessor {
144
144
 
145
145
  // dispatch signal
146
146
  dropped_marks.forEach(this.onMarkRemoved.send1, this.onMarkRemoved);
147
+
148
+ // update history
149
+
147
150
  }
148
151
 
149
152
  /**
@@ -456,7 +456,7 @@ function init() {
456
456
 
457
457
  // sample_gltf_sponza();
458
458
  // sample_gltf_rts_factory();
459
- sample_lucy();
459
+ // sample_lucy();
460
460
  // sample_gltf_hapro_2();
461
461
  // sample_gltf_hapro_1();
462
462
  // sample_gltf_broken_isiflow();
@@ -465,6 +465,9 @@ function init() {
465
465
  // gltf_sample('data/models/moicon/08-clickable-assets/model.gltf');
466
466
  // gltf_sample('data/models/moicon/05-ground-floor/model.gltf');
467
467
  // gltf_sample('data/models/moicon/isiflow_Oct_15_21/0/model.gltf');
468
+ // gltf_sample('moicon/29_Dec_2021_Nammo/1/model.gltf');
469
+ // gltf_sample('moicon/29_Dec_2021_Nammo/1-onematerial/model.gltf');
470
+ gltf_sample('moicon/29_Dec_2021_Nammo/2/model.gltf');
468
471
 
469
472
  document.addEventListener("mousemove", onDocumentMouseMove);
470
473
 
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "productName": "Meep",
6
6
  "description": "production-ready JavaScript game engine based on Entity Component System Architecture",
7
7
  "author": "Alexander Goldring",
8
- "version": "2.33.37",
8
+ "version": "2.33.38",
9
9
  "dependencies": {
10
10
  "gl-matrix": "3.4.3",
11
11
  "fast-levenshtein": "2.0.6",