@xeokit/xeokit-sdk 2.4.1 → 2.4.2-beta-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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xeokit/xeokit-sdk",
3
- "version": "2.4.1",
3
+ "version": "2.4.2-beta-1",
4
4
  "description": "Web Programming Toolkit for 3D/2D BIM and AEC Graphics",
5
5
  "module": "./dist/xeokit-sdk.es.js",
6
6
  "main": "./dist/xeokit-sdk.cjs.js",
@@ -0,0 +1,209 @@
1
+
2
+ import {LODManager} from "./LODManager.js";
3
+ import {Plugin} from "../../viewer";
4
+
5
+ /**
6
+ * Manages LOD culling for {@link SceneModel} implementations.
7
+ */
8
+ export class LODCullingPlugin extends Plugin {
9
+
10
+ constructor(viewer, cfg = {}) {
11
+
12
+ super("LODCulling", viewer);
13
+
14
+ this._scene = viewer.scene;
15
+ this._lodLevels = [2000, 600, 150, 80, 20];
16
+ this._neverCullTypes = [];
17
+ this._neverCullTypesMap = {};
18
+ this._lodManagers = {};
19
+ this._lodManagerList = [];
20
+
21
+ this.enabled = cfg.enabled;
22
+ this.targetFPS = cfg.targetFPS;
23
+
24
+ this._init();
25
+ }
26
+
27
+ _init() {
28
+
29
+ const MAX_NUM_TICKS = 4;
30
+ const tickTimeArray = new Array(MAX_NUM_TICKS);
31
+
32
+ let numTick = 0;
33
+ let currentFPS = -1;
34
+ let preRenderTime = Date.now();
35
+ let deltaTime = 0;
36
+ let sceneTick = 0;
37
+ let lastTickCameraMoved = sceneTick;
38
+
39
+ this._scene.on("rendering", () => { // Apply LOD-culling before rendering the scene
40
+ if (currentFPS === -1) {
41
+ return;
42
+ }
43
+ for (let i = 0, len = this._lodManagerList.length; i < len; i++) {
44
+ this._lodManagerList[i].applyLodCulling(currentFPS);
45
+ }
46
+ });
47
+
48
+ this._scene.on("rendered", () => {
49
+ preRenderTime = Date.now();
50
+ window.requestAnimationFrame(() => {
51
+ numTick++;
52
+ const newTime = Date.now();
53
+ deltaTime = newTime - preRenderTime;
54
+ preRenderTime = newTime;
55
+ tickTimeArray[numTick % MAX_NUM_TICKS] = deltaTime;
56
+ let sumTickTimes = 0;
57
+ if (numTick > MAX_NUM_TICKS) {
58
+ for (let i = 0; i < MAX_NUM_TICKS; i++) {
59
+ sumTickTimes += tickTimeArray[i];
60
+ }
61
+ currentFPS = MAX_NUM_TICKS / sumTickTimes * 1000;
62
+ }
63
+ });
64
+ });
65
+
66
+ this._scene.camera.on("matrix", () => {
67
+ lastTickCameraMoved = sceneTick;
68
+ });
69
+
70
+ this._scene.on("tick", () => {
71
+ if ((sceneTick - lastTickCameraMoved) > 3) {
72
+ for (let i = 0, len = this._lodManagerList.length; i < len; i++) { // Call LOD-culling tasks
73
+ this._lodManagerList[i].resetLodCulling();
74
+ }
75
+ }
76
+ sceneTick++;
77
+ });
78
+
79
+ this._onModelLoaded = viewer.scene.on("modelLoaded", (modelId) => {
80
+ const sceneModel = this.viewer.scene.models[modelId];
81
+ if (sceneModel) {
82
+ this._getLODManager(sceneModel);
83
+ }
84
+ });
85
+ }
86
+
87
+ /**
88
+ * Sets whether LOD is enabled for the {@link Scene}.
89
+ *
90
+ * Default value is ````false````.
91
+ *
92
+ * @type {Boolean}
93
+ */
94
+ set enabled(value) {
95
+ value = !!value;
96
+ if (this._enabled === value) {
97
+ return;
98
+ }
99
+ this._enabled = value;
100
+ this.glRedraw();
101
+ }
102
+
103
+ /**
104
+ * Gets whether LOD is enabled for the {@link Scene}.
105
+ *
106
+ * Default value is ````false````.
107
+ *
108
+ * @type {Boolean}
109
+ */
110
+ get enabled() {
111
+ return this._enabled;
112
+ }
113
+
114
+ /**
115
+ * Sets the maximum area that LOD takes into account when checking for possible occlusion for each fragment.
116
+ *
117
+ * Default value is ````30.0````.
118
+ *
119
+ * @type {Number}
120
+ */
121
+ set targetFPS(value) {
122
+ if (value === undefined || value === null) {
123
+ value = 30.0;
124
+ }
125
+ if (this._targetFPS === value) {
126
+ return;
127
+ }
128
+ this._targetFPS = value;
129
+ this.glRedraw();
130
+ }
131
+
132
+ /**
133
+ * Gets the maximum area that LOD takes into account when checking for possible occlusion for each fragment.
134
+ *
135
+ * Default value is ````30.0````.
136
+ *
137
+ * @type {Number}
138
+ */
139
+ get targetFPS() {
140
+ return this._targetFPS;
141
+ }
142
+
143
+ /**
144
+ * Sets the {@link MetaObject} types that are never culled.
145
+ *
146
+ * Default value is ````[]````.
147
+ *
148
+ * @type {string[]}
149
+ */
150
+ set neverCullTypes(value) {
151
+ if (value === undefined || value === null) {
152
+ value = [];
153
+ }
154
+ this._neverCullTypes = value;
155
+ this._neverCullTypesMap = {};
156
+ for (let i = 0, len = this._neverCullTypes.length; i < len; i++) {
157
+ this._neverCullTypesMap[this._neverCullTypes[i]] = true;
158
+ }
159
+ // this.glRedraw();
160
+ }
161
+
162
+ /**
163
+ * Gets the {@link MetaObject} types that are never culled.
164
+ *
165
+ * Default value is ````[]````.
166
+ *
167
+ * @type {string[]}
168
+ */
169
+ get neverCullTypes() {
170
+ return this._neverCullTypes;
171
+ }
172
+
173
+ /**
174
+ * @private
175
+ * @returns {*|{}}
176
+ */
177
+ get neverCullTypesMap() {
178
+ return this._neverCullTypesMap;
179
+ }
180
+
181
+ /**
182
+ * Called within SceneModel constructors
183
+ * @private
184
+ */
185
+ _getLODManager(sceneModel) {
186
+ const lodManager = new LODManager(this.scene, sceneModel, this._lodLevels, this._targetFPS);
187
+ this._lodManagers[lodManager.id] = lodManager;
188
+ this._lodManagerList = Object.values(this._lodManagers);
189
+ return lodManager;
190
+ }
191
+
192
+ /**
193
+ * Called within SceneModel destructors
194
+ * @private
195
+ */
196
+ _putLODManager(lodManager) {
197
+ delete this._lodManagers[lodManager.id];
198
+ this._lodManagerList = Object.values(this._lodManagers);
199
+ }
200
+
201
+ /**
202
+ * Destroys this component.
203
+ *
204
+ * @private
205
+ */
206
+ destroy() {
207
+ super.destroy();
208
+ }
209
+ }
@@ -0,0 +1,82 @@
1
+ import {LODState} from "./LODState.js";
2
+
3
+ /**
4
+ * @private
5
+ */
6
+ export class LODManager {
7
+
8
+ constructor(scene, sceneModel, lodLevels, targetFps) {
9
+ this.id = sceneModel.id;
10
+ this.scene = scene;
11
+ this.sceneModel = sceneModel;
12
+ this.lodState = new LODState(lodLevels, targetFps);
13
+ this.lodState.initializeLodState(sceneModel);
14
+ }
15
+
16
+ /**
17
+ * Cull any objects belonging to the current `LOD` level, and increase the `LOD` level.
18
+ */
19
+ _increaseLODLevelIndex() {
20
+ const lodState = this.lodState;
21
+ if (lodState.lodLevelIndex === lodState.primLODLevels.length) {
22
+ return false;
23
+ }
24
+ const entitiesInLOD = lodState.entitiesInLOD [lodState.primLODLevels[lodState.lodLevelIndex]] || [];
25
+ for (let i = 0, len = entitiesInLOD.length; i < len; i++) {
26
+ entitiesInLOD[i].culledLOD = true;
27
+ }
28
+ lodState.lodLevelIndex++;
29
+ return true;
30
+ }
31
+
32
+ /**
33
+ * Un-cull any objects belonging to the current `LOD` level, and decrease the `LOD` level.
34
+ */
35
+ _decreaseLODLevelIndex() {
36
+ const lodState = this.lodState;
37
+ if (lodState.lodLevelIndex === 0) {
38
+ return false;
39
+ }
40
+ const entitiesInLOD = lodState.entitiesInLOD [lodState.primLODLevels[lodState.lodLevelIndex - 1]] || [];
41
+ for (let i = 0, len = entitiesInLOD.length; i < len; i++) {
42
+ entitiesInLOD[i].culledLOD = false;
43
+ }
44
+ lodState.lodLevelIndex--;
45
+ return true;
46
+ }
47
+
48
+ /**
49
+ * Apply LOD culling.
50
+ *
51
+ * Will update LOD level, if needed, based on current FPS and target FPS,
52
+ * and then will cull/uncull the needed objects according to the LOD level.
53
+ *
54
+ * @param {number} currentFPS The current FPS (frames per second)
55
+ * @returns {boolean} Whether the LOD level was changed. This is, if some object was culled/unculled.
56
+ */
57
+ applyLodCulling(currentFPS) {
58
+ let lodState = this.lodState;
59
+ let retVal = false;
60
+ if (currentFPS < lodState.targetFps) {
61
+ if (++lodState.consecutiveFramesWithoutTargetFps > 2) {
62
+ lodState.consecutiveFramesWithoutTargetFps = 0;
63
+ retVal = this._increaseLODLevelIndex();
64
+ }
65
+ } else if (currentFPS > (lodState.targetFps + 4)) {
66
+ if (++lodState.consecutiveFramesWithTargetFps > 2) {
67
+ lodState.consecutiveFramesWithTargetFps = 0;
68
+ retVal = this._decreaseLODLevelIndex();
69
+ }
70
+ }
71
+ return retVal;
72
+ }
73
+
74
+ resetLodCulling() {
75
+ let retVal = false;
76
+ let decreasedLevel = false;
77
+ do {
78
+ retVal |= (decreasedLevel = this._decreaseLODLevelIndex());
79
+ } while (decreasedLevel);
80
+ return retVal;
81
+ }
82
+ }
@@ -0,0 +1,130 @@
1
+ import {math} from "../math/math.js";
2
+
3
+ /**
4
+ * Data structure containing pre-initialized `LOD` data.
5
+ *
6
+ * Will be used by the rest of `LOD` related code.
7
+ *
8
+ * @private
9
+ */
10
+
11
+ export class LODState {
12
+
13
+ /**
14
+ * @param {Array<number>} primLODLevels The primtive counts for the LOD levels, for example ```[ 2000, 600, 150, 80, 20 ]```
15
+ * @param {number} targetFps The target FPS (_Frames Per Second_) for the dynamic culling of objects in the different LOD levels.
16
+ */
17
+ constructor(primLODLevels, targetFps) {
18
+
19
+ /**
20
+ * An array ordered DESC with the number of primtives allowed in each LOD bucket.
21
+ *
22
+ * @type {Array<number>}
23
+ */
24
+ this.primLODLevels = primLODLevels;
25
+
26
+ /**
27
+ * A computed dictionary for `primtive-number-buckets` where:
28
+ * - key: the number of primtives allowed for the objects in the bucket.
29
+ * - value: all PerformanceNodes that have the number of primtives or more.
30
+ *
31
+ * @type {Map<number, Array<DataTextureSceneModelNode>>}
32
+ */
33
+ this.entitiesInLOD = {};
34
+
35
+ /**
36
+ * A computed dictionary for `primtive-number-buckets` where:
37
+ * - key: the number of primtives allowed for the objects in the bucket.
38
+ * - value: the sum of primtives counts for all PeformanceNodes in the bucket.
39
+ *
40
+ * @type {Map<number, number>}
41
+ */
42
+ this.primCountInLOD = {};
43
+
44
+ /**
45
+ * The target FPS for the `LOD` mechanism:
46
+ * - if real FPS are below this number, the next `LOD` level will be applied.
47
+ *
48
+ * - if real FPS are...
49
+ * - above this number plus a margin
50
+ * - and for some consecutive frames
51
+ * ... then the previous `LOD` level will be applied.
52
+ *
53
+ * @type {number}
54
+ */
55
+ this.targetFps = targetFps;
56
+
57
+ // /**
58
+ // * Not used at the moment.
59
+ // */
60
+ // this.restoreTime = LOD_RESTORE_TIME;
61
+
62
+ /**
63
+ * Current `LOD` level. Starts at 0.
64
+ *
65
+ * @type {number}
66
+ */
67
+ this.lodLevelIndex = 0;
68
+
69
+ /**
70
+ * Number of consecutive frames in current `LOD` level where FPS was above `targetFps`
71
+ *
72
+ * @type {number}
73
+ */
74
+ this.consecutiveFramesWithTargetFps = 0;
75
+
76
+ /**
77
+ * Number of consecutive frames in current `LOD` level where FPS was below `targetFps`
78
+ *
79
+ * @type {number}
80
+ */
81
+ this.consecutiveFramesWithoutTargetFps = 0;
82
+ }
83
+
84
+ /**
85
+ * @param {SceneModel} sceneModel
86
+ */
87
+ initializeLodState(sceneModel) {
88
+ const entityList = Object.values(sceneModel.objects);
89
+ if (entityList.length === 0) {
90
+ return;
91
+ }
92
+ const neverCullTypesMap = sceneModel.scene.lod.neverCullTypesMap;
93
+ const metaScene = sceneModel.scene.viewer.metaScene;
94
+ const entitiesInLOD = {};
95
+ const primCountInLOD = {};
96
+ const maxSize = 20;
97
+ const minComplexity = 25;
98
+
99
+ for (let i = 0, len = entityList.length; i < len; i++) {
100
+ const entity = entityList[i];
101
+ const metaObject = metaScene.metaObjects[entity.id];
102
+ if (metaObject && neverCullTypesMap[metaObject.type]) {
103
+ continue;
104
+ }
105
+ const entityComplexity = entity.numPrimitives;
106
+ const entitySize = math.getAABB3Diag(entity.aabb);
107
+ // const isCullable = ((minComplexity <= entityComplexity) && (entitySize <= maxSize));
108
+ // if (!isCullable) {
109
+ // continue;
110
+ // }
111
+ let lodLevel = 0, len;
112
+ for (lodLevel = 0, len = this.primLODLevels.length; lodLevel < len; lodLevel++) {
113
+ if (entity.numPrimitives >= this.primLODLevels [lodLevel]) {
114
+ break;
115
+ }
116
+ }
117
+ const lodPrims = this.primLODLevels [lodLevel] || 0;
118
+ if (!(lodPrims in entitiesInLOD)) {
119
+ entitiesInLOD [lodPrims] = [];
120
+ }
121
+ entitiesInLOD [lodPrims].push(entity);
122
+ if (!(lodPrims in primCountInLOD)) {
123
+ primCountInLOD [lodPrims] = 0;
124
+ }
125
+ primCountInLOD [lodPrims] += entity.numPrimitives;
126
+ }
127
+ this.entitiesInLOD = entitiesInLOD;
128
+ this.primCountInLOD = primCountInLOD;
129
+ }
130
+ }
@@ -0,0 +1 @@
1
+ export * from "./LOD.js";
@@ -199,16 +199,17 @@ export class DataTextureGenerator {
199
199
 
200
200
  /**
201
201
  * @param {WebGL2RenderingContext} gl
202
- * @param {ArrayLike<int>} indices
202
+ * @param indicesArrays
203
+ * @param lenIndices
203
204
  *
204
205
  * @returns {BindableDataTexture}
205
206
  */
206
- generateTextureFor8BitIndices(gl, indices) {
207
- if (indices.length === 0) {
207
+ generateTextureFor8BitIndices(gl, indicesArrays, lenIndices) {
208
+ if (lenIndices === 0) {
208
209
  return {texture: null, textureHeight: 0,};
209
210
  }
210
211
  const textureWidth = 4096;
211
- const textureHeight = Math.ceil(indices.length / 3 / textureWidth);
212
+ const textureHeight = Math.ceil(lenIndices / 3 / textureWidth);
212
213
  if (textureHeight === 0) {
213
214
  throw "texture height===0";
214
215
  }
@@ -216,8 +217,11 @@ export class DataTextureGenerator {
216
217
  const texArray = new Uint8Array(texArraySize);
217
218
  dataTextureRamStats.sizeDataTextureIndices += texArray.byteLength;
218
219
  dataTextureRamStats.numberOfTextures++;
219
- texArray.fill(0);
220
- texArray.set(indices, 0)
220
+ for (let i = 0, j = 0, len = indicesArrays.length; i < len; i++) {
221
+ const pc = indicesArrays[i];
222
+ texArray.set(pc, j);
223
+ j += pc.length;
224
+ }
221
225
  const texture = gl.createTexture();
222
226
  gl.bindTexture(gl.TEXTURE_2D, texture);
223
227
  gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGB8UI, textureWidth, textureHeight);
@@ -229,16 +233,17 @@ export class DataTextureGenerator {
229
233
 
230
234
  /**
231
235
  * @param {WebGL2RenderingContext} gl
232
- * @param {ArrayLike<int>} indices
236
+ * @param indicesArrays
237
+ * @param lenIndices
233
238
  *
234
239
  * @returns {BindableDataTexture}
235
240
  */
236
- generateTextureFor16BitIndices(gl, indices) {
237
- if (indices.length === 0) {
241
+ generateTextureFor16BitIndices(gl, indicesArrays, lenIndices) {
242
+ if (lenIndices === 0) {
238
243
  return {texture: null, textureHeight: 0,};
239
244
  }
240
245
  const textureWidth = 4096;
241
- const textureHeight = Math.ceil(indices.length / 3 / textureWidth);
246
+ const textureHeight = Math.ceil(lenIndices / 3 / textureWidth);
242
247
  if (textureHeight === 0) {
243
248
  throw "texture height===0";
244
249
  }
@@ -246,8 +251,11 @@ export class DataTextureGenerator {
246
251
  const texArray = new Uint16Array(texArraySize);
247
252
  dataTextureRamStats.sizeDataTextureIndices += texArray.byteLength;
248
253
  dataTextureRamStats.numberOfTextures++;
249
- texArray.fill(0);
250
- texArray.set(indices, 0)
254
+ for (let i = 0, j = 0, len = indicesArrays.length; i < len; i++) {
255
+ const pc = indicesArrays[i];
256
+ texArray.set(pc, j);
257
+ j += pc.length;
258
+ }
251
259
  const texture = gl.createTexture();
252
260
  gl.bindTexture(gl.TEXTURE_2D, texture);
253
261
  gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGB16UI, textureWidth, textureHeight);
@@ -259,16 +267,17 @@ export class DataTextureGenerator {
259
267
 
260
268
  /**
261
269
  * @param {WebGL2RenderingContext} gl
262
- * @param {ArrayLike<int>} indices
270
+ * @param indicesArrays
271
+ * @param lenIndices
263
272
  *
264
273
  * @returns {BindableDataTexture}
265
274
  */
266
- generateTextureFor32BitIndices(gl, indices) {
267
- if (indices.length === 0) {
268
- return {texture: null, textureHeight: 0};
275
+ generateTextureFor32BitIndices(gl, indicesArrays, lenIndices) {
276
+ if (lenIndices === 0) {
277
+ return {texture: null, textureHeight: 0,};
269
278
  }
270
279
  const textureWidth = 4096;
271
- const textureHeight = Math.ceil(indices.length / 3 / textureWidth);
280
+ const textureHeight = Math.ceil(lenIndices / 3 / textureWidth);
272
281
  if (textureHeight === 0) {
273
282
  throw "texture height===0";
274
283
  }
@@ -276,8 +285,11 @@ export class DataTextureGenerator {
276
285
  const texArray = new Uint32Array(texArraySize);
277
286
  dataTextureRamStats.sizeDataTextureIndices += texArray.byteLength;
278
287
  dataTextureRamStats.numberOfTextures++;
279
- texArray.fill(0);
280
- texArray.set(indices, 0)
288
+ for (let i = 0, j = 0, len = indicesArrays.length; i < len; i++) {
289
+ const pc = indicesArrays[i];
290
+ texArray.set(pc, j);
291
+ j += pc.length;
292
+ }
281
293
  const texture = gl.createTexture();
282
294
  gl.bindTexture(gl.TEXTURE_2D, texture);
283
295
  gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGB32UI, textureWidth, textureHeight);
@@ -289,16 +301,17 @@ export class DataTextureGenerator {
289
301
 
290
302
  /**
291
303
  * @param {WebGL2RenderingContext} gl
292
- * @param {ArrayLike<int>} edgeIndices
304
+ * @param indicesArrays
305
+ * @param lenIndices
293
306
  *
294
307
  * @returns {BindableDataTexture}
295
308
  */
296
- generateTextureFor8BitsEdgeIndices(gl, edgeIndices) {
297
- if (edgeIndices.length === 0) {
298
- return {texture: null, textureHeight: 0};
309
+ generateTextureFor8BitsEdgeIndices(gl, indicesArrays, lenIndices) {
310
+ if (lenIndices === 0) {
311
+ return {texture: null, textureHeight: 0,};
299
312
  }
300
313
  const textureWidth = 4096;
301
- const textureHeight = Math.ceil(edgeIndices.length / 2 / textureWidth);
314
+ const textureHeight = Math.ceil(lenIndices / 2 / textureWidth);
302
315
  if (textureHeight === 0) {
303
316
  throw "texture height===0";
304
317
  }
@@ -306,8 +319,11 @@ export class DataTextureGenerator {
306
319
  const texArray = new Uint8Array(texArraySize);
307
320
  dataTextureRamStats.sizeDataTextureEdgeIndices += texArray.byteLength;
308
321
  dataTextureRamStats.numberOfTextures++;
309
- texArray.fill(0);
310
- texArray.set(edgeIndices, 0)
322
+ for (let i = 0, j = 0, len = indicesArrays.length; i < len; i++) {
323
+ const pc = indicesArrays[i];
324
+ texArray.set(pc, j);
325
+ j += pc.length;
326
+ }
311
327
  const texture = gl.createTexture();
312
328
  gl.bindTexture(gl.TEXTURE_2D, texture);
313
329
  gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RG8UI, textureWidth, textureHeight);
@@ -319,16 +335,17 @@ export class DataTextureGenerator {
319
335
 
320
336
  /**
321
337
  * @param {WebGL2RenderingContext} gl
322
- * @param {ArrayLike<int>} edgeIndices
338
+ * @param indicesArrays
339
+ * @param lenIndices
323
340
  *
324
341
  * @returns {BindableDataTexture}
325
342
  */
326
- generateTextureFor16BitsEdgeIndices(gl, edgeIndices) {
327
- if (edgeIndices.length === 0) {
328
- return {texture: null, textureHeight: 0};
343
+ generateTextureFor16BitsEdgeIndices(gl, indicesArrays, lenIndices) {
344
+ if (lenIndices === 0) {
345
+ return {texture: null, textureHeight: 0,};
329
346
  }
330
347
  const textureWidth = 4096;
331
- const textureHeight = Math.ceil(edgeIndices.length / 2 / textureWidth);
348
+ const textureHeight = Math.ceil(lenIndices / 2 / textureWidth);
332
349
  if (textureHeight === 0) {
333
350
  throw "texture height===0";
334
351
  }
@@ -336,8 +353,11 @@ export class DataTextureGenerator {
336
353
  const texArray = new Uint16Array(texArraySize);
337
354
  dataTextureRamStats.sizeDataTextureEdgeIndices += texArray.byteLength;
338
355
  dataTextureRamStats.numberOfTextures++;
339
- texArray.fill(0);
340
- texArray.set(edgeIndices, 0)
356
+ for (let i = 0, j = 0, len = indicesArrays.length; i < len; i++) {
357
+ const pc = indicesArrays[i];
358
+ texArray.set(pc, j);
359
+ j += pc.length;
360
+ }
341
361
  const texture = gl.createTexture();
342
362
  gl.bindTexture(gl.TEXTURE_2D, texture);
343
363
  gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RG16UI, textureWidth, textureHeight);
@@ -349,16 +369,17 @@ export class DataTextureGenerator {
349
369
 
350
370
  /**
351
371
  * @param {WebGL2RenderingContext} gl
352
- * @param {ArrayLike<int>} edgeIndices
372
+ * @param indicesArrays
373
+ * @param lenIndices
353
374
  *
354
375
  * @returns {BindableDataTexture}
355
376
  */
356
- generateTextureFor32BitsEdgeIndices(gl, edgeIndices) {
357
- if (edgeIndices.length === 0) {
377
+ generateTextureFor32BitsEdgeIndices(gl, indicesArrays, lenIndices) {
378
+ if (lenIndices === 0) {
358
379
  return {texture: null, textureHeight: 0,};
359
380
  }
360
381
  const textureWidth = 4096;
361
- const textureHeight = Math.ceil(edgeIndices.length / 2 / textureWidth);
382
+ const textureHeight = Math.ceil(lenIndices / 2 / textureWidth);
362
383
  if (textureHeight === 0) {
363
384
  throw "texture height===0";
364
385
  }
@@ -366,8 +387,11 @@ export class DataTextureGenerator {
366
387
  const texArray = new Uint32Array(texArraySize);
367
388
  dataTextureRamStats.sizeDataTextureEdgeIndices += texArray.byteLength;
368
389
  dataTextureRamStats.numberOfTextures++;
369
- texArray.fill(0);
370
- texArray.set(edgeIndices, 0)
390
+ for (let i = 0, j = 0, len = indicesArrays.length; i < len; i++) {
391
+ const pc = indicesArrays[i];
392
+ texArray.set(pc, j);
393
+ j += pc.length;
394
+ }
371
395
  const texture = gl.createTexture();
372
396
  gl.bindTexture(gl.TEXTURE_2D, texture);
373
397
  gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RG32UI, textureWidth, textureHeight);
@@ -379,7 +403,8 @@ export class DataTextureGenerator {
379
403
 
380
404
  /**
381
405
  * @param {WebGL2RenderingContext} gl
382
- * @param {ArrayLike<int>} positions Array of (uniquified) quantized positions in the layer
406
+ * @param {ArrayLike<int>} positionsArrays Arrays of quantized positions in the layer
407
+ * @param lenPositions
383
408
  *
384
409
  * This will generate a texture for positions in the layer.
385
410
  *
@@ -389,8 +414,8 @@ export class DataTextureGenerator {
389
414
  *
390
415
  * @returns {BindableDataTexture}
391
416
  */
392
- generateTextureForPositions(gl, positions) {
393
- const numVertices = positions.length / 3;
417
+ generateTextureForPositions(gl, positionsArrays, lenPositions) {
418
+ const numVertices = lenPositions / 3;
394
419
  const textureWidth = 4096;
395
420
  const textureHeight = Math.ceil(numVertices / textureWidth);
396
421
  if (textureHeight === 0) {
@@ -400,8 +425,11 @@ export class DataTextureGenerator {
400
425
  const texArray = new Uint16Array(texArraySize);
401
426
  dataTextureRamStats.sizeDataTexturePositions += texArray.byteLength;
402
427
  dataTextureRamStats.numberOfTextures++;
403
- texArray.fill(0);
404
- texArray.set(positions, 0);
428
+ for (let i = 0, j = 0, len = positionsArrays.length; i < len; i++) {
429
+ const pc = positionsArrays[i];
430
+ texArray.set(pc, j);
431
+ j += pc.length;
432
+ }
405
433
  const texture = gl.createTexture();
406
434
  gl.bindTexture(gl.TEXTURE_2D, texture);
407
435
  gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGB16UI, textureWidth, textureHeight);