@damienmortini/three 0.1.171 → 0.1.173

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.
@@ -73,21 +73,12 @@ class DRACOLoader extends Loader {
73
73
 
74
74
  loader.load( url, ( buffer ) => {
75
75
 
76
- const taskConfig = {
77
- attributeIDs: this.defaultAttributeIDs,
78
- attributeTypes: this.defaultAttributeTypes,
79
- useUniqueIDs: false
80
- };
81
-
82
- this.decodeGeometry( buffer, taskConfig )
83
- .then( onLoad )
84
- .catch( onError );
76
+ this.decodeDracoFile( buffer, onLoad ).catch( onError );
85
77
 
86
78
  }, onProgress, onError );
87
79
 
88
80
  }
89
81
 
90
- /** @deprecated Kept for backward-compatibility with previous DRACOLoader versions. */
91
82
  decodeDracoFile( buffer, callback, attributeIDs, attributeTypes ) {
92
83
 
93
84
  const taskConfig = {
@@ -96,29 +87,12 @@ class DRACOLoader extends Loader {
96
87
  useUniqueIDs: !! attributeIDs
97
88
  };
98
89
 
99
- this.decodeGeometry( buffer, taskConfig ).then( callback );
90
+ return this.decodeGeometry( buffer, taskConfig ).then( callback );
100
91
 
101
92
  }
102
93
 
103
94
  decodeGeometry( buffer, taskConfig ) {
104
95
 
105
- // TODO: For backward-compatibility, support 'attributeTypes' objects containing
106
- // references (rather than names) to typed array constructors. These must be
107
- // serialized before sending them to the worker.
108
- for ( const attribute in taskConfig.attributeTypes ) {
109
-
110
- const type = taskConfig.attributeTypes[ attribute ];
111
-
112
- if ( type.BYTES_PER_ELEMENT !== undefined ) {
113
-
114
- taskConfig.attributeTypes[ attribute ] = type.name;
115
-
116
- }
117
-
118
- }
119
-
120
- //
121
-
122
96
  const taskKey = JSON.stringify( taskConfig );
123
97
 
124
98
  // Check for an existing task using this buffer. A transferred buffer cannot be transferred
@@ -12,6 +12,7 @@ import {
12
12
  FrontSide,
13
13
  Group,
14
14
  ImageBitmapLoader,
15
+ InstancedMesh,
15
16
  InterleavedBuffer,
16
17
  InterleavedBufferAttribute,
17
18
  Interpolant,
@@ -147,6 +148,12 @@ class GLTFLoader extends Loader {
147
148
 
148
149
  } );
149
150
 
151
+ this.register( function ( parser ) {
152
+
153
+ return new GLTFMeshGpuInstancing( parser );
154
+
155
+ } );
156
+
150
157
  }
151
158
 
152
159
  load( url, onLoad, onProgress, onError ) {
@@ -277,15 +284,15 @@ class GLTFLoader extends Loader {
277
284
 
278
285
  parse( data, path, onLoad, onError ) {
279
286
 
280
- let content;
287
+ let json;
281
288
  const extensions = {};
282
289
  const plugins = {};
283
290
 
284
291
  if ( typeof data === 'string' ) {
285
292
 
286
- content = data;
293
+ json = JSON.parse( data );
287
294
 
288
- } else {
295
+ } else if ( data instanceof ArrayBuffer ) {
289
296
 
290
297
  const magic = LoaderUtils.decodeText( new Uint8Array( data, 0, 4 ) );
291
298
 
@@ -302,17 +309,19 @@ class GLTFLoader extends Loader {
302
309
 
303
310
  }
304
311
 
305
- content = extensions[ EXTENSIONS.KHR_BINARY_GLTF ].content;
312
+ json = JSON.parse( extensions[ EXTENSIONS.KHR_BINARY_GLTF ].content );
306
313
 
307
314
  } else {
308
315
 
309
- content = LoaderUtils.decodeText( new Uint8Array( data ) );
316
+ json = JSON.parse( LoaderUtils.decodeText( new Uint8Array( data ) ) );
310
317
 
311
318
  }
312
319
 
313
- }
320
+ } else {
314
321
 
315
- const json = JSON.parse( content );
322
+ json = data;
323
+
324
+ }
316
325
 
317
326
  if ( json.asset === undefined || json.asset.version[ 0 ] < 2 ) {
318
327
 
@@ -468,7 +477,8 @@ const EXTENSIONS = {
468
477
  KHR_MESH_QUANTIZATION: 'KHR_mesh_quantization',
469
478
  KHR_MATERIALS_EMISSIVE_STRENGTH: 'KHR_materials_emissive_strength',
470
479
  EXT_TEXTURE_WEBP: 'EXT_texture_webp',
471
- EXT_MESHOPT_COMPRESSION: 'EXT_meshopt_compression'
480
+ EXT_MESHOPT_COMPRESSION: 'EXT_meshopt_compression',
481
+ EXT_MESH_GPU_INSTANCING: 'EXT_mesh_gpu_instancing'
472
482
  };
473
483
 
474
484
  /**
@@ -1044,7 +1054,7 @@ class GLTFMaterialsVolumeExtension {
1044
1054
 
1045
1055
  }
1046
1056
 
1047
- materialParams.attenuationDistance = extension.attenuationDistance || 0;
1057
+ materialParams.attenuationDistance = extension.attenuationDistance || Infinity;
1048
1058
 
1049
1059
  const colorArray = extension.attenuationColor || [ 1, 1, 1 ];
1050
1060
  materialParams.attenuationColor = new Color( colorArray[ 0 ], colorArray[ 1 ], colorArray[ 2 ] );
@@ -1341,7 +1351,7 @@ class GLTFMeshoptCompression {
1341
1351
 
1342
1352
  }
1343
1353
 
1344
- return Promise.all( [ buffer, decoder.ready ] ).then( function ( res ) {
1354
+ return buffer.then( function ( res ) {
1345
1355
 
1346
1356
  const byteOffset = extensionDef.byteOffset || 0;
1347
1357
  const byteLength = extensionDef.byteLength || 0;
@@ -1349,11 +1359,28 @@ class GLTFMeshoptCompression {
1349
1359
  const count = extensionDef.count;
1350
1360
  const stride = extensionDef.byteStride;
1351
1361
 
1352
- const result = new ArrayBuffer( count * stride );
1353
- const source = new Uint8Array( res[ 0 ], byteOffset, byteLength );
1362
+ const source = new Uint8Array( res, byteOffset, byteLength );
1363
+
1364
+ if ( decoder.decodeGltfBufferAsync ) {
1365
+
1366
+ return decoder.decodeGltfBufferAsync( count, stride, source, extensionDef.mode, extensionDef.filter ).then( function ( res ) {
1354
1367
 
1355
- decoder.decodeGltfBuffer( new Uint8Array( result ), count, stride, source, extensionDef.mode, extensionDef.filter );
1356
- return result;
1368
+ return res.buffer;
1369
+
1370
+ } );
1371
+
1372
+ } else {
1373
+
1374
+ // Support for MeshoptDecoder 0.18 or earlier, without decodeGltfBufferAsync
1375
+ return decoder.ready.then( function () {
1376
+
1377
+ const result = new ArrayBuffer( count * stride );
1378
+ decoder.decodeGltfBuffer( new Uint8Array( result ), count, stride, source, extensionDef.mode, extensionDef.filter );
1379
+ return result;
1380
+
1381
+ } );
1382
+
1383
+ }
1357
1384
 
1358
1385
  } );
1359
1386
 
@@ -1367,6 +1394,160 @@ class GLTFMeshoptCompression {
1367
1394
 
1368
1395
  }
1369
1396
 
1397
+ /**
1398
+ * GPU Instancing Extension
1399
+ *
1400
+ * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/EXT_mesh_gpu_instancing
1401
+ *
1402
+ */
1403
+ class GLTFMeshGpuInstancing {
1404
+
1405
+ constructor( parser ) {
1406
+
1407
+ this.name = EXTENSIONS.EXT_MESH_GPU_INSTANCING;
1408
+ this.parser = parser;
1409
+
1410
+ }
1411
+
1412
+ createNodeMesh( nodeIndex ) {
1413
+
1414
+ const json = this.parser.json;
1415
+ const nodeDef = json.nodes[ nodeIndex ];
1416
+
1417
+ if ( ! nodeDef.extensions || ! nodeDef.extensions[ this.name ] ||
1418
+ nodeDef.mesh === undefined ) {
1419
+
1420
+ return null;
1421
+
1422
+ }
1423
+
1424
+ const meshDef = json.meshes[ nodeDef.mesh ];
1425
+
1426
+ // No Points or Lines + Instancing support yet
1427
+
1428
+ for ( const primitive of meshDef.primitives ) {
1429
+
1430
+ if ( primitive.mode !== WEBGL_CONSTANTS.TRIANGLES &&
1431
+ primitive.mode !== WEBGL_CONSTANTS.TRIANGLE_STRIP &&
1432
+ primitive.mode !== WEBGL_CONSTANTS.TRIANGLE_FAN &&
1433
+ primitive.mode !== undefined ) {
1434
+
1435
+ return null;
1436
+
1437
+ }
1438
+
1439
+ }
1440
+
1441
+ const extensionDef = nodeDef.extensions[ this.name ];
1442
+ const attributesDef = extensionDef.attributes;
1443
+
1444
+ // @TODO: Can we support InstancedMesh + SkinnedMesh?
1445
+
1446
+ const pending = [];
1447
+ const attributes = {};
1448
+
1449
+ for ( const key in attributesDef ) {
1450
+
1451
+ pending.push( this.parser.getDependency( 'accessor', attributesDef[ key ] ).then( accessor => {
1452
+
1453
+ attributes[ key ] = accessor;
1454
+ return attributes[ key ];
1455
+
1456
+ } ) );
1457
+
1458
+ }
1459
+
1460
+ if ( pending.length < 1 ) {
1461
+
1462
+ return null;
1463
+
1464
+ }
1465
+
1466
+ pending.push( this.parser.createNodeMesh( nodeIndex ) );
1467
+
1468
+ return Promise.all( pending ).then( results => {
1469
+
1470
+ const nodeObject = results.pop();
1471
+ const meshes = nodeObject.isGroup ? nodeObject.children : [ nodeObject ];
1472
+ const count = results[ 0 ].count; // All attribute counts should be same
1473
+ const instancedMeshes = [];
1474
+
1475
+ for ( const mesh of meshes ) {
1476
+
1477
+ // Temporal variables
1478
+ const m = new Matrix4();
1479
+ const p = new Vector3();
1480
+ const q = new Quaternion();
1481
+ const s = new Vector3( 1, 1, 1 );
1482
+
1483
+ const instancedMesh = new InstancedMesh( mesh.geometry, mesh.material, count );
1484
+
1485
+ for ( let i = 0; i < count; i ++ ) {
1486
+
1487
+ if ( attributes.TRANSLATION ) {
1488
+
1489
+ p.fromBufferAttribute( attributes.TRANSLATION, i );
1490
+
1491
+ }
1492
+
1493
+ if ( attributes.ROTATION ) {
1494
+
1495
+ q.fromBufferAttribute( attributes.ROTATION, i );
1496
+
1497
+ }
1498
+
1499
+ if ( attributes.SCALE ) {
1500
+
1501
+ s.fromBufferAttribute( attributes.SCALE, i );
1502
+
1503
+ }
1504
+
1505
+ instancedMesh.setMatrixAt( i, m.compose( p, q, s ) );
1506
+
1507
+ }
1508
+
1509
+ // Add instance attributes to the geometry, excluding TRS.
1510
+ for ( const attributeName in attributes ) {
1511
+
1512
+ if ( attributeName !== 'TRANSLATION' &&
1513
+ attributeName !== 'ROTATION' &&
1514
+ attributeName !== 'SCALE' ) {
1515
+
1516
+ mesh.geometry.setAttribute( attributeName, attributes[ attributeName ] );
1517
+
1518
+ }
1519
+
1520
+ }
1521
+
1522
+ // Just in case
1523
+ Object3D.prototype.copy.call( instancedMesh, mesh );
1524
+
1525
+ // https://github.com/mrdoob/three.js/issues/18334
1526
+ instancedMesh.frustumCulled = false;
1527
+ this.parser.assignFinalMaterial( instancedMesh );
1528
+
1529
+ instancedMeshes.push( instancedMesh );
1530
+
1531
+ }
1532
+
1533
+ if ( nodeObject.isGroup ) {
1534
+
1535
+ nodeObject.clear();
1536
+
1537
+ nodeObject.add( ... instancedMeshes );
1538
+
1539
+ return nodeObject;
1540
+
1541
+ }
1542
+
1543
+ return instancedMeshes[ 0 ];
1544
+
1545
+ } );
1546
+
1547
+ }
1548
+
1549
+ }
1550
+
1370
1551
  /* BINARY EXTENSION */
1371
1552
  const BINARY_EXTENSION_HEADER_MAGIC = 'glTF';
1372
1553
  const BINARY_EXTENSION_HEADER_LENGTH = 12;
@@ -1487,7 +1668,7 @@ class GLTFDracoMeshCompressionExtension {
1487
1668
  const accessorDef = json.accessors[ primitive.attributes[ attributeName ] ];
1488
1669
  const componentType = WEBGL_COMPONENT_TYPES[ accessorDef.componentType ];
1489
1670
 
1490
- attributeTypeMap[ threeAttributeName ] = componentType;
1671
+ attributeTypeMap[ threeAttributeName ] = componentType.name;
1491
1672
  attributeNormalizedMap[ threeAttributeName ] = accessorDef.normalized === true;
1492
1673
 
1493
1674
  }
@@ -3009,7 +3190,7 @@ class GLTFParser {
3009
3190
 
3010
3191
  texture.flipY = false;
3011
3192
 
3012
- if ( textureDef.name ) texture.name = textureDef.name;
3193
+ texture.name = textureDef.name || sourceDef.name || '';
3013
3194
 
3014
3195
  const samplers = json.samplers || {};
3015
3196
  const sampler = samplers[ textureDef.sampler ] || {};
@@ -3776,7 +3957,7 @@ class GLTFParser {
3776
3957
  const channel = animationDef.channels[ i ];
3777
3958
  const sampler = animationDef.samplers[ channel.sampler ];
3778
3959
  const target = channel.target;
3779
- const name = target.node !== undefined ? target.node : target.id; // NOTE: target.id is deprecated.
3960
+ const name = target.node;
3780
3961
  const input = animationDef.parameters !== undefined ? animationDef.parameters[ sampler.input ] : sampler.input;
3781
3962
  const output = animationDef.parameters !== undefined ? animationDef.parameters[ sampler.output ] : sampler.output;
3782
3963
 
@@ -13,6 +13,7 @@
13
13
 
14
14
  import {
15
15
  CompressedTexture,
16
+ CompressedArrayTexture,
16
17
  Data3DTexture,
17
18
  DataTexture,
18
19
  FileLoader,
@@ -35,15 +36,15 @@ import {
35
36
  RGBAFormat,
36
37
  RGFormat,
37
38
  sRGBEncoding,
38
- UnsignedByteType
39
+ UnsignedByteType,
39
40
  } from '../../../../three/src/Three.js';
40
41
  import { WorkerPool } from '../utils/WorkerPool.js';
41
- import * as KTX from '../libs/ktx-parse.module.js';
42
-
43
- const {
42
+ import {
44
43
  read,
45
44
  KHR_DF_FLAG_ALPHA_PREMULTIPLIED,
46
45
  KHR_DF_TRANSFER_SRGB,
46
+ KHR_SUPERCOMPRESSION_NONE,
47
+ KHR_SUPERCOMPRESSION_ZSTD,
47
48
  VK_FORMAT_UNDEFINED,
48
49
  VK_FORMAT_R16_SFLOAT,
49
50
  VK_FORMAT_R16G16_SFLOAT,
@@ -57,12 +58,15 @@ const {
57
58
  VK_FORMAT_R8G8_UNORM,
58
59
  VK_FORMAT_R8G8B8A8_SRGB,
59
60
  VK_FORMAT_R8G8B8A8_UNORM,
60
- } = KTX; // eslint-disable-line no-undef
61
+ } from '../libs/ktx-parse.module.js';
62
+ import { ZSTDDecoder } from '../libs/zstddec.module.js';
61
63
 
62
64
  const _taskCache = new WeakMap();
63
65
 
64
66
  let _activeLoaders = 0;
65
67
 
68
+ let _zstd;
69
+
66
70
  class KTX2Loader extends Loader {
67
71
 
68
72
  constructor( manager ) {
@@ -233,16 +237,21 @@ class KTX2Loader extends Loader {
233
237
 
234
238
  }
235
239
 
236
- _createTextureFrom( transcodeResult ) {
240
+ _createTextureFrom( transcodeResult, container ) {
237
241
 
238
242
  const { mipmaps, width, height, format, type, error, dfdTransferFn, dfdFlags } = transcodeResult;
239
243
 
240
244
  if ( type === 'error' ) return Promise.reject( error );
241
245
 
242
- const texture = new CompressedTexture( mipmaps, width, height, format, UnsignedByteType );
246
+ const texture = container.layerCount > 1
247
+ ? new CompressedArrayTexture( mipmaps, width, height, container.layerCount, format, UnsignedByteType )
248
+ : new CompressedTexture( mipmaps, width, height, format, UnsignedByteType );
249
+
250
+
243
251
  texture.minFilter = mipmaps.length === 1 ? LinearFilter : LinearMipmapLinearFilter;
244
252
  texture.magFilter = LinearFilter;
245
253
  texture.generateMipmaps = false;
254
+
246
255
  texture.needsUpdate = true;
247
256
  texture.encoding = dfdTransferFn === KHR_DF_TRANSFER_SRGB ? sRGBEncoding : LinearEncoding;
248
257
  texture.premultiplyAlpha = !! ( dfdFlags & KHR_DF_FLAG_ALPHA_PREMULTIPLIED );
@@ -254,9 +263,9 @@ class KTX2Loader extends Loader {
254
263
  /**
255
264
  * @param {ArrayBuffer} buffer
256
265
  * @param {object?} config
257
- * @return {Promise<CompressedTexture|DataTexture|Data3DTexture>}
266
+ * @return {Promise<CompressedTexture|CompressedArrayTexture|DataTexture|Data3DTexture>}
258
267
  */
259
- _createTexture( buffer, config = {} ) {
268
+ async _createTexture( buffer, config = {} ) {
260
269
 
261
270
  const container = read( new Uint8Array( buffer ) );
262
271
 
@@ -267,13 +276,12 @@ class KTX2Loader extends Loader {
267
276
  }
268
277
 
269
278
  //
270
-
271
279
  const taskConfig = config;
272
280
  const texturePending = this.init().then( () => {
273
281
 
274
282
  return this.workerPool.postMessage( { type: 'transcode', buffer, taskConfig: taskConfig }, [ buffer ] );
275
283
 
276
- } ).then( ( e ) => this._createTextureFrom( e.data ) );
284
+ } ).then( ( e ) => this._createTextureFrom( e.data, container ) );
277
285
 
278
286
  // Cache the task result.
279
287
  _taskCache.set( buffer, { promise: texturePending } );
@@ -434,6 +442,7 @@ KTX2Loader.BasisWorker = function () {
434
442
  const basisFormat = ktx2File.isUASTC() ? BasisFormat.UASTC_4x4 : BasisFormat.ETC1S;
435
443
  const width = ktx2File.getWidth();
436
444
  const height = ktx2File.getHeight();
445
+ const layers = ktx2File.getLayers() || 1;
437
446
  const levels = ktx2File.getLevels();
438
447
  const hasAlpha = ktx2File.getHasAlpha();
439
448
  const dfdTransferFn = ktx2File.getDFDTransferFunc();
@@ -459,30 +468,39 @@ KTX2Loader.BasisWorker = function () {
459
468
 
460
469
  for ( let mip = 0; mip < levels; mip ++ ) {
461
470
 
462
- const levelInfo = ktx2File.getImageLevelInfo( mip, 0, 0 );
463
- const mipWidth = levelInfo.origWidth;
464
- const mipHeight = levelInfo.origHeight;
465
- const dst = new Uint8Array( ktx2File.getImageTranscodedSizeInBytes( mip, 0, 0, transcoderFormat ) );
466
-
467
- const status = ktx2File.transcodeImage(
468
- dst,
469
- mip,
470
- 0,
471
- 0,
472
- transcoderFormat,
473
- 0,
474
- - 1,
475
- - 1,
476
- );
471
+ const layerMips = [];
472
+
473
+ let mipWidth, mipHeight;
474
+
475
+ for ( let layer = 0; layer < layers; layer ++ ) {
476
+
477
+ const levelInfo = ktx2File.getImageLevelInfo( mip, layer, 0 );
478
+ mipWidth = levelInfo.origWidth;
479
+ mipHeight = levelInfo.origHeight;
480
+ const dst = new Uint8Array( ktx2File.getImageTranscodedSizeInBytes( mip, layer, 0, transcoderFormat ) );
481
+ const status = ktx2File.transcodeImage(
482
+ dst,
483
+ mip,
484
+ layer,
485
+ 0,
486
+ transcoderFormat,
487
+ 0,
488
+ - 1,
489
+ - 1,
490
+ );
491
+
492
+ if ( ! status ) {
493
+
494
+ cleanup();
495
+ throw new Error( 'THREE.KTX2Loader: .transcodeImage failed.' );
477
496
 
478
- if ( ! status ) {
497
+ }
479
498
 
480
- cleanup();
481
- throw new Error( 'THREE.KTX2Loader: .transcodeImage failed.' );
499
+ layerMips.push( dst );
482
500
 
483
501
  }
484
502
 
485
- mipmaps.push( { data: dst, width: mipWidth, height: mipHeight } );
503
+ mipmaps.push( { data: concat( layerMips ), width: mipWidth, height: mipHeight } );
486
504
 
487
505
  }
488
506
 
@@ -609,6 +627,33 @@ KTX2Loader.BasisWorker = function () {
609
627
 
610
628
  }
611
629
 
630
+ /** Concatenates N byte arrays. */
631
+ function concat( arrays ) {
632
+
633
+ let totalByteLength = 0;
634
+
635
+ for ( const array of arrays ) {
636
+
637
+ totalByteLength += array.byteLength;
638
+
639
+ }
640
+
641
+ const result = new Uint8Array( totalByteLength );
642
+
643
+ let byteOffset = 0;
644
+
645
+ for ( const array of arrays ) {
646
+
647
+ result.set( array, byteOffset );
648
+
649
+ byteOffset += array.byteLength;
650
+
651
+ }
652
+
653
+ return result;
654
+
655
+ }
656
+
612
657
  };
613
658
 
614
659
  //
@@ -660,7 +705,7 @@ const ENCODING_MAP = {
660
705
 
661
706
  };
662
707
 
663
- function createDataTexture( container ) {
708
+ async function createDataTexture( container ) {
664
709
 
665
710
  const { vkFormat, pixelWidth, pixelHeight, pixelDepth } = container;
666
711
 
@@ -670,11 +715,36 @@ function createDataTexture( container ) {
670
715
 
671
716
  }
672
717
 
673
- //
718
+ const level = container.levels[ 0 ];
674
719
 
720
+ let levelData;
675
721
  let view;
676
722
 
677
- const levelData = container.levels[ 0 ].levelData;
723
+ if ( container.supercompressionScheme === KHR_SUPERCOMPRESSION_NONE ) {
724
+
725
+ levelData = level.levelData;
726
+
727
+ } else if ( container.supercompressionScheme === KHR_SUPERCOMPRESSION_ZSTD ) {
728
+
729
+ if ( ! _zstd ) {
730
+
731
+ _zstd = new Promise( async ( resolve ) => {
732
+
733
+ const zstd = new ZSTDDecoder();
734
+ await zstd.init();
735
+ resolve( zstd );
736
+
737
+ } );
738
+
739
+ }
740
+
741
+ levelData = ( await _zstd ).decode( level.levelData, level.uncompressedByteLength );
742
+
743
+ } else {
744
+
745
+ throw new Error( 'THREE.KTX2Loader: Unsupported supercompressionScheme.' );
746
+
747
+ }
678
748
 
679
749
  if ( TYPE_MAP[ vkFormat ] === FloatType ) {
680
750
 
@@ -701,7 +771,6 @@ function createDataTexture( container ) {
701
771
  view = levelData;
702
772
 
703
773
  }
704
-
705
774
  //
706
775
 
707
776
  const texture = pixelDepth === 0
@@ -5,7 +5,6 @@ import {
5
5
  InstancedBufferAttribute,
6
6
  InterleavedBuffer,
7
7
  InterleavedBufferAttribute,
8
- MathUtils,
9
8
  TriangleFanDrawMode,
10
9
  TriangleStripDrawMode,
11
10
  TrianglesDrawMode,
@@ -36,17 +35,16 @@ function computeMikkTSpaceTangents( geometry, MikkTSpace, negateSign = true ) {
36
35
 
37
36
  if ( attribute.normalized || attribute.isInterleavedBufferAttribute ) {
38
37
 
39
- const srcArray = attribute.isInterleavedBufferAttribute ? attribute.data.array : attribute.array;
40
38
  const dstArray = new Float32Array( attribute.getCount() * attribute.itemSize );
41
39
 
42
40
  for ( let i = 0, j = 0; i < attribute.getCount(); i ++ ) {
43
41
 
44
- dstArray[ j ++ ] = MathUtils.denormalize( attribute.getX( i ), srcArray );
45
- dstArray[ j ++ ] = MathUtils.denormalize( attribute.getY( i ), srcArray );
42
+ dstArray[ j ++ ] = attribute.getX( i );
43
+ dstArray[ j ++ ] = attribute.getY( i );
46
44
 
47
45
  if ( attribute.itemSize > 2 ) {
48
46
 
49
- dstArray[ j ++ ] = MathUtils.denormalize( attribute.getZ( i ), srcArray );
47
+ dstArray[ j ++ ] = attribute.getZ( i );
50
48
 
51
49
  }
52
50
 
@@ -194,11 +192,6 @@ function mergeBufferGeometries( geometries, useGroups = false ) {
194
192
 
195
193
  }
196
194
 
197
- // gather .userData
198
-
199
- mergedGeometry.userData.mergedUserData = mergedGeometry.userData.mergedUserData || [];
200
- mergedGeometry.userData.mergedUserData.push( geometry.userData );
201
-
202
195
  if ( useGroups ) {
203
196
 
204
197
  let count;
@@ -373,6 +366,28 @@ function mergeBufferAttributes( attributes ) {
373
366
 
374
367
  }
375
368
 
369
+ /**
370
+ * @param {BufferAttribute}
371
+ * @return {BufferAttribute}
372
+ */
373
+ export function deepCloneAttribute( attribute ) {
374
+
375
+ if ( attribute.isInstancedInterleavedBufferAttribute || attribute.isInterleavedBufferAttribute ) {
376
+
377
+ return deinterleaveAttribute( attribute );
378
+
379
+ }
380
+
381
+ if ( attribute.isInstancedBufferAttribute ) {
382
+
383
+ return new InstancedBufferAttribute().copy( attribute );
384
+
385
+ }
386
+
387
+ return new BufferAttribute().copy( attribute );
388
+
389
+ }
390
+
376
391
  /**
377
392
  * @param {Array<BufferAttribute>} attributes
378
393
  * @return {Array<InterleavedBufferAttribute>}
@@ -385,7 +400,7 @@ function interleaveAttributes( attributes ) {
385
400
  let arrayLength = 0;
386
401
  let stride = 0;
387
402
 
388
- // calculate the the length and type of the interleavedBuffer
403
+ // calculate the length and type of the interleavedBuffer
389
404
  for ( let i = 0, l = attributes.length; i < l; ++ i ) {
390
405
 
391
406
  const attribute = attributes[ i ];
@@ -555,7 +570,7 @@ function estimateBytesUsed( geometry ) {
555
570
  /**
556
571
  * @param {BufferGeometry} geometry
557
572
  * @param {number} tolerance
558
- * @return {BufferGeometry>}
573
+ * @return {BufferGeometry}
559
574
  */
560
575
  function mergeVertices( geometry, tolerance = 1e-4 ) {
561
576
 
@@ -573,22 +588,33 @@ function mergeVertices( geometry, tolerance = 1e-4 ) {
573
588
 
574
589
  // attributes and new attribute arrays
575
590
  const attributeNames = Object.keys( geometry.attributes );
576
- const attrArrays = {};
577
- const morphAttrsArrays = {};
591
+ const tmpAttributes = {};
592
+ const tmpMorphAttributes = {};
578
593
  const newIndices = [];
579
594
  const getters = [ 'getX', 'getY', 'getZ', 'getW' ];
595
+ const setters = [ 'setX', 'setY', 'setZ', 'setW' ];
580
596
 
581
- // initialize the arrays
597
+ // Initialize the arrays, allocating space conservatively. Extra
598
+ // space will be trimmed in the last step.
582
599
  for ( let i = 0, l = attributeNames.length; i < l; i ++ ) {
583
600
 
584
601
  const name = attributeNames[ i ];
602
+ const attr = geometry.attributes[ name ];
585
603
 
586
- attrArrays[ name ] = [];
604
+ tmpAttributes[ name ] = new BufferAttribute(
605
+ new attr.array.constructor( attr.count * attr.itemSize ),
606
+ attr.itemSize,
607
+ attr.normalized
608
+ );
587
609
 
588
610
  const morphAttr = geometry.morphAttributes[ name ];
589
611
  if ( morphAttr ) {
590
612
 
591
- morphAttrsArrays[ name ] = new Array( morphAttr.length ).fill().map( () => [] );
613
+ tmpMorphAttributes[ name ] = new BufferAttribute(
614
+ new morphAttr.array.constructor( morphAttr.count * morphAttr.itemSize ),
615
+ morphAttr.itemSize,
616
+ morphAttr.normalized
617
+ );
592
618
 
593
619
  }
594
620
 
@@ -626,26 +652,27 @@ function mergeVertices( geometry, tolerance = 1e-4 ) {
626
652
 
627
653
  } else {
628
654
 
629
- // copy data to the new index in the attribute arrays
655
+ // copy data to the new index in the temporary attributes
630
656
  for ( let j = 0, l = attributeNames.length; j < l; j ++ ) {
631
657
 
632
658
  const name = attributeNames[ j ];
633
659
  const attribute = geometry.getAttribute( name );
634
660
  const morphAttr = geometry.morphAttributes[ name ];
635
661
  const itemSize = attribute.itemSize;
636
- const newarray = attrArrays[ name ];
637
- const newMorphArrays = morphAttrsArrays[ name ];
662
+ const newarray = tmpAttributes[ name ];
663
+ const newMorphArrays = tmpMorphAttributes[ name ];
638
664
 
639
665
  for ( let k = 0; k < itemSize; k ++ ) {
640
666
 
641
667
  const getterFunc = getters[ k ];
642
- newarray.push( attribute[ getterFunc ]( index ) );
668
+ const setterFunc = setters[ k ];
669
+ newarray[ setterFunc ]( nextIndex, attribute[ getterFunc ]( index ) );
643
670
 
644
671
  if ( morphAttr ) {
645
672
 
646
673
  for ( let m = 0, ml = morphAttr.length; m < ml; m ++ ) {
647
674
 
648
- newMorphArrays[ m ].push( morphAttr[ m ][ getterFunc ]( index ) );
675
+ newMorphArrays[ m ][ setterFunc ]( nextIndex, morphAttr[ m ][ getterFunc ]( index ) );
649
676
 
650
677
  }
651
678
 
@@ -663,31 +690,29 @@ function mergeVertices( geometry, tolerance = 1e-4 ) {
663
690
 
664
691
  }
665
692
 
666
- // Generate typed arrays from new attribute arrays and update
667
- // the attributeBuffers
693
+ // generate result BufferGeometry
668
694
  const result = geometry.clone();
669
- for ( let i = 0, l = attributeNames.length; i < l; i ++ ) {
670
-
671
- const name = attributeNames[ i ];
672
- const oldAttribute = geometry.getAttribute( name );
673
-
674
- const buffer = new oldAttribute.array.constructor( attrArrays[ name ] );
675
- const attribute = new BufferAttribute( buffer, oldAttribute.itemSize, oldAttribute.normalized );
695
+ for ( const name in geometry.attributes ) {
676
696
 
677
- result.setAttribute( name, attribute );
697
+ const tmpAttribute = tmpAttributes[ name ];
678
698
 
679
- // Update the attribute arrays
680
- if ( name in morphAttrsArrays ) {
699
+ result.setAttribute( name, new BufferAttribute(
700
+ tmpAttribute.array.slice( 0, nextIndex * tmpAttribute.itemSize ),
701
+ tmpAttribute.itemSize,
702
+ tmpAttribute.normalized,
703
+ ) );
681
704
 
682
- for ( let j = 0; j < morphAttrsArrays[ name ].length; j ++ ) {
705
+ if ( ! ( name in tmpMorphAttributes ) ) continue;
683
706
 
684
- const oldMorphAttribute = geometry.morphAttributes[ name ][ j ];
707
+ for ( let j = 0; j < tmpMorphAttributes[ name ].length; j ++ ) {
685
708
 
686
- const buffer = new oldMorphAttribute.array.constructor( morphAttrsArrays[ name ][ j ] );
687
- const morphAttribute = new BufferAttribute( buffer, oldMorphAttribute.itemSize, oldMorphAttribute.normalized );
688
- result.morphAttributes[ name ][ j ] = morphAttribute;
709
+ const tmpMorphAttribute = tmpMorphAttributes[ name ][ j ];
689
710
 
690
- }
711
+ result.morphAttributes[ name ][ j ] = new BufferAttribute(
712
+ tmpMorphAttribute.array.slice( 0, nextIndex * tmpMorphAttribute.itemSize ),
713
+ tmpMorphAttribute.itemSize,
714
+ tmpMorphAttribute.normalized,
715
+ );
691
716
 
692
717
  }
693
718
 
@@ -704,7 +729,7 @@ function mergeVertices( geometry, tolerance = 1e-4 ) {
704
729
  /**
705
730
  * @param {BufferGeometry} geometry
706
731
  * @param {number} drawMode
707
- * @return {BufferGeometry>}
732
+ * @return {BufferGeometry}
708
733
  */
709
734
  function toTrianglesDrawMode( geometry, drawMode ) {
710
735
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@damienmortini/three",
3
- "version": "0.1.171",
3
+ "version": "0.1.173",
4
4
  "description": "Three.js helpers",
5
5
  "scripts": {
6
6
  "install": "npm run copyexamples",
@@ -25,9 +25,9 @@
25
25
  "bugs": "https://github.com/damienmortini/lib/issues",
26
26
  "homepage": "https://github.com/damienmortini/lib/tree/main/packages/three",
27
27
  "dependencies": {
28
- "@damienmortini/core": "^0.2.133",
28
+ "@damienmortini/core": "^0.2.135",
29
29
  "fs-extra": "^10.1.0",
30
- "three": "0.143.0"
30
+ "three": "0.146.0"
31
31
  },
32
- "gitHead": "ca9574013c9ba1c2a195603346a2d90242d5b198"
32
+ "gitHead": "2eeafcaa9fe81bdec2dc81d847962be4a821f5eb"
33
33
  }