@damienmortini/three 0.1.165 → 0.1.168

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.
@@ -117,6 +117,12 @@ class GLTFLoader extends Loader {
117
117
 
118
118
  } );
119
119
 
120
+ this.register( function ( parser ) {
121
+
122
+ return new GLTFMaterialsEmissiveStrengthExtension( parser );
123
+
124
+ } );
125
+
120
126
  this.register( function ( parser ) {
121
127
 
122
128
  return new GLTFMaterialsSpecularExtension( parser );
@@ -453,6 +459,7 @@ const EXTENSIONS = {
453
459
  KHR_TEXTURE_BASISU: 'KHR_texture_basisu',
454
460
  KHR_TEXTURE_TRANSFORM: 'KHR_texture_transform',
455
461
  KHR_MESH_QUANTIZATION: 'KHR_mesh_quantization',
462
+ KHR_MATERIALS_EMISSIVE_STRENGTH: 'KHR_materials_emissive_strength',
456
463
  EXT_TEXTURE_WEBP: 'EXT_texture_webp',
457
464
  EXT_MESHOPT_COMPRESSION: 'EXT_meshopt_compression'
458
465
  };
@@ -626,7 +633,7 @@ class GLTFMaterialsUnlitExtension {
626
633
 
627
634
  if ( metallicRoughness.baseColorTexture !== undefined ) {
628
635
 
629
- pending.push( parser.assignTexture( materialParams, 'map', metallicRoughness.baseColorTexture ) );
636
+ pending.push( parser.assignTexture( materialParams, 'map', metallicRoughness.baseColorTexture, sRGBEncoding ) );
630
637
 
631
638
  }
632
639
 
@@ -638,6 +645,45 @@ class GLTFMaterialsUnlitExtension {
638
645
 
639
646
  }
640
647
 
648
+ /**
649
+ * Materials Emissive Strength Extension
650
+ *
651
+ * Specification: https://github.com/KhronosGroup/glTF/blob/5768b3ce0ef32bc39cdf1bef10b948586635ead3/extensions/2.0/Khronos/KHR_materials_emissive_strength/README.md
652
+ */
653
+ class GLTFMaterialsEmissiveStrengthExtension {
654
+
655
+ constructor( parser ) {
656
+
657
+ this.parser = parser;
658
+ this.name = EXTENSIONS.KHR_MATERIALS_EMISSIVE_STRENGTH;
659
+
660
+ }
661
+
662
+ extendMaterialParams( materialIndex, materialParams ) {
663
+
664
+ const parser = this.parser;
665
+ const materialDef = parser.json.materials[ materialIndex ];
666
+
667
+ if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) {
668
+
669
+ return Promise.resolve();
670
+
671
+ }
672
+
673
+ const emissiveStrength = materialDef.extensions[ this.name ].emissiveStrength;
674
+
675
+ if ( emissiveStrength !== undefined ) {
676
+
677
+ materialParams.emissiveIntensity = emissiveStrength;
678
+
679
+ }
680
+
681
+ return Promise.resolve();
682
+
683
+ }
684
+
685
+ }
686
+
641
687
  /**
642
688
  * Clearcoat Materials Extension
643
689
  *
@@ -780,7 +826,7 @@ class GLTFMaterialsSheenExtension {
780
826
 
781
827
  if ( extension.sheenColorTexture !== undefined ) {
782
828
 
783
- pending.push( parser.assignTexture( materialParams, 'sheenColorMap', extension.sheenColorTexture ) );
829
+ pending.push( parser.assignTexture( materialParams, 'sheenColorMap', extension.sheenColorTexture, sRGBEncoding ) );
784
830
 
785
831
  }
786
832
 
@@ -1013,11 +1059,7 @@ class GLTFMaterialsSpecularExtension {
1013
1059
 
1014
1060
  if ( extension.specularColorTexture !== undefined ) {
1015
1061
 
1016
- pending.push( parser.assignTexture( materialParams, 'specularColorMap', extension.specularColorTexture ).then( function ( texture ) {
1017
-
1018
- texture.encoding = sRGBEncoding;
1019
-
1020
- } ) );
1062
+ pending.push( parser.assignTexture( materialParams, 'specularColorMap', extension.specularColorTexture, sRGBEncoding ) );
1021
1063
 
1022
1064
  }
1023
1065
 
@@ -1055,7 +1097,6 @@ class GLTFTextureBasisUExtension {
1055
1097
  }
1056
1098
 
1057
1099
  const extension = textureDef.extensions[ this.name ];
1058
- const source = json.images[ extension.source ];
1059
1100
  const loader = parser.options.ktx2Loader;
1060
1101
 
1061
1102
  if ( ! loader ) {
@@ -1073,7 +1114,7 @@ class GLTFTextureBasisUExtension {
1073
1114
 
1074
1115
  }
1075
1116
 
1076
- return parser.loadTextureImage( textureIndex, source, loader );
1117
+ return parser.loadTextureImage( textureIndex, extension.source, loader );
1077
1118
 
1078
1119
  }
1079
1120
 
@@ -1121,7 +1162,7 @@ class GLTFTextureWebPExtension {
1121
1162
 
1122
1163
  return this.detectSupport().then( function ( isSupported ) {
1123
1164
 
1124
- if ( isSupported ) return parser.loadTextureImage( textureIndex, source, loader );
1165
+ if ( isSupported ) return parser.loadTextureImage( textureIndex, extension.source, loader );
1125
1166
 
1126
1167
  if ( json.extensionsRequired && json.extensionsRequired.indexOf( name ) >= 0 ) {
1127
1168
 
@@ -1665,8 +1706,7 @@ class GLTFMaterialsPbrSpecularGlossinessExtension {
1665
1706
  'glossiness',
1666
1707
  'alphaMap',
1667
1708
  'envMap',
1668
- 'envMapIntensity',
1669
- 'refractionRatio',
1709
+ 'envMapIntensity'
1670
1710
  ];
1671
1711
 
1672
1712
  }
@@ -1697,7 +1737,7 @@ class GLTFMaterialsPbrSpecularGlossinessExtension {
1697
1737
 
1698
1738
  if ( pbrSpecularGlossiness.diffuseTexture !== undefined ) {
1699
1739
 
1700
- pending.push( parser.assignTexture( materialParams, 'map', pbrSpecularGlossiness.diffuseTexture ) );
1740
+ pending.push( parser.assignTexture( materialParams, 'map', pbrSpecularGlossiness.diffuseTexture, sRGBEncoding ) );
1701
1741
 
1702
1742
  }
1703
1743
 
@@ -1715,7 +1755,7 @@ class GLTFMaterialsPbrSpecularGlossinessExtension {
1715
1755
 
1716
1756
  const specGlossMapDef = pbrSpecularGlossiness.specularGlossinessTexture;
1717
1757
  pending.push( parser.assignTexture( materialParams, 'glossinessMap', specGlossMapDef ) );
1718
- pending.push( parser.assignTexture( materialParams, 'specularMap', specGlossMapDef ) );
1758
+ pending.push( parser.assignTexture( materialParams, 'specularMap', specGlossMapDef, sRGBEncoding ) );
1719
1759
 
1720
1760
  }
1721
1761
 
@@ -1739,7 +1779,7 @@ class GLTFMaterialsPbrSpecularGlossinessExtension {
1739
1779
  material.aoMapIntensity = 1.0;
1740
1780
 
1741
1781
  material.emissive = materialParams.emissive;
1742
- material.emissiveIntensity = 1.0;
1782
+ material.emissiveIntensity = materialParams.emissiveIntensity === undefined ? 1.0 : materialParams.emissiveIntensity;
1743
1783
  material.emissiveMap = materialParams.emissiveMap === undefined ? null : materialParams.emissiveMap;
1744
1784
 
1745
1785
  material.bumpMap = materialParams.bumpMap === undefined ? null : materialParams.bumpMap;
@@ -1765,8 +1805,6 @@ class GLTFMaterialsPbrSpecularGlossinessExtension {
1765
1805
  material.envMap = materialParams.envMap === undefined ? null : materialParams.envMap;
1766
1806
  material.envMapIntensity = 1.0;
1767
1807
 
1768
- material.refractionRatio = 0.98;
1769
-
1770
1808
  return material;
1771
1809
 
1772
1810
  }
@@ -2052,6 +2090,7 @@ function addMorphTargets( geometry, targets, parser ) {
2052
2090
 
2053
2091
  let hasMorphPosition = false;
2054
2092
  let hasMorphNormal = false;
2093
+ let hasMorphColor = false;
2055
2094
 
2056
2095
  for ( let i = 0, il = targets.length; i < il; i ++ ) {
2057
2096
 
@@ -2059,15 +2098,17 @@ function addMorphTargets( geometry, targets, parser ) {
2059
2098
 
2060
2099
  if ( target.POSITION !== undefined ) hasMorphPosition = true;
2061
2100
  if ( target.NORMAL !== undefined ) hasMorphNormal = true;
2101
+ if ( target.COLOR_0 !== undefined ) hasMorphColor = true;
2062
2102
 
2063
- if ( hasMorphPosition && hasMorphNormal ) break;
2103
+ if ( hasMorphPosition && hasMorphNormal && hasMorphColor ) break;
2064
2104
 
2065
2105
  }
2066
2106
 
2067
- if ( ! hasMorphPosition && ! hasMorphNormal ) return Promise.resolve( geometry );
2107
+ if ( ! hasMorphPosition && ! hasMorphNormal && ! hasMorphColor ) return Promise.resolve( geometry );
2068
2108
 
2069
2109
  const pendingPositionAccessors = [];
2070
2110
  const pendingNormalAccessors = [];
2111
+ const pendingColorAccessors = [];
2071
2112
 
2072
2113
  for ( let i = 0, il = targets.length; i < il; i ++ ) {
2073
2114
 
@@ -2093,18 +2134,31 @@ function addMorphTargets( geometry, targets, parser ) {
2093
2134
 
2094
2135
  }
2095
2136
 
2137
+ if ( hasMorphColor ) {
2138
+
2139
+ const pendingAccessor = target.COLOR_0 !== undefined
2140
+ ? parser.getDependency( 'accessor', target.COLOR_0 )
2141
+ : geometry.attributes.color;
2142
+
2143
+ pendingColorAccessors.push( pendingAccessor );
2144
+
2145
+ }
2146
+
2096
2147
  }
2097
2148
 
2098
2149
  return Promise.all( [
2099
2150
  Promise.all( pendingPositionAccessors ),
2100
- Promise.all( pendingNormalAccessors )
2151
+ Promise.all( pendingNormalAccessors ),
2152
+ Promise.all( pendingColorAccessors )
2101
2153
  ] ).then( function ( accessors ) {
2102
2154
 
2103
2155
  const morphPositions = accessors[ 0 ];
2104
2156
  const morphNormals = accessors[ 1 ];
2157
+ const morphColors = accessors[ 2 ];
2105
2158
 
2106
2159
  if ( hasMorphPosition ) geometry.morphAttributes.position = morphPositions;
2107
2160
  if ( hasMorphNormal ) geometry.morphAttributes.normal = morphNormals;
2161
+ if ( hasMorphColor ) geometry.morphAttributes.color = morphColors;
2108
2162
  geometry.morphTargetsRelative = true;
2109
2163
 
2110
2164
  return geometry;
@@ -2219,6 +2273,15 @@ function getNormalizedComponentScale( constructor ) {
2219
2273
 
2220
2274
  }
2221
2275
 
2276
+ function getImageURIMimeType( uri ) {
2277
+
2278
+ if ( uri.search( /\.jpe?g($|\?)/i ) > 0 || uri.search( /^data\:image\/jpeg/ ) === 0 ) return 'image/jpeg';
2279
+ if ( uri.search( /\.webp($|\?)/i ) > 0 || uri.search( /^data\:image\/webp/ ) === 0 ) return 'image/webp';
2280
+
2281
+ return 'image/png';
2282
+
2283
+ }
2284
+
2222
2285
  /* GLTF PARSER */
2223
2286
 
2224
2287
  class GLTFParser {
@@ -2244,6 +2307,7 @@ class GLTFParser {
2244
2307
  this.cameraCache = { refs: {}, uses: {} };
2245
2308
  this.lightCache = { refs: {}, uses: {} };
2246
2309
 
2310
+ this.sourceCache = {};
2247
2311
  this.textureCache = {};
2248
2312
 
2249
2313
  // Track node names, to ensure no duplicates
@@ -2251,14 +2315,19 @@ class GLTFParser {
2251
2315
 
2252
2316
  // Use an ImageBitmapLoader if imageBitmaps are supported. Moves much of the
2253
2317
  // 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 ) {
2255
2318
 
2256
- this.textureLoader = new ImageBitmapLoader( this.options.manager );
2319
+ const isSafari = /^((?!chrome|android).)*safari/i.test( navigator.userAgent ) === true;
2320
+ const isFirefox = navigator.userAgent.indexOf( 'Firefox' ) > - 1;
2321
+ const firefoxVersion = isFirefox ? navigator.userAgent.match( /Firefox\/([0-9]+)\./ )[ 1 ] : - 1;
2257
2322
 
2258
- } else {
2323
+ if ( typeof createImageBitmap === 'undefined' || isSafari || ( isFirefox && firefoxVersion < 98 ) ) {
2259
2324
 
2260
2325
  this.textureLoader = new TextureLoader( this.options.manager );
2261
2326
 
2327
+ } else {
2328
+
2329
+ this.textureLoader = new ImageBitmapLoader( this.options.manager );
2330
+
2262
2331
  }
2263
2332
 
2264
2333
  this.textureLoader.setCrossOrigin( this.options.crossOrigin );
@@ -2562,7 +2631,11 @@ class GLTFParser {
2562
2631
  break;
2563
2632
 
2564
2633
  case 'animation':
2565
- dependency = this.loadAnimation( index );
2634
+ dependency = this._invokeOne( function ( ext ) {
2635
+
2636
+ return ext.loadAnimation && ext.loadAnimation( index );
2637
+
2638
+ } );
2566
2639
  break;
2567
2640
 
2568
2641
  case 'camera':
@@ -2808,30 +2881,31 @@ class GLTFParser {
2808
2881
  const json = this.json;
2809
2882
  const options = this.options;
2810
2883
  const textureDef = json.textures[ textureIndex ];
2811
- const source = json.images[ textureDef.source ];
2884
+ const sourceIndex = textureDef.source;
2885
+ const sourceDef = json.images[ sourceIndex ];
2812
2886
 
2813
2887
  let loader = this.textureLoader;
2814
2888
 
2815
- if ( source.uri ) {
2889
+ if ( sourceDef.uri ) {
2816
2890
 
2817
- const handler = options.manager.getHandler( source.uri );
2891
+ const handler = options.manager.getHandler( sourceDef.uri );
2818
2892
  if ( handler !== null ) loader = handler;
2819
2893
 
2820
2894
  }
2821
2895
 
2822
- return this.loadTextureImage( textureIndex, source, loader );
2896
+ return this.loadTextureImage( textureIndex, sourceIndex, loader );
2823
2897
 
2824
2898
  }
2825
2899
 
2826
- loadTextureImage( textureIndex, source, loader ) {
2900
+ loadTextureImage( textureIndex, sourceIndex, loader ) {
2827
2901
 
2828
2902
  const parser = this;
2829
2903
  const json = this.json;
2830
- const options = this.options;
2831
2904
 
2832
2905
  const textureDef = json.textures[ textureIndex ];
2906
+ const sourceDef = json.images[ sourceIndex ];
2833
2907
 
2834
- const cacheKey = ( source.uri || source.bufferView ) + ':' + textureDef.sampler;
2908
+ const cacheKey = ( sourceDef.uri || sourceDef.bufferView ) + ':' + textureDef.sampler;
2835
2909
 
2836
2910
  if ( this.textureCache[ cacheKey ] ) {
2837
2911
 
@@ -2840,27 +2914,71 @@ class GLTFParser {
2840
2914
 
2841
2915
  }
2842
2916
 
2917
+ const promise = this.loadImageSource( sourceIndex, loader ).then( function ( texture ) {
2918
+
2919
+ texture.flipY = false;
2920
+
2921
+ if ( textureDef.name ) texture.name = textureDef.name;
2922
+
2923
+ const samplers = json.samplers || {};
2924
+ const sampler = samplers[ textureDef.sampler ] || {};
2925
+
2926
+ texture.magFilter = WEBGL_FILTERS[ sampler.magFilter ] || LinearFilter;
2927
+ texture.minFilter = WEBGL_FILTERS[ sampler.minFilter ] || LinearMipmapLinearFilter;
2928
+ texture.wrapS = WEBGL_WRAPPINGS[ sampler.wrapS ] || RepeatWrapping;
2929
+ texture.wrapT = WEBGL_WRAPPINGS[ sampler.wrapT ] || RepeatWrapping;
2930
+
2931
+ parser.associations.set( texture, { textures: textureIndex } );
2932
+
2933
+ return texture;
2934
+
2935
+ } ).catch( function () {
2936
+
2937
+ return null;
2938
+
2939
+ } );
2940
+
2941
+ this.textureCache[ cacheKey ] = promise;
2942
+
2943
+ return promise;
2944
+
2945
+ }
2946
+
2947
+ loadImageSource( sourceIndex, loader ) {
2948
+
2949
+ const parser = this;
2950
+ const json = this.json;
2951
+ const options = this.options;
2952
+
2953
+ if ( this.sourceCache[ sourceIndex ] !== undefined ) {
2954
+
2955
+ return this.sourceCache[ sourceIndex ].then( ( texture ) => texture.clone() );
2956
+
2957
+ }
2958
+
2959
+ const sourceDef = json.images[ sourceIndex ];
2960
+
2843
2961
  const URL = self.URL || self.webkitURL;
2844
2962
 
2845
- let sourceURI = source.uri || '';
2963
+ let sourceURI = sourceDef.uri || '';
2846
2964
  let isObjectURL = false;
2847
2965
 
2848
- if ( source.bufferView !== undefined ) {
2966
+ if ( sourceDef.bufferView !== undefined ) {
2849
2967
 
2850
2968
  // Load binary image data from bufferView, if provided.
2851
2969
 
2852
- sourceURI = parser.getDependency( 'bufferView', source.bufferView ).then( function ( bufferView ) {
2970
+ sourceURI = parser.getDependency( 'bufferView', sourceDef.bufferView ).then( function ( bufferView ) {
2853
2971
 
2854
2972
  isObjectURL = true;
2855
- const blob = new Blob( [ bufferView ], { type: source.mimeType } );
2973
+ const blob = new Blob( [ bufferView ], { type: sourceDef.mimeType } );
2856
2974
  sourceURI = URL.createObjectURL( blob );
2857
2975
  return sourceURI;
2858
2976
 
2859
2977
  } );
2860
2978
 
2861
- } else if ( source.uri === undefined ) {
2979
+ } else if ( sourceDef.uri === undefined ) {
2862
2980
 
2863
- throw new Error( 'THREE.GLTFLoader: Image ' + textureIndex + ' is missing URI and bufferView' );
2981
+ throw new Error( 'THREE.GLTFLoader: Image ' + sourceIndex + ' is missing URI and bufferView' );
2864
2982
 
2865
2983
  }
2866
2984
 
@@ -2897,31 +3015,18 @@ class GLTFParser {
2897
3015
 
2898
3016
  }
2899
3017
 
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 } );
3018
+ texture.userData.mimeType = sourceDef.mimeType || getImageURIMimeType( sourceDef.uri );
2913
3019
 
2914
3020
  return texture;
2915
3021
 
2916
- } ).catch( function () {
3022
+ } ).catch( function ( error ) {
2917
3023
 
2918
3024
  console.error( 'THREE.GLTFLoader: Couldn\'t load texture', sourceURI );
2919
- return null;
3025
+ throw error;
2920
3026
 
2921
3027
  } );
2922
3028
 
2923
- this.textureCache[ cacheKey ] = promise;
2924
-
3029
+ this.sourceCache[ sourceIndex ] = promise;
2925
3030
  return promise;
2926
3031
 
2927
3032
  }
@@ -2933,7 +3038,7 @@ class GLTFParser {
2933
3038
  * @param {Object} mapDef
2934
3039
  * @return {Promise<Texture>}
2935
3040
  */
2936
- assignTexture( materialParams, mapName, mapDef ) {
3041
+ assignTexture( materialParams, mapName, mapDef, encoding ) {
2937
3042
 
2938
3043
  const parser = this;
2939
3044
 
@@ -2961,6 +3066,12 @@ class GLTFParser {
2961
3066
 
2962
3067
  }
2963
3068
 
3069
+ if ( encoding !== undefined ) {
3070
+
3071
+ texture.encoding = encoding;
3072
+
3073
+ }
3074
+
2964
3075
  materialParams[ mapName ] = texture;
2965
3076
 
2966
3077
  return texture;
@@ -3132,7 +3243,7 @@ class GLTFParser {
3132
3243
 
3133
3244
  if ( metallicRoughness.baseColorTexture !== undefined ) {
3134
3245
 
3135
- pending.push( parser.assignTexture( materialParams, 'map', metallicRoughness.baseColorTexture ) );
3246
+ pending.push( parser.assignTexture( materialParams, 'map', metallicRoughness.baseColorTexture, sRGBEncoding ) );
3136
3247
 
3137
3248
  }
3138
3249
 
@@ -3223,7 +3334,7 @@ class GLTFParser {
3223
3334
 
3224
3335
  if ( materialDef.emissiveTexture !== undefined && materialType !== MeshBasicMaterial ) {
3225
3336
 
3226
- pending.push( parser.assignTexture( materialParams, 'emissiveMap', materialDef.emissiveTexture ) );
3337
+ pending.push( parser.assignTexture( materialParams, 'emissiveMap', materialDef.emissiveTexture, sRGBEncoding ) );
3227
3338
 
3228
3339
  }
3229
3340
 
@@ -3243,10 +3354,6 @@ class GLTFParser {
3243
3354
 
3244
3355
  if ( materialDef.name ) material.name = materialDef.name;
3245
3356
 
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
3357
  assignExtrasToUserData( material, materialDef );
3251
3358
 
3252
3359
  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,113 @@ 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';
12
13
 
14
+ function computeTangents() {
13
15
 
14
- function computeTangents( geometry ) {
16
+ throw new Error( 'BufferGeometryUtils: computeTangents renamed to computeMikkTSpaceTangents.' );
15
17
 
16
- geometry.computeTangents();
17
- console.warn( 'THREE.BufferGeometryUtils: .computeTangents() has been removed. Use BufferGeometry.computeTangents() instead.' );
18
+ }
19
+
20
+ function computeMikkTSpaceTangents( geometry, MikkTSpace, negateSign = true ) {
21
+
22
+ if ( ! MikkTSpace || ! MikkTSpace.isReady ) {
23
+
24
+ throw new Error( 'BufferGeometryUtils: Initialized MikkTSpace library required.' );
25
+
26
+ }
27
+
28
+ if ( ! geometry.hasAttribute( 'position' ) || ! geometry.hasAttribute( 'normal' ) || ! geometry.hasAttribute( 'uv' ) ) {
29
+
30
+ throw new Error( 'BufferGeometryUtils: Tangents require "position", "normal", and "uv" attributes.' );
31
+
32
+ }
33
+
34
+ function getAttributeArray( attribute ) {
35
+
36
+ if ( attribute.normalized || attribute.isInterleavedBufferAttribute ) {
37
+
38
+ const srcArray = attribute.isInterleavedBufferAttribute ? attribute.data.array : attribute.array;
39
+ const dstArray = new Float32Array( attribute.getCount() * attribute.itemSize );
40
+
41
+ for ( let i = 0, j = 0; i < attribute.getCount(); i ++ ) {
42
+
43
+ dstArray[ j ++ ] = MathUtils.denormalize( attribute.getX( i ), srcArray );
44
+ dstArray[ j ++ ] = MathUtils.denormalize( attribute.getY( i ), srcArray );
45
+
46
+ if ( attribute.itemSize > 2 ) {
47
+
48
+ dstArray[ j ++ ] = MathUtils.denormalize( attribute.getZ( i ), srcArray );
49
+
50
+ }
51
+
52
+ }
53
+
54
+ return dstArray;
55
+
56
+ }
57
+
58
+ if ( attribute.array instanceof Float32Array ) {
59
+
60
+ return attribute.array;
61
+
62
+ }
63
+
64
+ return new Float32Array( attribute.array );
65
+
66
+ }
67
+
68
+ // MikkTSpace algorithm requires non-indexed input.
69
+
70
+ const _geometry = geometry.index ? geometry.toNonIndexed() : geometry;
71
+
72
+ // Compute vertex tangents.
73
+
74
+ const tangents = MikkTSpace.generateTangents(
75
+
76
+ getAttributeArray( _geometry.attributes.position ),
77
+ getAttributeArray( _geometry.attributes.normal ),
78
+ getAttributeArray( _geometry.attributes.uv )
79
+
80
+ );
81
+
82
+ // Texture coordinate convention of glTF differs from the apparent
83
+ // default of the MikkTSpace library; .w component must be flipped.
84
+
85
+ if ( negateSign ) {
86
+
87
+ for ( let i = 3; i < tangents.length; i += 4 ) {
88
+
89
+ tangents[ i ] *= - 1;
90
+
91
+ }
92
+
93
+ }
94
+
95
+ //
96
+
97
+ _geometry.setAttribute( 'tangent', new BufferAttribute( tangents, 4 ) );
98
+
99
+ if ( geometry !== _geometry ) {
100
+
101
+ geometry.copy( _geometry )
102
+
103
+ }
104
+
105
+ return geometry;
18
106
 
19
107
  }
20
108
 
21
109
  /**
22
- * @param {Array<BufferGeometry>} geometries
23
- * @param {Boolean} useGroups
24
- * @return {BufferGeometry}
25
- */
110
+ * @param {Array<BufferGeometry>} geometries
111
+ * @param {Boolean} useGroups
112
+ * @return {BufferGeometry}
113
+ */
26
114
  function mergeBufferGeometries( geometries, useGroups = false ) {
27
115
 
28
116
  const isIndexed = geometries[ 0 ].index !== null;
@@ -349,6 +437,97 @@ function interleaveAttributes( attributes ) {
349
437
 
350
438
  }
351
439
 
440
+ // returns a new, non-interleaved version of the provided attribute
441
+ export function deinterleaveAttribute( attribute ) {
442
+
443
+ const cons = attribute.data.array.constructor;
444
+ const count = attribute.count;
445
+ const itemSize = attribute.itemSize;
446
+ const normalized = attribute.normalized;
447
+
448
+ const array = new cons( count * itemSize );
449
+ let newAttribute;
450
+ if ( attribute.isInstancedInterleavedBufferAttribute ) {
451
+
452
+ newAttribute = new InstancedBufferAttribute( array, itemSize, normalized, attribute.meshPerAttribute );
453
+
454
+ } else {
455
+
456
+ newAttribute = new BufferAttribute( array, itemSize, normalized );
457
+
458
+ }
459
+
460
+ for ( let i = 0; i < count; i ++ ) {
461
+
462
+ newAttribute.setX( i, attribute.getX( i ) );
463
+
464
+ if ( itemSize >= 2 ) {
465
+
466
+ newAttribute.setY( i, attribute.getY( i ) );
467
+
468
+ }
469
+
470
+ if ( itemSize >= 3 ) {
471
+
472
+ newAttribute.setZ( i, attribute.getZ( i ) );
473
+
474
+ }
475
+
476
+ if ( itemSize >= 4 ) {
477
+
478
+ newAttribute.setW( i, attribute.getW( i ) );
479
+
480
+ }
481
+
482
+ }
483
+
484
+ return newAttribute;
485
+
486
+ }
487
+
488
+ // deinterleaves all attributes on the geometry
489
+ export function deinterleaveGeometry( geometry ) {
490
+
491
+ const attributes = geometry.attributes;
492
+ const morphTargets = geometry.morphTargets;
493
+ const attrMap = new Map();
494
+
495
+ for ( const key in attributes ) {
496
+
497
+ const attr = attributes[ key ];
498
+ if ( attr.isInterleavedBufferAttribute ) {
499
+
500
+ if ( ! attrMap.has( attr ) ) {
501
+
502
+ attrMap.set( attr, deinterleaveAttribute( attr ) );
503
+
504
+ }
505
+
506
+ attributes[ key ] = attrMap.get( attr );
507
+
508
+ }
509
+
510
+ }
511
+
512
+ for ( const key in morphTargets ) {
513
+
514
+ const attr = morphTargets[ key ];
515
+ if ( attr.isInterleavedBufferAttribute ) {
516
+
517
+ if ( ! attrMap.has( attr ) ) {
518
+
519
+ attrMap.set( attr, deinterleaveAttribute( attr ) );
520
+
521
+ }
522
+
523
+ morphTargets[ key ] = attrMap.get( attr );
524
+
525
+ }
526
+
527
+ }
528
+
529
+ }
530
+
352
531
  /**
353
532
  * @param {Array<BufferGeometry>} geometry
354
533
  * @return {number}
@@ -660,7 +839,6 @@ function computeMorphedAttributes( object ) {
660
839
 
661
840
  function _calculateMorphedAttributeData(
662
841
  object,
663
- material,
664
842
  attribute,
665
843
  morphAttribute,
666
844
  morphTargetsRelative,
@@ -676,7 +854,7 @@ function computeMorphedAttributes( object ) {
676
854
 
677
855
  const morphInfluences = object.morphTargetInfluences;
678
856
 
679
- if ( material.morphTargets && morphAttribute && morphInfluences ) {
857
+ if ( morphAttribute && morphInfluences ) {
680
858
 
681
859
  _morphA.set( 0, 0, 0 );
682
860
  _morphB.set( 0, 0, 0 );
@@ -749,7 +927,7 @@ function computeMorphedAttributes( object ) {
749
927
  const groups = geometry.groups;
750
928
  const drawRange = geometry.drawRange;
751
929
  let i, j, il, jl;
752
- let group, groupMaterial;
930
+ let group;
753
931
  let start, end;
754
932
 
755
933
  const modifiedPosition = new Float32Array( positionAttribute.count * positionAttribute.itemSize );
@@ -764,7 +942,6 @@ function computeMorphedAttributes( object ) {
764
942
  for ( i = 0, il = groups.length; i < il; i ++ ) {
765
943
 
766
944
  group = groups[ i ];
767
- groupMaterial = material[ group.materialIndex ];
768
945
 
769
946
  start = Math.max( group.start, drawRange.start );
770
947
  end = Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) );
@@ -777,7 +954,6 @@ function computeMorphedAttributes( object ) {
777
954
 
778
955
  _calculateMorphedAttributeData(
779
956
  object,
780
- groupMaterial,
781
957
  positionAttribute,
782
958
  morphPosition,
783
959
  morphTargetsRelative,
@@ -787,7 +963,6 @@ function computeMorphedAttributes( object ) {
787
963
 
788
964
  _calculateMorphedAttributeData(
789
965
  object,
790
- groupMaterial,
791
966
  normalAttribute,
792
967
  morphNormal,
793
968
  morphTargetsRelative,
@@ -812,7 +987,6 @@ function computeMorphedAttributes( object ) {
812
987
 
813
988
  _calculateMorphedAttributeData(
814
989
  object,
815
- material,
816
990
  positionAttribute,
817
991
  morphPosition,
818
992
  morphTargetsRelative,
@@ -822,7 +996,6 @@ function computeMorphedAttributes( object ) {
822
996
 
823
997
  _calculateMorphedAttributeData(
824
998
  object,
825
- material,
826
999
  normalAttribute,
827
1000
  morphNormal,
828
1001
  morphTargetsRelative,
@@ -834,7 +1007,7 @@ function computeMorphedAttributes( object ) {
834
1007
 
835
1008
  }
836
1009
 
837
- } else if ( positionAttribute !== undefined ) {
1010
+ } else {
838
1011
 
839
1012
  // non-indexed buffer geometry
840
1013
 
@@ -843,7 +1016,6 @@ function computeMorphedAttributes( object ) {
843
1016
  for ( i = 0, il = groups.length; i < il; i ++ ) {
844
1017
 
845
1018
  group = groups[ i ];
846
- groupMaterial = material[ group.materialIndex ];
847
1019
 
848
1020
  start = Math.max( group.start, drawRange.start );
849
1021
  end = Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) );
@@ -856,7 +1028,6 @@ function computeMorphedAttributes( object ) {
856
1028
 
857
1029
  _calculateMorphedAttributeData(
858
1030
  object,
859
- groupMaterial,
860
1031
  positionAttribute,
861
1032
  morphPosition,
862
1033
  morphTargetsRelative,
@@ -866,7 +1037,6 @@ function computeMorphedAttributes( object ) {
866
1037
 
867
1038
  _calculateMorphedAttributeData(
868
1039
  object,
869
- groupMaterial,
870
1040
  normalAttribute,
871
1041
  morphNormal,
872
1042
  morphTargetsRelative,
@@ -891,7 +1061,6 @@ function computeMorphedAttributes( object ) {
891
1061
 
892
1062
  _calculateMorphedAttributeData(
893
1063
  object,
894
- material,
895
1064
  positionAttribute,
896
1065
  morphPosition,
897
1066
  morphTargetsRelative,
@@ -901,7 +1070,6 @@ function computeMorphedAttributes( object ) {
901
1070
 
902
1071
  _calculateMorphedAttributeData(
903
1072
  object,
904
- material,
905
1073
  normalAttribute,
906
1074
  morphNormal,
907
1075
  morphTargetsRelative,
@@ -929,10 +1097,111 @@ function computeMorphedAttributes( object ) {
929
1097
 
930
1098
  }
931
1099
 
1100
+ function mergeGroups( geometry ) {
1101
+
1102
+ if ( geometry.groups.length === 0 ) {
1103
+
1104
+ console.warn( 'THREE.BufferGeometryUtils.mergeGroups(): No groups are defined. Nothing to merge.' );
1105
+ return geometry;
1106
+
1107
+ }
1108
+
1109
+ let groups = geometry.groups;
1110
+
1111
+ // sort groups by material index
932
1112
 
1113
+ groups = groups.sort( ( a, b ) => {
1114
+
1115
+ if ( a.materialIndex !== b.materialIndex ) return a.materialIndex - b.materialIndex;
1116
+
1117
+ return a.start - b.start;
1118
+
1119
+ } );
1120
+
1121
+ // create index for non-indexed geometries
1122
+
1123
+ if ( geometry.getIndex() === null ) {
1124
+
1125
+ const positionAttribute = geometry.getAttribute( 'position' );
1126
+ const indices = [];
1127
+
1128
+ for ( let i = 0; i < positionAttribute.count; i += 3 ) {
1129
+
1130
+ indices.push( i, i + 1, i + 2 );
1131
+
1132
+ }
1133
+
1134
+ geometry.setIndex( indices );
1135
+
1136
+ }
1137
+
1138
+ // sort index
1139
+
1140
+ const index = geometry.getIndex();
1141
+
1142
+ const newIndices = [];
1143
+
1144
+ for ( let i = 0; i < groups.length; i ++ ) {
1145
+
1146
+ const group = groups[ i ];
1147
+
1148
+ const groupStart = group.start;
1149
+ const groupLength = groupStart + group.count;
1150
+
1151
+ for ( let j = groupStart; j < groupLength; j ++ ) {
1152
+
1153
+ newIndices.push( index.getX( j ) );
1154
+
1155
+ }
1156
+
1157
+ }
1158
+
1159
+ geometry.dispose(); // Required to force buffer recreation
1160
+ geometry.setIndex( newIndices );
1161
+
1162
+ // update groups indices
1163
+
1164
+ let start = 0;
1165
+
1166
+ for ( let i = 0; i < groups.length; i ++ ) {
1167
+
1168
+ const group = groups[ i ];
1169
+
1170
+ group.start = start;
1171
+ start += group.count;
1172
+
1173
+ }
1174
+
1175
+ // merge groups
1176
+
1177
+ let currentGroup = groups[ 0 ];
1178
+
1179
+ geometry.groups = [ currentGroup ];
1180
+
1181
+ for ( let i = 1; i < groups.length; i ++ ) {
1182
+
1183
+ const group = groups[ i ];
1184
+
1185
+ if ( currentGroup.materialIndex === group.materialIndex ) {
1186
+
1187
+ currentGroup.count += group.count;
1188
+
1189
+ } else {
1190
+
1191
+ currentGroup = group;
1192
+ geometry.groups.push( currentGroup );
1193
+
1194
+ }
1195
+
1196
+ }
1197
+
1198
+ return geometry;
1199
+
1200
+ }
933
1201
 
934
1202
  export {
935
1203
  computeTangents,
1204
+ computeMikkTSpaceTangents,
936
1205
  mergeBufferGeometries,
937
1206
  mergeBufferAttributes,
938
1207
  interleaveAttributes,
@@ -940,4 +1209,5 @@ export {
940
1209
  mergeVertices,
941
1210
  toTrianglesDrawMode,
942
1211
  computeMorphedAttributes,
1212
+ mergeGroups
943
1213
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@damienmortini/three",
3
- "version": "0.1.165",
3
+ "version": "0.1.168",
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.129",
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.140.2"
31
31
  },
32
- "gitHead": "1d8a4087fc41e674bb5e3b1ef6c841b635885bdc"
32
+ "gitHead": "9b36880886bbdadeb96b8e58597d7e7c9cfa8682"
33
33
  }