@damienmortini/three 0.1.166 → 0.1.167

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.
@@ -626,7 +626,7 @@ class GLTFMaterialsUnlitExtension {
626
626
 
627
627
  if ( metallicRoughness.baseColorTexture !== undefined ) {
628
628
 
629
- pending.push( parser.assignTexture( materialParams, 'map', metallicRoughness.baseColorTexture ) );
629
+ pending.push( parser.assignTexture( materialParams, 'map', metallicRoughness.baseColorTexture, sRGBEncoding ) );
630
630
 
631
631
  }
632
632
 
@@ -780,7 +780,7 @@ class GLTFMaterialsSheenExtension {
780
780
 
781
781
  if ( extension.sheenColorTexture !== undefined ) {
782
782
 
783
- pending.push( parser.assignTexture( materialParams, 'sheenColorMap', extension.sheenColorTexture ) );
783
+ pending.push( parser.assignTexture( materialParams, 'sheenColorMap', extension.sheenColorTexture, sRGBEncoding ) );
784
784
 
785
785
  }
786
786
 
@@ -1013,11 +1013,7 @@ class GLTFMaterialsSpecularExtension {
1013
1013
 
1014
1014
  if ( extension.specularColorTexture !== undefined ) {
1015
1015
 
1016
- pending.push( parser.assignTexture( materialParams, 'specularColorMap', extension.specularColorTexture ).then( function ( texture ) {
1017
-
1018
- texture.encoding = sRGBEncoding;
1019
-
1020
- } ) );
1016
+ pending.push( parser.assignTexture( materialParams, 'specularColorMap', extension.specularColorTexture, sRGBEncoding ) );
1021
1017
 
1022
1018
  }
1023
1019
 
@@ -1055,7 +1051,6 @@ class GLTFTextureBasisUExtension {
1055
1051
  }
1056
1052
 
1057
1053
  const extension = textureDef.extensions[ this.name ];
1058
- const source = json.images[ extension.source ];
1059
1054
  const loader = parser.options.ktx2Loader;
1060
1055
 
1061
1056
  if ( ! loader ) {
@@ -1073,7 +1068,7 @@ class GLTFTextureBasisUExtension {
1073
1068
 
1074
1069
  }
1075
1070
 
1076
- return parser.loadTextureImage( textureIndex, source, loader );
1071
+ return parser.loadTextureImage( textureIndex, extension.source, loader );
1077
1072
 
1078
1073
  }
1079
1074
 
@@ -1665,8 +1660,7 @@ class GLTFMaterialsPbrSpecularGlossinessExtension {
1665
1660
  'glossiness',
1666
1661
  'alphaMap',
1667
1662
  'envMap',
1668
- 'envMapIntensity',
1669
- 'refractionRatio',
1663
+ 'envMapIntensity'
1670
1664
  ];
1671
1665
 
1672
1666
  }
@@ -1697,7 +1691,7 @@ class GLTFMaterialsPbrSpecularGlossinessExtension {
1697
1691
 
1698
1692
  if ( pbrSpecularGlossiness.diffuseTexture !== undefined ) {
1699
1693
 
1700
- pending.push( parser.assignTexture( materialParams, 'map', pbrSpecularGlossiness.diffuseTexture ) );
1694
+ pending.push( parser.assignTexture( materialParams, 'map', pbrSpecularGlossiness.diffuseTexture, sRGBEncoding ) );
1701
1695
 
1702
1696
  }
1703
1697
 
@@ -1715,7 +1709,7 @@ class GLTFMaterialsPbrSpecularGlossinessExtension {
1715
1709
 
1716
1710
  const specGlossMapDef = pbrSpecularGlossiness.specularGlossinessTexture;
1717
1711
  pending.push( parser.assignTexture( materialParams, 'glossinessMap', specGlossMapDef ) );
1718
- pending.push( parser.assignTexture( materialParams, 'specularMap', specGlossMapDef ) );
1712
+ pending.push( parser.assignTexture( materialParams, 'specularMap', specGlossMapDef, sRGBEncoding ) );
1719
1713
 
1720
1714
  }
1721
1715
 
@@ -1765,8 +1759,6 @@ class GLTFMaterialsPbrSpecularGlossinessExtension {
1765
1759
  material.envMap = materialParams.envMap === undefined ? null : materialParams.envMap;
1766
1760
  material.envMapIntensity = 1.0;
1767
1761
 
1768
- material.refractionRatio = 0.98;
1769
-
1770
1762
  return material;
1771
1763
 
1772
1764
  }
@@ -2052,6 +2044,7 @@ function addMorphTargets( geometry, targets, parser ) {
2052
2044
 
2053
2045
  let hasMorphPosition = false;
2054
2046
  let hasMorphNormal = false;
2047
+ let hasMorphColor = false;
2055
2048
 
2056
2049
  for ( let i = 0, il = targets.length; i < il; i ++ ) {
2057
2050
 
@@ -2059,15 +2052,17 @@ function addMorphTargets( geometry, targets, parser ) {
2059
2052
 
2060
2053
  if ( target.POSITION !== undefined ) hasMorphPosition = true;
2061
2054
  if ( target.NORMAL !== undefined ) hasMorphNormal = true;
2055
+ if ( target.COLOR_0 !== undefined ) hasMorphColor = true;
2062
2056
 
2063
- if ( hasMorphPosition && hasMorphNormal ) break;
2057
+ if ( hasMorphPosition && hasMorphNormal && hasMorphColor ) break;
2064
2058
 
2065
2059
  }
2066
2060
 
2067
- if ( ! hasMorphPosition && ! hasMorphNormal ) return Promise.resolve( geometry );
2061
+ if ( ! hasMorphPosition && ! hasMorphNormal && ! hasMorphColor ) return Promise.resolve( geometry );
2068
2062
 
2069
2063
  const pendingPositionAccessors = [];
2070
2064
  const pendingNormalAccessors = [];
2065
+ const pendingColorAccessors = [];
2071
2066
 
2072
2067
  for ( let i = 0, il = targets.length; i < il; i ++ ) {
2073
2068
 
@@ -2093,18 +2088,31 @@ function addMorphTargets( geometry, targets, parser ) {
2093
2088
 
2094
2089
  }
2095
2090
 
2091
+ if ( hasMorphColor ) {
2092
+
2093
+ const pendingAccessor = target.COLOR_0 !== undefined
2094
+ ? parser.getDependency( 'accessor', target.COLOR_0 )
2095
+ : geometry.attributes.color;
2096
+
2097
+ pendingColorAccessors.push( pendingAccessor );
2098
+
2099
+ }
2100
+
2096
2101
  }
2097
2102
 
2098
2103
  return Promise.all( [
2099
2104
  Promise.all( pendingPositionAccessors ),
2100
- Promise.all( pendingNormalAccessors )
2105
+ Promise.all( pendingNormalAccessors ),
2106
+ Promise.all( pendingColorAccessors )
2101
2107
  ] ).then( function ( accessors ) {
2102
2108
 
2103
2109
  const morphPositions = accessors[ 0 ];
2104
2110
  const morphNormals = accessors[ 1 ];
2111
+ const morphColors = accessors[ 2 ];
2105
2112
 
2106
2113
  if ( hasMorphPosition ) geometry.morphAttributes.position = morphPositions;
2107
2114
  if ( hasMorphNormal ) geometry.morphAttributes.normal = morphNormals;
2115
+ if ( hasMorphColor ) geometry.morphAttributes.color = morphColors;
2108
2116
  geometry.morphTargetsRelative = true;
2109
2117
 
2110
2118
  return geometry;
@@ -2219,6 +2227,15 @@ function getNormalizedComponentScale( constructor ) {
2219
2227
 
2220
2228
  }
2221
2229
 
2230
+ function getImageURIMimeType( uri ) {
2231
+
2232
+ if ( uri.search( /\.jpe?g($|\?)/i ) > 0 || uri.search( /^data\:image\/jpeg/ ) === 0 ) return 'image/jpeg';
2233
+ if ( uri.search( /\.webp($|\?)/i ) > 0 || uri.search( /^data\:image\/webp/ ) === 0 ) return 'image/webp';
2234
+
2235
+ return 'image/png';
2236
+
2237
+ }
2238
+
2222
2239
  /* GLTF PARSER */
2223
2240
 
2224
2241
  class GLTFParser {
@@ -2244,6 +2261,7 @@ class GLTFParser {
2244
2261
  this.cameraCache = { refs: {}, uses: {} };
2245
2262
  this.lightCache = { refs: {}, uses: {} };
2246
2263
 
2264
+ this.sourceCache = {};
2247
2265
  this.textureCache = {};
2248
2266
 
2249
2267
  // Track node names, to ensure no duplicates
@@ -2251,7 +2269,7 @@ class GLTFParser {
2251
2269
 
2252
2270
  // Use an ImageBitmapLoader if imageBitmaps are supported. Moves much of the
2253
2271
  // expensive work of uploading a texture to the GPU off the main thread.
2254
- if ( typeof createImageBitmap !== 'undefined' && /Firefox|^((?!chrome|android).)*safari/i.test( navigator.userAgent ) === false ) {
2272
+ if ( typeof createImageBitmap !== 'undefined' && /^((?!chrome|android).)*safari/i.test( navigator.userAgent ) === false ) {
2255
2273
 
2256
2274
  this.textureLoader = new ImageBitmapLoader( this.options.manager );
2257
2275
 
@@ -2808,30 +2826,31 @@ class GLTFParser {
2808
2826
  const json = this.json;
2809
2827
  const options = this.options;
2810
2828
  const textureDef = json.textures[ textureIndex ];
2811
- const source = json.images[ textureDef.source ];
2829
+ const sourceIndex = textureDef.source;
2830
+ const sourceDef = json.images[ sourceIndex ];
2812
2831
 
2813
2832
  let loader = this.textureLoader;
2814
2833
 
2815
- if ( source.uri ) {
2834
+ if ( sourceDef.uri ) {
2816
2835
 
2817
- const handler = options.manager.getHandler( source.uri );
2836
+ const handler = options.manager.getHandler( sourceDef.uri );
2818
2837
  if ( handler !== null ) loader = handler;
2819
2838
 
2820
2839
  }
2821
2840
 
2822
- return this.loadTextureImage( textureIndex, source, loader );
2841
+ return this.loadTextureImage( textureIndex, sourceIndex, loader );
2823
2842
 
2824
2843
  }
2825
2844
 
2826
- loadTextureImage( textureIndex, source, loader ) {
2845
+ loadTextureImage( textureIndex, sourceIndex, loader ) {
2827
2846
 
2828
2847
  const parser = this;
2829
2848
  const json = this.json;
2830
- const options = this.options;
2831
2849
 
2832
2850
  const textureDef = json.textures[ textureIndex ];
2851
+ const sourceDef = json.images[ sourceIndex ];
2833
2852
 
2834
- const cacheKey = ( source.uri || source.bufferView ) + ':' + textureDef.sampler;
2853
+ const cacheKey = ( sourceDef.uri || sourceDef.bufferView ) + ':' + textureDef.sampler;
2835
2854
 
2836
2855
  if ( this.textureCache[ cacheKey ] ) {
2837
2856
 
@@ -2840,27 +2859,71 @@ class GLTFParser {
2840
2859
 
2841
2860
  }
2842
2861
 
2862
+ const promise = this.loadImageSource( sourceIndex, loader ).then( function ( texture ) {
2863
+
2864
+ texture.flipY = false;
2865
+
2866
+ if ( textureDef.name ) texture.name = textureDef.name;
2867
+
2868
+ const samplers = json.samplers || {};
2869
+ const sampler = samplers[ textureDef.sampler ] || {};
2870
+
2871
+ texture.magFilter = WEBGL_FILTERS[ sampler.magFilter ] || LinearFilter;
2872
+ texture.minFilter = WEBGL_FILTERS[ sampler.minFilter ] || LinearMipmapLinearFilter;
2873
+ texture.wrapS = WEBGL_WRAPPINGS[ sampler.wrapS ] || RepeatWrapping;
2874
+ texture.wrapT = WEBGL_WRAPPINGS[ sampler.wrapT ] || RepeatWrapping;
2875
+
2876
+ parser.associations.set( texture, { textures: textureIndex } );
2877
+
2878
+ return texture;
2879
+
2880
+ } ).catch( function () {
2881
+
2882
+ return null;
2883
+
2884
+ } );
2885
+
2886
+ this.textureCache[ cacheKey ] = promise;
2887
+
2888
+ return promise;
2889
+
2890
+ }
2891
+
2892
+ loadImageSource( sourceIndex, loader ) {
2893
+
2894
+ const parser = this;
2895
+ const json = this.json;
2896
+ const options = this.options;
2897
+
2898
+ if ( this.sourceCache[ sourceIndex ] !== undefined ) {
2899
+
2900
+ return this.sourceCache[ sourceIndex ].then( ( texture ) => texture.clone() );
2901
+
2902
+ }
2903
+
2904
+ const sourceDef = json.images[ sourceIndex ];
2905
+
2843
2906
  const URL = self.URL || self.webkitURL;
2844
2907
 
2845
- let sourceURI = source.uri || '';
2908
+ let sourceURI = sourceDef.uri || '';
2846
2909
  let isObjectURL = false;
2847
2910
 
2848
- if ( source.bufferView !== undefined ) {
2911
+ if ( sourceDef.bufferView !== undefined ) {
2849
2912
 
2850
2913
  // Load binary image data from bufferView, if provided.
2851
2914
 
2852
- sourceURI = parser.getDependency( 'bufferView', source.bufferView ).then( function ( bufferView ) {
2915
+ sourceURI = parser.getDependency( 'bufferView', sourceDef.bufferView ).then( function ( bufferView ) {
2853
2916
 
2854
2917
  isObjectURL = true;
2855
- const blob = new Blob( [ bufferView ], { type: source.mimeType } );
2918
+ const blob = new Blob( [ bufferView ], { type: sourceDef.mimeType } );
2856
2919
  sourceURI = URL.createObjectURL( blob );
2857
2920
  return sourceURI;
2858
2921
 
2859
2922
  } );
2860
2923
 
2861
- } else if ( source.uri === undefined ) {
2924
+ } else if ( sourceDef.uri === undefined ) {
2862
2925
 
2863
- throw new Error( 'THREE.GLTFLoader: Image ' + textureIndex + ' is missing URI and bufferView' );
2926
+ throw new Error( 'THREE.GLTFLoader: Image ' + sourceIndex + ' is missing URI and bufferView' );
2864
2927
 
2865
2928
  }
2866
2929
 
@@ -2897,31 +2960,18 @@ class GLTFParser {
2897
2960
 
2898
2961
  }
2899
2962
 
2900
- texture.flipY = false;
2901
-
2902
- if ( textureDef.name ) texture.name = textureDef.name;
2903
-
2904
- const samplers = json.samplers || {};
2905
- const sampler = samplers[ textureDef.sampler ] || {};
2906
-
2907
- texture.magFilter = WEBGL_FILTERS[ sampler.magFilter ] || LinearFilter;
2908
- texture.minFilter = WEBGL_FILTERS[ sampler.minFilter ] || LinearMipmapLinearFilter;
2909
- texture.wrapS = WEBGL_WRAPPINGS[ sampler.wrapS ] || RepeatWrapping;
2910
- texture.wrapT = WEBGL_WRAPPINGS[ sampler.wrapT ] || RepeatWrapping;
2911
-
2912
- parser.associations.set( texture, { textures: textureIndex } );
2963
+ texture.userData.mimeType = sourceDef.mimeType || getImageURIMimeType( sourceDef.uri );
2913
2964
 
2914
2965
  return texture;
2915
2966
 
2916
- } ).catch( function () {
2967
+ } ).catch( function ( error ) {
2917
2968
 
2918
2969
  console.error( 'THREE.GLTFLoader: Couldn\'t load texture', sourceURI );
2919
- return null;
2970
+ throw error;
2920
2971
 
2921
2972
  } );
2922
2973
 
2923
- this.textureCache[ cacheKey ] = promise;
2924
-
2974
+ this.sourceCache[ sourceIndex ] = promise;
2925
2975
  return promise;
2926
2976
 
2927
2977
  }
@@ -2933,7 +2983,7 @@ class GLTFParser {
2933
2983
  * @param {Object} mapDef
2934
2984
  * @return {Promise<Texture>}
2935
2985
  */
2936
- assignTexture( materialParams, mapName, mapDef ) {
2986
+ assignTexture( materialParams, mapName, mapDef, encoding ) {
2937
2987
 
2938
2988
  const parser = this;
2939
2989
 
@@ -2961,6 +3011,12 @@ class GLTFParser {
2961
3011
 
2962
3012
  }
2963
3013
 
3014
+ if ( encoding !== undefined ) {
3015
+
3016
+ texture.encoding = encoding;
3017
+
3018
+ }
3019
+
2964
3020
  materialParams[ mapName ] = texture;
2965
3021
 
2966
3022
  return texture;
@@ -3132,7 +3188,7 @@ class GLTFParser {
3132
3188
 
3133
3189
  if ( metallicRoughness.baseColorTexture !== undefined ) {
3134
3190
 
3135
- pending.push( parser.assignTexture( materialParams, 'map', metallicRoughness.baseColorTexture ) );
3191
+ pending.push( parser.assignTexture( materialParams, 'map', metallicRoughness.baseColorTexture, sRGBEncoding ) );
3136
3192
 
3137
3193
  }
3138
3194
 
@@ -3223,7 +3279,7 @@ class GLTFParser {
3223
3279
 
3224
3280
  if ( materialDef.emissiveTexture !== undefined && materialType !== MeshBasicMaterial ) {
3225
3281
 
3226
- pending.push( parser.assignTexture( materialParams, 'emissiveMap', materialDef.emissiveTexture ) );
3282
+ pending.push( parser.assignTexture( materialParams, 'emissiveMap', materialDef.emissiveTexture, sRGBEncoding ) );
3227
3283
 
3228
3284
  }
3229
3285
 
@@ -3243,10 +3299,6 @@ class GLTFParser {
3243
3299
 
3244
3300
  if ( materialDef.name ) material.name = materialDef.name;
3245
3301
 
3246
- // baseColorTexture, emissiveTexture, and specularGlossinessTexture use sRGB encoding.
3247
- if ( material.map ) material.map.encoding = sRGBEncoding;
3248
- if ( material.emissiveMap ) material.emissiveMap.encoding = sRGBEncoding;
3249
-
3250
3302
  assignExtrasToUserData( material, materialDef );
3251
3303
 
3252
3304
  parser.associations.set( material, { materials: materialIndex } );
@@ -106,15 +106,6 @@ class KTX2Loader extends Loader {
106
106
 
107
107
  }
108
108
 
109
- dispose() {
110
-
111
- this.workerPool.dispose();
112
- if ( this.workerSourceURL ) URL.revokeObjectURL( this.workerSourceURL );
113
-
114
- return this;
115
-
116
- }
117
-
118
109
  init() {
119
110
 
120
111
  if ( ! this.transcoderPending ) {
@@ -270,8 +261,8 @@ class KTX2Loader extends Loader {
270
261
 
271
262
  dispose() {
272
263
 
273
- URL.revokeObjectURL( this.workerSourceURL );
274
264
  this.workerPool.dispose();
265
+ if ( this.workerSourceURL ) URL.revokeObjectURL( this.workerSourceURL );
275
266
 
276
267
  _activeLoaders --;
277
268
 
@@ -4,25 +4,91 @@ import {
4
4
  Float32BufferAttribute,
5
5
  InterleavedBuffer,
6
6
  InterleavedBufferAttribute,
7
+ MathUtils,
7
8
  TriangleFanDrawMode,
8
9
  TriangleStripDrawMode,
9
10
  TrianglesDrawMode,
10
- Vector3
11
+ Vector3,
11
12
  } from '../../../../three/src/Three.js';
13
+ import { generateTangents } from '../libs/mikktspace.module.js';
12
14
 
13
15
 
14
- function computeTangents( geometry ) {
16
+ function computeTangents( geometry, negateSign = true ) {
15
17
 
16
- geometry.computeTangents();
17
- console.warn( 'THREE.BufferGeometryUtils: .computeTangents() has been removed. Use BufferGeometry.computeTangents() instead.' );
18
+ function getAttributeArray( attribute ) {
19
+
20
+ if ( attribute.normalized || attribute.isInterleavedBufferAttribute ) {
21
+
22
+ const srcArray = attribute.isInterleavedBufferAttribute ? attribute.data.array : attribute.array;
23
+ const dstArray = new Float32Array( attribute.getCount() * attribute.itemSize );
24
+
25
+ for ( let i = 0, j = 0; i < attribute.getCount(); i ++ ) {
26
+
27
+ dstArray[ j ++ ] = MathUtils.denormalize( attribute.getX( i ), srcArray );
28
+ dstArray[ j ++ ] = MathUtils.denormalize( attribute.getY( i ), srcArray );
29
+
30
+ if ( attribute.itemSize > 2 ) {
31
+
32
+ dstArray[ j ++ ] = MathUtils.denormalize( attribute.getZ( i ), srcArray );
33
+
34
+ }
35
+
36
+ }
37
+
38
+ return dstArray;
39
+
40
+ }
41
+
42
+ if ( attribute.array instanceof Float32Array ) {
43
+
44
+ return attribute.array;
45
+
46
+ }
47
+
48
+ return new Float32Array( attribute.array );
49
+
50
+ }
51
+
52
+ // MikkTSpace algorithm requires non-indexed input.
53
+
54
+ const _geometry = geometry.index ? geometry.toNonIndexed() : geometry;
55
+
56
+ // Compute vertex tangents.
57
+
58
+ const tangents = generateTangents(
59
+
60
+ getAttributeArray( _geometry.attributes.position ),
61
+ getAttributeArray( _geometry.attributes.normal ),
62
+ getAttributeArray( _geometry.attributes.uv )
63
+
64
+ );
65
+
66
+ // Texture coordinate convention of glTF differs from the apparent
67
+ // default of the MikkTSpace library; .w component must be flipped.
68
+
69
+ if ( negateSign ) {
70
+
71
+ for ( let i = 3; i < tangents.length; i += 4 ) {
72
+
73
+ tangents[ i ] *= - 1;
74
+
75
+ }
76
+
77
+ }
78
+
79
+ //
80
+
81
+ _geometry.setAttribute( 'tangent', new BufferAttribute( tangents, 4 ) );
82
+
83
+ return geometry.copy( _geometry );
18
84
 
19
85
  }
20
86
 
21
87
  /**
22
- * @param {Array<BufferGeometry>} geometries
23
- * @param {Boolean} useGroups
24
- * @return {BufferGeometry}
25
- */
88
+ * @param {Array<BufferGeometry>} geometries
89
+ * @param {Boolean} useGroups
90
+ * @return {BufferGeometry}
91
+ */
26
92
  function mergeBufferGeometries( geometries, useGroups = false ) {
27
93
 
28
94
  const isIndexed = geometries[ 0 ].index !== null;
@@ -834,7 +900,7 @@ function computeMorphedAttributes( object ) {
834
900
 
835
901
  }
836
902
 
837
- } else if ( positionAttribute !== undefined ) {
903
+ } else {
838
904
 
839
905
  // non-indexed buffer geometry
840
906
 
@@ -929,7 +995,107 @@ function computeMorphedAttributes( object ) {
929
995
 
930
996
  }
931
997
 
998
+ function mergeGroups( geometry ) {
999
+
1000
+ if ( geometry.groups.length === 0 ) {
1001
+
1002
+ console.warn( 'THREE.BufferGeometryUtils.mergeGroups(): No groups are defined. Nothing to merge.' );
1003
+ return geometry;
1004
+
1005
+ }
1006
+
1007
+ let groups = geometry.groups;
1008
+
1009
+ // sort groups by material index
1010
+
1011
+ groups = groups.sort( ( a, b ) => {
1012
+
1013
+ if ( a.materialIndex !== b.materialIndex ) return a.materialIndex - b.materialIndex;
1014
+
1015
+ return a.start - b.start;
932
1016
 
1017
+ } );
1018
+
1019
+ // create index for non-indexed geometries
1020
+
1021
+ if ( geometry.getIndex() === null ) {
1022
+
1023
+ const positionAttribute = geometry.getAttribute( 'position' );
1024
+ const indices = [];
1025
+
1026
+ for ( let i = 0; i < positionAttribute.count; i += 3 ) {
1027
+
1028
+ indices.push( i, i + 1, i + 2 );
1029
+
1030
+ }
1031
+
1032
+ geometry.setIndex( indices );
1033
+
1034
+ }
1035
+
1036
+ // sort index
1037
+
1038
+ const index = geometry.getIndex();
1039
+
1040
+ const newIndices = [];
1041
+
1042
+ for ( let i = 0; i < groups.length; i ++ ) {
1043
+
1044
+ const group = groups[ i ];
1045
+
1046
+ const groupStart = group.start;
1047
+ const groupLength = groupStart + group.count;
1048
+
1049
+ for ( let j = groupStart; j < groupLength; j ++ ) {
1050
+
1051
+ newIndices.push( index.getX( j ) );
1052
+
1053
+ }
1054
+
1055
+ }
1056
+
1057
+ geometry.dispose(); // Required to force buffer recreation
1058
+ geometry.setIndex( newIndices );
1059
+
1060
+ // update groups indices
1061
+
1062
+ let start = 0;
1063
+
1064
+ for ( let i = 0; i < groups.length; i ++ ) {
1065
+
1066
+ const group = groups[ i ];
1067
+
1068
+ group.start = start;
1069
+ start += group.count;
1070
+
1071
+ }
1072
+
1073
+ // merge groups
1074
+
1075
+ let currentGroup = groups[ 0 ];
1076
+
1077
+ geometry.groups = [ currentGroup ];
1078
+
1079
+ for ( let i = 1; i < groups.length; i ++ ) {
1080
+
1081
+ const group = groups[ i ];
1082
+
1083
+ if ( currentGroup.materialIndex === group.materialIndex ) {
1084
+
1085
+ currentGroup.count += group.count;
1086
+
1087
+ } else {
1088
+
1089
+ currentGroup = group;
1090
+ geometry.groups.push( currentGroup );
1091
+
1092
+ }
1093
+
1094
+ }
1095
+
1096
+ return geometry;
1097
+
1098
+ }
933
1099
 
934
1100
  export {
935
1101
  computeTangents,
@@ -940,4 +1106,5 @@ export {
940
1106
  mergeVertices,
941
1107
  toTrianglesDrawMode,
942
1108
  computeMorphedAttributes,
1109
+ mergeGroups
943
1110
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@damienmortini/three",
3
- "version": "0.1.166",
3
+ "version": "0.1.167",
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.130",
29
- "fs-extra": "^10.0.0",
30
- "three": "0.137.5"
28
+ "@damienmortini/core": "^0.2.131",
29
+ "fs-extra": "^10.0.1",
30
+ "three": "0.139.0"
31
31
  },
32
- "gitHead": "cb0bafdeb0bf9475e139e8248b0c591acac0ebea"
32
+ "gitHead": "212228c077e3dd31b65117e24ec84c80a9bfb984"
33
33
  }