@damienmortini/three 0.1.181 → 0.1.182

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.
@@ -351,6 +351,12 @@ class DRACOLoader extends Loader {
351
351
 
352
352
  this.workerPool.length = 0;
353
353
 
354
+ if ( this.workerSourceURL !== '' ) {
355
+
356
+ URL.revokeObjectURL( this.workerSourceURL );
357
+
358
+ }
359
+
354
360
  return this;
355
361
 
356
362
  }
@@ -53,7 +53,6 @@ import {
53
53
  SkinnedMesh,
54
54
  Sphere,
55
55
  SpotLight,
56
- TangentSpaceNormalMap,
57
56
  Texture,
58
57
  TextureLoader,
59
58
  TriangleFanDrawMode,
@@ -63,6 +62,7 @@ import {
63
62
  VectorKeyframeTrack,
64
63
  sRGBEncoding
65
64
  } from '../../../../three/src/Three.js';
65
+ import { toTrianglesDrawMode } from '../utils/BufferGeometryUtils.js';
66
66
 
67
67
  class GLTFLoader extends Loader {
68
68
 
@@ -287,6 +287,7 @@ class GLTFLoader extends Loader {
287
287
  let json;
288
288
  const extensions = {};
289
289
  const plugins = {};
290
+ const textDecoder = new TextDecoder();
290
291
 
291
292
  if ( typeof data === 'string' ) {
292
293
 
@@ -294,7 +295,7 @@ class GLTFLoader extends Loader {
294
295
 
295
296
  } else if ( data instanceof ArrayBuffer ) {
296
297
 
297
- const magic = LoaderUtils.decodeText( new Uint8Array( data, 0, 4 ) );
298
+ const magic = textDecoder.decode( new Uint8Array( data, 0, 4 ) );
298
299
 
299
300
  if ( magic === BINARY_EXTENSION_HEADER_MAGIC ) {
300
301
 
@@ -313,7 +314,7 @@ class GLTFLoader extends Loader {
313
314
 
314
315
  } else {
315
316
 
316
- json = JSON.parse( LoaderUtils.decodeText( new Uint8Array( data ) ) );
317
+ json = JSON.parse( textDecoder.decode( data ) );
317
318
 
318
319
  }
319
320
 
@@ -369,10 +370,6 @@ class GLTFLoader extends Loader {
369
370
  extensions[ extensionName ] = new GLTFMaterialsUnlitExtension();
370
371
  break;
371
372
 
372
- case EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS:
373
- extensions[ extensionName ] = new GLTFMaterialsPbrSpecularGlossinessExtension();
374
- break;
375
-
376
373
  case EXTENSIONS.KHR_DRACO_MESH_COMPRESSION:
377
374
  extensions[ extensionName ] = new GLTFDracoMeshCompressionExtension( json, this.dracoLoader );
378
375
  break;
@@ -465,7 +462,6 @@ const EXTENSIONS = {
465
462
  KHR_LIGHTS_PUNCTUAL: 'KHR_lights_punctual',
466
463
  KHR_MATERIALS_CLEARCOAT: 'KHR_materials_clearcoat',
467
464
  KHR_MATERIALS_IOR: 'KHR_materials_ior',
468
- KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS: 'KHR_materials_pbrSpecularGlossiness',
469
465
  KHR_MATERIALS_SHEEN: 'KHR_materials_sheen',
470
466
  KHR_MATERIALS_SPECULAR: 'KHR_materials_specular',
471
467
  KHR_MATERIALS_TRANSMISSION: 'KHR_materials_transmission',
@@ -576,6 +572,8 @@ class GLTFLightsExtension {
576
572
 
577
573
  lightNode.decay = 2;
578
574
 
575
+ assignExtrasToUserData( lightNode, lightDef );
576
+
579
577
  if ( lightDef.intensity !== undefined ) lightNode.intensity = lightDef.intensity;
580
578
 
581
579
  lightNode.name = parser.createUniqueName( lightDef.name || ( 'light_' + lightIndex ) );
@@ -588,6 +586,14 @@ class GLTFLightsExtension {
588
586
 
589
587
  }
590
588
 
589
+ getDependency( type, index ) {
590
+
591
+ if ( type !== 'light' ) return;
592
+
593
+ return this._loadLight( index );
594
+
595
+ }
596
+
591
597
  createNodeAttachment( nodeIndex ) {
592
598
 
593
599
  const self = this;
@@ -1562,9 +1568,10 @@ class GLTFBinaryExtension {
1562
1568
  this.body = null;
1563
1569
 
1564
1570
  const headerView = new DataView( data, 0, BINARY_EXTENSION_HEADER_LENGTH );
1571
+ const textDecoder = new TextDecoder();
1565
1572
 
1566
1573
  this.header = {
1567
- magic: LoaderUtils.decodeText( new Uint8Array( data.slice( 0, 4 ) ) ),
1574
+ magic: textDecoder.decode( new Uint8Array( data.slice( 0, 4 ) ) ),
1568
1575
  version: headerView.getUint32( 4, true ),
1569
1576
  length: headerView.getUint32( 8, true )
1570
1577
  };
@@ -1594,7 +1601,7 @@ class GLTFBinaryExtension {
1594
1601
  if ( chunkType === BINARY_EXTENSION_CHUNK_TYPES.JSON ) {
1595
1602
 
1596
1603
  const contentArray = new Uint8Array( data, BINARY_EXTENSION_HEADER_LENGTH + chunkIndex, chunkLength );
1597
- this.content = LoaderUtils.decodeText( contentArray );
1604
+ this.content = textDecoder.decode( contentArray );
1598
1605
 
1599
1606
  } else if ( chunkType === BINARY_EXTENSION_CHUNK_TYPES.BIN ) {
1600
1607
 
@@ -1758,335 +1765,6 @@ class GLTFTextureTransformExtension {
1758
1765
 
1759
1766
  }
1760
1767
 
1761
- /**
1762
- * Specular-Glossiness Extension
1763
- *
1764
- * Specification: https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Archived/KHR_materials_pbrSpecularGlossiness
1765
- */
1766
-
1767
- /**
1768
- * A sub class of StandardMaterial with some of the functionality
1769
- * changed via the `onBeforeCompile` callback
1770
- * @pailhead
1771
- */
1772
- class GLTFMeshStandardSGMaterial extends MeshStandardMaterial {
1773
-
1774
- constructor( params ) {
1775
-
1776
- super();
1777
-
1778
- this.isGLTFSpecularGlossinessMaterial = true;
1779
-
1780
- //various chunks that need replacing
1781
- const specularMapParsFragmentChunk = [
1782
- '#ifdef USE_SPECULARMAP',
1783
- ' uniform sampler2D specularMap;',
1784
- '#endif'
1785
- ].join( '\n' );
1786
-
1787
- const glossinessMapParsFragmentChunk = [
1788
- '#ifdef USE_GLOSSINESSMAP',
1789
- ' uniform sampler2D glossinessMap;',
1790
- '#endif'
1791
- ].join( '\n' );
1792
-
1793
- const specularMapFragmentChunk = [
1794
- 'vec3 specularFactor = specular;',
1795
- '#ifdef USE_SPECULARMAP',
1796
- ' vec4 texelSpecular = texture2D( specularMap, vUv );',
1797
- ' // reads channel RGB, compatible with a glTF Specular-Glossiness (RGBA) texture',
1798
- ' specularFactor *= texelSpecular.rgb;',
1799
- '#endif'
1800
- ].join( '\n' );
1801
-
1802
- const glossinessMapFragmentChunk = [
1803
- 'float glossinessFactor = glossiness;',
1804
- '#ifdef USE_GLOSSINESSMAP',
1805
- ' vec4 texelGlossiness = texture2D( glossinessMap, vUv );',
1806
- ' // reads channel A, compatible with a glTF Specular-Glossiness (RGBA) texture',
1807
- ' glossinessFactor *= texelGlossiness.a;',
1808
- '#endif'
1809
- ].join( '\n' );
1810
-
1811
- const lightPhysicalFragmentChunk = [
1812
- 'PhysicalMaterial material;',
1813
- 'material.diffuseColor = diffuseColor.rgb * ( 1. - max( specularFactor.r, max( specularFactor.g, specularFactor.b ) ) );',
1814
- 'vec3 dxy = max( abs( dFdx( geometryNormal ) ), abs( dFdy( geometryNormal ) ) );',
1815
- 'float geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );',
1816
- 'material.roughness = max( 1.0 - glossinessFactor, 0.0525 ); // 0.0525 corresponds to the base mip of a 256 cubemap.',
1817
- 'material.roughness += geometryRoughness;',
1818
- 'material.roughness = min( material.roughness, 1.0 );',
1819
- 'material.specularColor = specularFactor;',
1820
- ].join( '\n' );
1821
-
1822
- const uniforms = {
1823
- specular: { value: new Color().setHex( 0xffffff ) },
1824
- glossiness: { value: 1 },
1825
- specularMap: { value: null },
1826
- glossinessMap: { value: null }
1827
- };
1828
-
1829
- this._extraUniforms = uniforms;
1830
-
1831
- this.onBeforeCompile = function ( shader ) {
1832
-
1833
- for ( const uniformName in uniforms ) {
1834
-
1835
- shader.uniforms[ uniformName ] = uniforms[ uniformName ];
1836
-
1837
- }
1838
-
1839
- shader.fragmentShader = shader.fragmentShader
1840
- .replace( 'uniform float roughness;', 'uniform vec3 specular;' )
1841
- .replace( 'uniform float metalness;', 'uniform float glossiness;' )
1842
- .replace( '#include <roughnessmap_pars_fragment>', specularMapParsFragmentChunk )
1843
- .replace( '#include <metalnessmap_pars_fragment>', glossinessMapParsFragmentChunk )
1844
- .replace( '#include <roughnessmap_fragment>', specularMapFragmentChunk )
1845
- .replace( '#include <metalnessmap_fragment>', glossinessMapFragmentChunk )
1846
- .replace( '#include <lights_physical_fragment>', lightPhysicalFragmentChunk );
1847
-
1848
- };
1849
-
1850
- Object.defineProperties( this, {
1851
-
1852
- specular: {
1853
- get: function () {
1854
-
1855
- return uniforms.specular.value;
1856
-
1857
- },
1858
- set: function ( v ) {
1859
-
1860
- uniforms.specular.value = v;
1861
-
1862
- }
1863
- },
1864
-
1865
- specularMap: {
1866
- get: function () {
1867
-
1868
- return uniforms.specularMap.value;
1869
-
1870
- },
1871
- set: function ( v ) {
1872
-
1873
- uniforms.specularMap.value = v;
1874
-
1875
- if ( v ) {
1876
-
1877
- this.defines.USE_SPECULARMAP = ''; // USE_UV is set by the renderer for specular maps
1878
-
1879
- } else {
1880
-
1881
- delete this.defines.USE_SPECULARMAP;
1882
-
1883
- }
1884
-
1885
- }
1886
- },
1887
-
1888
- glossiness: {
1889
- get: function () {
1890
-
1891
- return uniforms.glossiness.value;
1892
-
1893
- },
1894
- set: function ( v ) {
1895
-
1896
- uniforms.glossiness.value = v;
1897
-
1898
- }
1899
- },
1900
-
1901
- glossinessMap: {
1902
- get: function () {
1903
-
1904
- return uniforms.glossinessMap.value;
1905
-
1906
- },
1907
- set: function ( v ) {
1908
-
1909
- uniforms.glossinessMap.value = v;
1910
-
1911
- if ( v ) {
1912
-
1913
- this.defines.USE_GLOSSINESSMAP = '';
1914
- this.defines.USE_UV = '';
1915
-
1916
- } else {
1917
-
1918
- delete this.defines.USE_GLOSSINESSMAP;
1919
- delete this.defines.USE_UV;
1920
-
1921
- }
1922
-
1923
- }
1924
- }
1925
-
1926
- } );
1927
-
1928
- delete this.metalness;
1929
- delete this.roughness;
1930
- delete this.metalnessMap;
1931
- delete this.roughnessMap;
1932
-
1933
- this.setValues( params );
1934
-
1935
- }
1936
-
1937
- copy( source ) {
1938
-
1939
- super.copy( source );
1940
-
1941
- this.specularMap = source.specularMap;
1942
- this.specular.copy( source.specular );
1943
- this.glossinessMap = source.glossinessMap;
1944
- this.glossiness = source.glossiness;
1945
- delete this.metalness;
1946
- delete this.roughness;
1947
- delete this.metalnessMap;
1948
- delete this.roughnessMap;
1949
- return this;
1950
-
1951
- }
1952
-
1953
- }
1954
-
1955
-
1956
- class GLTFMaterialsPbrSpecularGlossinessExtension {
1957
-
1958
- constructor() {
1959
-
1960
- this.name = EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS;
1961
-
1962
- this.specularGlossinessParams = [
1963
- 'color',
1964
- 'map',
1965
- 'lightMap',
1966
- 'lightMapIntensity',
1967
- 'aoMap',
1968
- 'aoMapIntensity',
1969
- 'emissive',
1970
- 'emissiveIntensity',
1971
- 'emissiveMap',
1972
- 'bumpMap',
1973
- 'bumpScale',
1974
- 'normalMap',
1975
- 'normalMapType',
1976
- 'displacementMap',
1977
- 'displacementScale',
1978
- 'displacementBias',
1979
- 'specularMap',
1980
- 'specular',
1981
- 'glossinessMap',
1982
- 'glossiness',
1983
- 'alphaMap',
1984
- 'envMap',
1985
- 'envMapIntensity'
1986
- ];
1987
-
1988
- }
1989
-
1990
- getMaterialType() {
1991
-
1992
- return GLTFMeshStandardSGMaterial;
1993
-
1994
- }
1995
-
1996
- extendParams( materialParams, materialDef, parser ) {
1997
-
1998
- const pbrSpecularGlossiness = materialDef.extensions[ this.name ];
1999
-
2000
- materialParams.color = new Color( 1.0, 1.0, 1.0 );
2001
- materialParams.opacity = 1.0;
2002
-
2003
- const pending = [];
2004
-
2005
- if ( Array.isArray( pbrSpecularGlossiness.diffuseFactor ) ) {
2006
-
2007
- const array = pbrSpecularGlossiness.diffuseFactor;
2008
-
2009
- materialParams.color.fromArray( array );
2010
- materialParams.opacity = array[ 3 ];
2011
-
2012
- }
2013
-
2014
- if ( pbrSpecularGlossiness.diffuseTexture !== undefined ) {
2015
-
2016
- pending.push( parser.assignTexture( materialParams, 'map', pbrSpecularGlossiness.diffuseTexture, sRGBEncoding ) );
2017
-
2018
- }
2019
-
2020
- materialParams.emissive = new Color( 0.0, 0.0, 0.0 );
2021
- materialParams.glossiness = pbrSpecularGlossiness.glossinessFactor !== undefined ? pbrSpecularGlossiness.glossinessFactor : 1.0;
2022
- materialParams.specular = new Color( 1.0, 1.0, 1.0 );
2023
-
2024
- if ( Array.isArray( pbrSpecularGlossiness.specularFactor ) ) {
2025
-
2026
- materialParams.specular.fromArray( pbrSpecularGlossiness.specularFactor );
2027
-
2028
- }
2029
-
2030
- if ( pbrSpecularGlossiness.specularGlossinessTexture !== undefined ) {
2031
-
2032
- const specGlossMapDef = pbrSpecularGlossiness.specularGlossinessTexture;
2033
- pending.push( parser.assignTexture( materialParams, 'glossinessMap', specGlossMapDef ) );
2034
- pending.push( parser.assignTexture( materialParams, 'specularMap', specGlossMapDef, sRGBEncoding ) );
2035
-
2036
- }
2037
-
2038
- return Promise.all( pending );
2039
-
2040
- }
2041
-
2042
- createMaterial( materialParams ) {
2043
-
2044
- const material = new GLTFMeshStandardSGMaterial( materialParams );
2045
- material.fog = true;
2046
-
2047
- material.color = materialParams.color;
2048
-
2049
- material.map = materialParams.map === undefined ? null : materialParams.map;
2050
-
2051
- material.lightMap = null;
2052
- material.lightMapIntensity = 1.0;
2053
-
2054
- material.aoMap = materialParams.aoMap === undefined ? null : materialParams.aoMap;
2055
- material.aoMapIntensity = 1.0;
2056
-
2057
- material.emissive = materialParams.emissive;
2058
- material.emissiveIntensity = materialParams.emissiveIntensity === undefined ? 1.0 : materialParams.emissiveIntensity;
2059
- material.emissiveMap = materialParams.emissiveMap === undefined ? null : materialParams.emissiveMap;
2060
-
2061
- material.bumpMap = materialParams.bumpMap === undefined ? null : materialParams.bumpMap;
2062
- material.bumpScale = 1;
2063
-
2064
- material.normalMap = materialParams.normalMap === undefined ? null : materialParams.normalMap;
2065
- material.normalMapType = TangentSpaceNormalMap;
2066
-
2067
- if ( materialParams.normalScale ) material.normalScale = materialParams.normalScale;
2068
-
2069
- material.displacementMap = null;
2070
- material.displacementScale = 1;
2071
- material.displacementBias = 0;
2072
-
2073
- material.specularMap = materialParams.specularMap === undefined ? null : materialParams.specularMap;
2074
- material.specular = materialParams.specular;
2075
-
2076
- material.glossinessMap = materialParams.glossinessMap === undefined ? null : materialParams.glossinessMap;
2077
- material.glossiness = materialParams.glossiness;
2078
-
2079
- material.alphaMap = null;
2080
-
2081
- material.envMap = materialParams.envMap === undefined ? null : materialParams.envMap;
2082
- material.envMapIntensity = 1.0;
2083
-
2084
- return material;
2085
-
2086
- }
2087
-
2088
- }
2089
-
2090
1768
  /**
2091
1769
  * Mesh Quantization Extension
2092
1770
  *
@@ -2554,6 +2232,8 @@ function getImageURIMimeType( uri ) {
2554
2232
 
2555
2233
  }
2556
2234
 
2235
+ const _identityMatrix = new Matrix4();
2236
+
2557
2237
  /* GLTF PARSER */
2558
2238
 
2559
2239
  class GLTFParser {
@@ -2588,9 +2268,17 @@ class GLTFParser {
2588
2268
  // Use an ImageBitmapLoader if imageBitmaps are supported. Moves much of the
2589
2269
  // expensive work of uploading a texture to the GPU off the main thread.
2590
2270
 
2591
- const isSafari = /^((?!chrome|android).)*safari/i.test( navigator.userAgent ) === true;
2592
- const isFirefox = navigator.userAgent.indexOf( 'Firefox' ) > - 1;
2593
- const firefoxVersion = isFirefox ? navigator.userAgent.match( /Firefox\/([0-9]+)\./ )[ 1 ] : - 1;
2271
+ let isSafari = false;
2272
+ let isFirefox = false;
2273
+ let firefoxVersion = - 1;
2274
+
2275
+ if ( typeof navigator !== 'undefined' ) {
2276
+
2277
+ isSafari = /^((?!chrome|android).)*safari/i.test( navigator.userAgent ) === true;
2278
+ isFirefox = navigator.userAgent.indexOf( 'Firefox' ) > - 1;
2279
+ firefoxVersion = isFirefox ? navigator.userAgent.match( /Firefox\/([0-9]+)\./ )[ 1 ] : - 1;
2280
+
2281
+ }
2594
2282
 
2595
2283
  if ( typeof createImageBitmap === 'undefined' || isSafari || ( isFirefox && firefoxVersion < 98 ) ) {
2596
2284
 
@@ -2855,7 +2543,11 @@ class GLTFParser {
2855
2543
  break;
2856
2544
 
2857
2545
  case 'node':
2858
- dependency = this.loadNode( index );
2546
+ dependency = this._invokeOne( function ( ext ) {
2547
+
2548
+ return ext.loadNode && ext.loadNode( index );
2549
+
2550
+ } );
2859
2551
  break;
2860
2552
 
2861
2553
  case 'mesh':
@@ -2915,7 +2607,19 @@ class GLTFParser {
2915
2607
  break;
2916
2608
 
2917
2609
  default:
2918
- throw new Error( 'Unknown type: ' + type );
2610
+ dependency = this._invokeOne( function ( ext ) {
2611
+
2612
+ return ext != this && ext.getDependency && ext.getDependency( type, index );
2613
+
2614
+ } );
2615
+
2616
+ if ( ! dependency ) {
2617
+
2618
+ throw new Error( 'Unknown type: ' + type );
2619
+
2620
+ }
2621
+
2622
+ break;
2919
2623
 
2920
2624
  }
2921
2625
 
@@ -3025,10 +2729,12 @@ class GLTFParser {
3025
2729
 
3026
2730
  if ( accessorDef.bufferView === undefined && accessorDef.sparse === undefined ) {
3027
2731
 
3028
- // Ignore empty accessors, which may be used to declare runtime
3029
- // information about attributes coming from another source (e.g. Draco
3030
- // compression extension).
3031
- return Promise.resolve( null );
2732
+ const itemSize = WEBGL_TYPE_SIZES[ accessorDef.type ];
2733
+ const TypedArray = WEBGL_COMPONENT_TYPES[ accessorDef.componentType ];
2734
+ const normalized = accessorDef.normalized === true;
2735
+
2736
+ const array = new TypedArray( accessorDef.count * itemSize );
2737
+ return Promise.resolve( new BufferAttribute( array, itemSize, normalized ) );
3032
2738
 
3033
2739
  }
3034
2740
 
@@ -3146,7 +2852,7 @@ class GLTFParser {
3146
2852
  /**
3147
2853
  * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#textures
3148
2854
  * @param {number} textureIndex
3149
- * @return {Promise<THREE.Texture>}
2855
+ * @return {Promise<THREE.Texture|null>}
3150
2856
  */
3151
2857
  loadTexture( textureIndex ) {
3152
2858
 
@@ -3316,6 +3022,8 @@ class GLTFParser {
3316
3022
 
3317
3023
  return this.getDependency( 'texture', mapDef.index ).then( function ( texture ) {
3318
3024
 
3025
+ if ( ! texture ) return null;
3026
+
3319
3027
  // Materials sample aoMap from UV set 1 and other maps from UV set 0 - this can't be configured
3320
3028
  // However, we will copy UV set 0 to UV set 1 on demand for aoMap
3321
3029
  if ( mapDef.texCoord !== undefined && mapDef.texCoord != 0 && ! ( mapName === 'aoMap' && mapDef.texCoord == 1 ) ) {
@@ -3414,7 +3122,6 @@ class GLTFParser {
3414
3122
 
3415
3123
  let cacheKey = 'ClonedMaterial:' + material.uuid + ':';
3416
3124
 
3417
- if ( material.isGLTFSpecularGlossinessMaterial ) cacheKey += 'specular-glossiness:';
3418
3125
  if ( useDerivativeTangents ) cacheKey += 'derivative-tangents:';
3419
3126
  if ( useVertexColors ) cacheKey += 'vertex-colors:';
3420
3127
  if ( useFlatShading ) cacheKey += 'flat-shading:';
@@ -3482,13 +3189,7 @@ class GLTFParser {
3482
3189
 
3483
3190
  const pending = [];
3484
3191
 
3485
- if ( materialExtensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ] ) {
3486
-
3487
- const sgExtension = extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ];
3488
- materialType = sgExtension.getMaterialType();
3489
- pending.push( sgExtension.extendParams( materialParams, materialDef, parser ) );
3490
-
3491
- } else if ( materialExtensions[ EXTENSIONS.KHR_MATERIALS_UNLIT ] ) {
3192
+ if ( materialExtensions[ EXTENSIONS.KHR_MATERIALS_UNLIT ] ) {
3492
3193
 
3493
3194
  const kmuExtension = extensions[ EXTENSIONS.KHR_MATERIALS_UNLIT ];
3494
3195
  materialType = kmuExtension.getMaterialType();
@@ -3612,17 +3313,7 @@ class GLTFParser {
3612
3313
 
3613
3314
  return Promise.all( pending ).then( function () {
3614
3315
 
3615
- let material;
3616
-
3617
- if ( materialType === GLTFMeshStandardSGMaterial ) {
3618
-
3619
- material = extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ].createMaterial( materialParams );
3620
-
3621
- } else {
3622
-
3623
- material = new materialType( materialParams );
3624
-
3625
- }
3316
+ const material = new materialType( materialParams );
3626
3317
 
3627
3318
  if ( materialDef.name ) material.name = materialDef.name;
3628
3319
 
@@ -3911,25 +3602,65 @@ class GLTFParser {
3911
3602
  /**
3912
3603
  * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins
3913
3604
  * @param {number} skinIndex
3914
- * @return {Promise<Object>}
3605
+ * @return {Promise<Skeleton>}
3915
3606
  */
3916
3607
  loadSkin( skinIndex ) {
3917
3608
 
3918
3609
  const skinDef = this.json.skins[ skinIndex ];
3919
3610
 
3920
- const skinEntry = { joints: skinDef.joints };
3611
+ const pending = [];
3921
3612
 
3922
- if ( skinDef.inverseBindMatrices === undefined ) {
3613
+ for ( let i = 0, il = skinDef.joints.length; i < il; i ++ ) {
3923
3614
 
3924
- return Promise.resolve( skinEntry );
3615
+ pending.push( this.getDependency( 'node', skinDef.joints[ i ] ) );
3925
3616
 
3926
3617
  }
3927
3618
 
3928
- return this.getDependency( 'accessor', skinDef.inverseBindMatrices ).then( function ( accessor ) {
3619
+ if ( skinDef.inverseBindMatrices !== undefined ) {
3620
+
3621
+ pending.push( this.getDependency( 'accessor', skinDef.inverseBindMatrices ) );
3622
+
3623
+ } else {
3624
+
3625
+ pending.push( null );
3626
+
3627
+ }
3628
+
3629
+ return Promise.all( pending ).then( function ( results ) {
3630
+
3631
+ const inverseBindMatrices = results.pop();
3632
+ const jointNodes = results;
3633
+
3634
+ const bones = [];
3635
+ const boneInverses = [];
3929
3636
 
3930
- skinEntry.inverseBindMatrices = accessor;
3637
+ for ( let i = 0, il = jointNodes.length; i < il; i ++ ) {
3638
+
3639
+ const jointNode = jointNodes[ i ];
3640
+
3641
+ if ( jointNode ) {
3642
+
3643
+ bones.push( jointNode );
3644
+
3645
+ const mat = new Matrix4();
3646
+
3647
+ if ( inverseBindMatrices !== null ) {
3648
+
3649
+ mat.fromArray( inverseBindMatrices.array, i * 16 );
3650
+
3651
+ }
3652
+
3653
+ boneInverses.push( mat );
3654
+
3655
+ } else {
3931
3656
 
3932
- return skinEntry;
3657
+ console.warn( 'THREE.GLTFLoader: Joint "%s" could not be found.', skinDef.joints[ i ] );
3658
+
3659
+ }
3660
+
3661
+ }
3662
+
3663
+ return new Skeleton( bones, boneInverses );
3933
3664
 
3934
3665
  } );
3935
3666
 
@@ -4159,7 +3890,7 @@ class GLTFParser {
4159
3890
 
4160
3891
  return ( function () {
4161
3892
 
4162
- const pending = [];
3893
+ const objectPending = [];
4163
3894
 
4164
3895
  const meshPromise = parser._invokeOne( function ( ext ) {
4165
3896
 
@@ -4169,13 +3900,13 @@ class GLTFParser {
4169
3900
 
4170
3901
  if ( meshPromise ) {
4171
3902
 
4172
- pending.push( meshPromise );
3903
+ objectPending.push( meshPromise );
4173
3904
 
4174
3905
  }
4175
3906
 
4176
3907
  if ( nodeDef.camera !== undefined ) {
4177
3908
 
4178
- pending.push( parser.getDependency( 'camera', nodeDef.camera ).then( function ( camera ) {
3909
+ objectPending.push( parser.getDependency( 'camera', nodeDef.camera ).then( function ( camera ) {
4179
3910
 
4180
3911
  return parser._getNodeRef( parser.cameraCache, nodeDef.camera, camera );
4181
3912
 
@@ -4189,13 +3920,34 @@ class GLTFParser {
4189
3920
 
4190
3921
  } ).forEach( function ( promise ) {
4191
3922
 
4192
- pending.push( promise );
3923
+ objectPending.push( promise );
4193
3924
 
4194
3925
  } );
4195
3926
 
4196
- return Promise.all( pending );
3927
+ const childPending = [];
3928
+ const childrenDef = nodeDef.children || [];
3929
+
3930
+ for ( let i = 0, il = childrenDef.length; i < il; i ++ ) {
4197
3931
 
4198
- }() ).then( function ( objects ) {
3932
+ childPending.push( parser.getDependency( 'node', childrenDef[ i ] ) );
3933
+
3934
+ }
3935
+
3936
+ const skeletonPending = nodeDef.skin === undefined
3937
+ ? Promise.resolve( null )
3938
+ : parser.getDependency( 'skin', nodeDef.skin );
3939
+
3940
+ return Promise.all( [
3941
+ Promise.all( objectPending ),
3942
+ Promise.all( childPending ),
3943
+ skeletonPending
3944
+ ] );
3945
+
3946
+ }() ).then( function ( results ) {
3947
+
3948
+ const objects = results[ 0 ];
3949
+ const children = results[ 1 ];
3950
+ const skeleton = results[ 2 ];
4199
3951
 
4200
3952
  let node;
4201
3953
 
@@ -4275,6 +4027,26 @@ class GLTFParser {
4275
4027
 
4276
4028
  parser.associations.get( node ).nodes = nodeIndex;
4277
4029
 
4030
+ if ( skeleton !== null ) {
4031
+
4032
+ // This full traverse should be fine because
4033
+ // child glTF nodes have not been added to this node yet.
4034
+ node.traverse( function ( mesh ) {
4035
+
4036
+ if ( ! mesh.isSkinnedMesh ) return;
4037
+
4038
+ mesh.bind( skeleton, _identityMatrix );
4039
+
4040
+ } );
4041
+
4042
+ }
4043
+
4044
+ for ( let i = 0, il = children.length; i < il; i ++ ) {
4045
+
4046
+ node.add( children[ i ] );
4047
+
4048
+ }
4049
+
4278
4050
  return node;
4279
4051
 
4280
4052
  } );
@@ -4288,7 +4060,6 @@ class GLTFParser {
4288
4060
  */
4289
4061
  loadScene( sceneIndex ) {
4290
4062
 
4291
- const json = this.json;
4292
4063
  const extensions = this.extensions;
4293
4064
  const sceneDef = this.json.scenes[ sceneIndex ];
4294
4065
  const parser = this;
@@ -4308,11 +4079,17 @@ class GLTFParser {
4308
4079
 
4309
4080
  for ( let i = 0, il = nodeIds.length; i < il; i ++ ) {
4310
4081
 
4311
- pending.push( buildNodeHierarchy( nodeIds[ i ], scene, json, parser ) );
4082
+ pending.push( parser.getDependency( 'node', nodeIds[ i ] ) );
4312
4083
 
4313
4084
  }
4314
4085
 
4315
- return Promise.all( pending ).then( function () {
4086
+ return Promise.all( pending ).then( function ( nodes ) {
4087
+
4088
+ for ( let i = 0, il = nodes.length; i < il; i ++ ) {
4089
+
4090
+ scene.add( nodes[ i ] );
4091
+
4092
+ }
4316
4093
 
4317
4094
  // Removes dangling associations, associations that reference a node that
4318
4095
  // didn't make it into the scene.
@@ -4356,102 +4133,6 @@ class GLTFParser {
4356
4133
 
4357
4134
  }
4358
4135
 
4359
- function buildNodeHierarchy( nodeId, parentObject, json, parser ) {
4360
-
4361
- const nodeDef = json.nodes[ nodeId ];
4362
-
4363
- return parser.getDependency( 'node', nodeId ).then( function ( node ) {
4364
-
4365
- if ( nodeDef.skin === undefined ) return node;
4366
-
4367
- // build skeleton here as well
4368
-
4369
- let skinEntry;
4370
-
4371
- return parser.getDependency( 'skin', nodeDef.skin ).then( function ( skin ) {
4372
-
4373
- skinEntry = skin;
4374
-
4375
- const pendingJoints = [];
4376
-
4377
- for ( let i = 0, il = skinEntry.joints.length; i < il; i ++ ) {
4378
-
4379
- pendingJoints.push( parser.getDependency( 'node', skinEntry.joints[ i ] ) );
4380
-
4381
- }
4382
-
4383
- return Promise.all( pendingJoints );
4384
-
4385
- } ).then( function ( jointNodes ) {
4386
-
4387
- node.traverse( function ( mesh ) {
4388
-
4389
- if ( ! mesh.isMesh ) return;
4390
-
4391
- const bones = [];
4392
- const boneInverses = [];
4393
-
4394
- for ( let j = 0, jl = jointNodes.length; j < jl; j ++ ) {
4395
-
4396
- const jointNode = jointNodes[ j ];
4397
-
4398
- if ( jointNode ) {
4399
-
4400
- bones.push( jointNode );
4401
-
4402
- const mat = new Matrix4();
4403
-
4404
- if ( skinEntry.inverseBindMatrices !== undefined ) {
4405
-
4406
- mat.fromArray( skinEntry.inverseBindMatrices.array, j * 16 );
4407
-
4408
- }
4409
-
4410
- boneInverses.push( mat );
4411
-
4412
- } else {
4413
-
4414
- console.warn( 'THREE.GLTFLoader: Joint "%s" could not be found.', skinEntry.joints[ j ] );
4415
-
4416
- }
4417
-
4418
- }
4419
-
4420
- mesh.bind( new Skeleton( bones, boneInverses ), mesh.matrixWorld );
4421
-
4422
- } );
4423
-
4424
- return node;
4425
-
4426
- } );
4427
-
4428
- } ).then( function ( node ) {
4429
-
4430
- // build node hierachy
4431
-
4432
- parentObject.add( node );
4433
-
4434
- const pending = [];
4435
-
4436
- if ( nodeDef.children ) {
4437
-
4438
- const children = nodeDef.children;
4439
-
4440
- for ( let i = 0, il = children.length; i < il; i ++ ) {
4441
-
4442
- const child = children[ i ];
4443
- pending.push( buildNodeHierarchy( child, node, json, parser ) );
4444
-
4445
- }
4446
-
4447
- }
4448
-
4449
- return Promise.all( pending );
4450
-
4451
- } );
4452
-
4453
- }
4454
-
4455
4136
  /**
4456
4137
  * @param {BufferGeometry} geometry
4457
4138
  * @param {GLTF.Primitive} primitiveDef
@@ -4627,98 +4308,4 @@ function addPrimitiveAttributes( geometry, primitiveDef, parser ) {
4627
4308
 
4628
4309
  }
4629
4310
 
4630
- /**
4631
- * @param {BufferGeometry} geometry
4632
- * @param {Number} drawMode
4633
- * @return {BufferGeometry}
4634
- */
4635
- function toTrianglesDrawMode( geometry, drawMode ) {
4636
-
4637
- let index = geometry.getIndex();
4638
-
4639
- // generate index if not present
4640
-
4641
- if ( index === null ) {
4642
-
4643
- const indices = [];
4644
-
4645
- const position = geometry.getAttribute( 'position' );
4646
-
4647
- if ( position !== undefined ) {
4648
-
4649
- for ( let i = 0; i < position.count; i ++ ) {
4650
-
4651
- indices.push( i );
4652
-
4653
- }
4654
-
4655
- geometry.setIndex( indices );
4656
- index = geometry.getIndex();
4657
-
4658
- } else {
4659
-
4660
- console.error( 'THREE.GLTFLoader.toTrianglesDrawMode(): Undefined position attribute. Processing not possible.' );
4661
- return geometry;
4662
-
4663
- }
4664
-
4665
- }
4666
-
4667
- //
4668
-
4669
- const numberOfTriangles = index.count - 2;
4670
- const newIndices = [];
4671
-
4672
- if ( drawMode === TriangleFanDrawMode ) {
4673
-
4674
- // gl.TRIANGLE_FAN
4675
-
4676
- for ( let i = 1; i <= numberOfTriangles; i ++ ) {
4677
-
4678
- newIndices.push( index.getX( 0 ) );
4679
- newIndices.push( index.getX( i ) );
4680
- newIndices.push( index.getX( i + 1 ) );
4681
-
4682
- }
4683
-
4684
- } else {
4685
-
4686
- // gl.TRIANGLE_STRIP
4687
-
4688
- for ( let i = 0; i < numberOfTriangles; i ++ ) {
4689
-
4690
- if ( i % 2 === 0 ) {
4691
-
4692
- newIndices.push( index.getX( i ) );
4693
- newIndices.push( index.getX( i + 1 ) );
4694
- newIndices.push( index.getX( i + 2 ) );
4695
-
4696
-
4697
- } else {
4698
-
4699
- newIndices.push( index.getX( i + 2 ) );
4700
- newIndices.push( index.getX( i + 1 ) );
4701
- newIndices.push( index.getX( i ) );
4702
-
4703
- }
4704
-
4705
- }
4706
-
4707
- }
4708
-
4709
- if ( ( newIndices.length / 3 ) !== numberOfTriangles ) {
4710
-
4711
- console.error( 'THREE.GLTFLoader.toTrianglesDrawMode(): Unable to generate correct amount of triangles.' );
4712
-
4713
- }
4714
-
4715
- // build final geometry
4716
-
4717
- const newGeometry = geometry.clone();
4718
- newGeometry.setIndex( newIndices );
4719
-
4720
- return newGeometry;
4721
-
4722
- }
4723
-
4724
4311
  export { GLTFLoader };
@@ -1225,6 +1225,112 @@ function mergeGroups( geometry ) {
1225
1225
 
1226
1226
  }
1227
1227
 
1228
+
1229
+ // Creates a new, non-indexed geometry with smooth normals everywhere except faces that meet at
1230
+ // an angle greater than the crease angle.
1231
+ function toCreasedNormals( geometry, creaseAngle = Math.PI / 3 /* 60 degrees */ ) {
1232
+
1233
+ const creaseDot = Math.cos( creaseAngle );
1234
+ const hashMultiplier = ( 1 + 1e-10 ) * 1e2;
1235
+
1236
+ // reusable vertors
1237
+ const verts = [ new Vector3(), new Vector3(), new Vector3() ];
1238
+ const tempVec1 = new Vector3();
1239
+ const tempVec2 = new Vector3();
1240
+ const tempNorm = new Vector3();
1241
+ const tempNorm2 = new Vector3();
1242
+
1243
+ // hashes a vector
1244
+ function hashVertex( v ) {
1245
+
1246
+ const x = ~ ~ ( v.x * hashMultiplier );
1247
+ const y = ~ ~ ( v.y * hashMultiplier );
1248
+ const z = ~ ~ ( v.z * hashMultiplier );
1249
+ return `${x},${y},${z}`;
1250
+
1251
+ }
1252
+
1253
+ const resultGeometry = geometry.toNonIndexed();
1254
+ const posAttr = resultGeometry.attributes.position;
1255
+ const vertexMap = {};
1256
+
1257
+ // find all the normals shared by commonly located vertices
1258
+ for ( let i = 0, l = posAttr.count / 3; i < l; i ++ ) {
1259
+
1260
+ const i3 = 3 * i;
1261
+ const a = verts[ 0 ].fromBufferAttribute( posAttr, i3 + 0 );
1262
+ const b = verts[ 1 ].fromBufferAttribute( posAttr, i3 + 1 );
1263
+ const c = verts[ 2 ].fromBufferAttribute( posAttr, i3 + 2 );
1264
+
1265
+ tempVec1.subVectors( c, b );
1266
+ tempVec2.subVectors( a, b );
1267
+
1268
+ // add the normal to the map for all vertices
1269
+ const normal = new Vector3().crossVectors( tempVec1, tempVec2 ).normalize();
1270
+ for ( let n = 0; n < 3; n ++ ) {
1271
+
1272
+ const vert = verts[ n ];
1273
+ const hash = hashVertex( vert );
1274
+ if ( ! ( hash in vertexMap ) ) {
1275
+
1276
+ vertexMap[ hash ] = [];
1277
+
1278
+ }
1279
+
1280
+ vertexMap[ hash ].push( normal );
1281
+
1282
+ }
1283
+
1284
+ }
1285
+
1286
+ // average normals from all vertices that share a common location if they are within the
1287
+ // provided crease threshold
1288
+ const normalArray = new Float32Array( posAttr.count * 3 );
1289
+ const normAttr = new BufferAttribute( normalArray, 3, false );
1290
+ for ( let i = 0, l = posAttr.count / 3; i < l; i ++ ) {
1291
+
1292
+ // get the face normal for this vertex
1293
+ const i3 = 3 * i;
1294
+ const a = verts[ 0 ].fromBufferAttribute( posAttr, i3 + 0 );
1295
+ const b = verts[ 1 ].fromBufferAttribute( posAttr, i3 + 1 );
1296
+ const c = verts[ 2 ].fromBufferAttribute( posAttr, i3 + 2 );
1297
+
1298
+ tempVec1.subVectors( c, b );
1299
+ tempVec2.subVectors( a, b );
1300
+
1301
+ tempNorm.crossVectors( tempVec1, tempVec2 ).normalize();
1302
+
1303
+ // average all normals that meet the threshold and set the normal value
1304
+ for ( let n = 0; n < 3; n ++ ) {
1305
+
1306
+ const vert = verts[ n ];
1307
+ const hash = hashVertex( vert );
1308
+ const otherNormals = vertexMap[ hash ];
1309
+ tempNorm2.set( 0, 0, 0 );
1310
+
1311
+ for ( let k = 0, lk = otherNormals.length; k < lk; k ++ ) {
1312
+
1313
+ const otherNorm = otherNormals[ k ];
1314
+ if ( tempNorm.dot( otherNorm ) > creaseDot ) {
1315
+
1316
+ tempNorm2.add( otherNorm );
1317
+
1318
+ }
1319
+
1320
+ }
1321
+
1322
+ tempNorm2.normalize();
1323
+ normAttr.setXYZ( i3 + n, tempNorm2.x, tempNorm2.y, tempNorm2.z );
1324
+
1325
+ }
1326
+
1327
+ }
1328
+
1329
+ resultGeometry.setAttribute( 'normal', normAttr );
1330
+ return resultGeometry;
1331
+
1332
+ }
1333
+
1228
1334
  export {
1229
1335
  computeTangents,
1230
1336
  computeMikkTSpaceTangents,
@@ -1235,5 +1341,6 @@ export {
1235
1341
  mergeVertices,
1236
1342
  toTrianglesDrawMode,
1237
1343
  computeMorphedAttributes,
1238
- mergeGroups
1344
+ mergeGroups,
1345
+ toCreasedNormals
1239
1346
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@damienmortini/three",
3
- "version": "0.1.181",
3
+ "version": "0.1.182",
4
4
  "description": "Three.js helpers",
5
5
  "scripts": {
6
6
  "install": "npm run copyexamples",
@@ -28,9 +28,9 @@
28
28
  "bugs": "https://github.com/damienmortini/lib/issues",
29
29
  "homepage": "https://github.com/damienmortini/lib/tree/main/packages/three",
30
30
  "dependencies": {
31
- "@damienmortini/core": "^0.2.142",
31
+ "@damienmortini/core": "^0.2.143",
32
32
  "fs-extra": "^11.1.0",
33
33
  "three": "0.149.0"
34
34
  },
35
- "gitHead": "3786e86afb461622bcd3c8c50c44bdd1fc10309e"
35
+ "gitHead": "9c39ac87a4d53c7be6b0c9cf128b892e4fd3abc3"
36
36
  }