|
@@ -1214,15 +1214,11 @@ THREE.GLTFLoader = ( function () {
|
|
|
/**
|
|
|
* Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#morph-targets
|
|
|
*
|
|
|
- * @param {THREE.Mesh} mesh
|
|
|
- * @param {GLTF.Mesh} meshDef
|
|
|
- * @param {GLTF.Primitive} primitiveDef
|
|
|
+ * @param {THREE.Geometry} geometry
|
|
|
+ * @param {Array<GLTF.Target>} targets
|
|
|
* @param {Array<THREE.BufferAttribute>} accessors
|
|
|
*/
|
|
|
- function addMorphTargets( mesh, meshDef, primitiveDef, accessors ) {
|
|
|
-
|
|
|
- var geometry = mesh.geometry;
|
|
|
- var targets = primitiveDef.targets;
|
|
|
+ function addMorphTargets( geometry, targets, accessors ) {
|
|
|
|
|
|
var hasMorphPosition = false;
|
|
|
var hasMorphNormal = false;
|
|
@@ -1330,6 +1326,14 @@ THREE.GLTFLoader = ( function () {
|
|
|
if ( hasMorphPosition ) geometry.morphAttributes.position = morphPositions;
|
|
|
if ( hasMorphNormal ) geometry.morphAttributes.normal = morphNormals;
|
|
|
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @param {THREE.Mesh} mesh
|
|
|
+ * @param {GLTF.Mesh} meshDef
|
|
|
+ */
|
|
|
+ function updateMorphTargets( mesh, meshDef ) {
|
|
|
+
|
|
|
mesh.updateMorphTargets();
|
|
|
|
|
|
if ( meshDef.weights !== undefined ) {
|
|
@@ -1375,26 +1379,31 @@ THREE.GLTFLoader = ( function () {
|
|
|
|
|
|
}
|
|
|
|
|
|
- var attribA = a.attributes || {};
|
|
|
- var attribB = b.attributes || {};
|
|
|
- var keysA = Object.keys( attribA );
|
|
|
- var keysB = Object.keys( attribB );
|
|
|
+ return isObjectEqual( a.attributes, b.attributes );
|
|
|
|
|
|
- if ( keysA.length !== keysB.length ) {
|
|
|
+ }
|
|
|
|
|
|
- return false;
|
|
|
+ function isObjectEqual( a, b ) {
|
|
|
+
|
|
|
+ if ( Object.keys( a ).length !== Object.keys( b ).length ) return false;
|
|
|
+
|
|
|
+ for ( var key in a ) {
|
|
|
+
|
|
|
+ if ( a[ key ] !== b[ key ] ) return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
- for ( var i = 0, il = keysA.length; i < il; i ++ ) {
|
|
|
+ return true;
|
|
|
|
|
|
- var key = keysA[ i ];
|
|
|
+ }
|
|
|
|
|
|
- if ( attribA[ key ] !== attribB[ key ] ) {
|
|
|
+ function isArrayEqual( a, b ) {
|
|
|
|
|
|
- return false;
|
|
|
+ if ( a.length !== b.length ) return false;
|
|
|
|
|
|
- }
|
|
|
+ for ( var i = 0, il = a.length; i < il; i ++ ) {
|
|
|
+
|
|
|
+ if ( a[ i ] !== b[ i ] ) return false;
|
|
|
|
|
|
}
|
|
|
|
|
@@ -1408,11 +1417,35 @@ THREE.GLTFLoader = ( function () {
|
|
|
|
|
|
var cached = cache[ i ];
|
|
|
|
|
|
- if ( isPrimitiveEqual( cached.primitive, newPrimitive ) ) {
|
|
|
+ if ( isPrimitiveEqual( cached.primitive, newPrimitive ) ) return cached.promise;
|
|
|
|
|
|
- return cached.promise;
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
+ return null;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ function getCachedCombinedGeometry( cache, geometries ) {
|
|
|
+
|
|
|
+ for ( var i = 0, il = cache.length; i < il; i ++ ) {
|
|
|
+
|
|
|
+ var cached = cache[ i ];
|
|
|
+
|
|
|
+ if ( isArrayEqual( geometries, cached.baseGeometries ) ) return cached.geometry;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ return null;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ function getCachedMultiPassGeometry( cache, geometry, primitives ) {
|
|
|
+
|
|
|
+ for ( var i = 0, il = cache.length; i < il; i ++ ) {
|
|
|
+
|
|
|
+ var cached = cache[ i ];
|
|
|
+
|
|
|
+ if ( geometry === cached.baseGeometry && isArrayEqual( primitives, cached.primitives ) ) return cached.geometry;
|
|
|
|
|
|
}
|
|
|
|
|
@@ -1445,6 +1478,47 @@ THREE.GLTFLoader = ( function () {
|
|
|
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Checks if we can build a single Mesh with MultiMaterial from multiple primitives.
|
|
|
+ * Returns true if all primitives use the same attributes/morphAttributes/mode
|
|
|
+ * and also have index. Otherwise returns false.
|
|
|
+ *
|
|
|
+ * @param {Array<GLTF.Primitive>} primitives
|
|
|
+ * @return {Boolean}
|
|
|
+ */
|
|
|
+ function isMultiPassGeometry( primitives ) {
|
|
|
+
|
|
|
+ if ( primitives.length < 2 ) return false;
|
|
|
+
|
|
|
+ var primitive0 = primitives[ 0 ];
|
|
|
+ var targets0 = primitive0.targets || [];
|
|
|
+
|
|
|
+ if ( primitive0.indices === undefined ) return false;
|
|
|
+
|
|
|
+ for ( var i = 1, il = primitives.length; i < il; i ++ ) {
|
|
|
+
|
|
|
+ var primitive = primitives[ i ];
|
|
|
+
|
|
|
+ if ( primitive0.mode !== primitive.mode ) return false;
|
|
|
+ if ( primitive.indices === undefined ) return false;
|
|
|
+ if ( ! isObjectEqual( primitive0.attributes, primitive.attributes ) ) return false;
|
|
|
+
|
|
|
+ var targets = primitive.targets || [];
|
|
|
+
|
|
|
+ if ( targets0.length !== targets.length ) return false;
|
|
|
+
|
|
|
+ for ( var j = 0, jl = targets0.length; j < jl; j ++ ) {
|
|
|
+
|
|
|
+ if ( ! isObjectEqual( targets0[ j ], targets[ j ] ) ) return false;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
/* GLTF PARSER */
|
|
|
|
|
|
function GLTFParser( json, extensions, options ) {
|
|
@@ -1458,6 +1532,8 @@ THREE.GLTFLoader = ( function () {
|
|
|
|
|
|
// BufferGeometry caching
|
|
|
this.primitiveCache = [];
|
|
|
+ this.multiplePrimitivesCache = [];
|
|
|
+ this.multiPassGeometryCache = []
|
|
|
|
|
|
this.textureLoader = new THREE.TextureLoader( this.options.manager );
|
|
|
this.textureLoader.setCrossOrigin( this.options.crossOrigin );
|
|
@@ -2183,7 +2259,7 @@ THREE.GLTFLoader = ( function () {
|
|
|
* @param {GLTF.Primitive} primitiveDef
|
|
|
* @param {Array<THREE.BufferAttribute>} accessors
|
|
|
*/
|
|
|
- function addPrimitiveAttributes ( geometry, primitiveDef, accessors ) {
|
|
|
+ function addPrimitiveAttributes( geometry, primitiveDef, accessors ) {
|
|
|
|
|
|
var attributes = primitiveDef.attributes;
|
|
|
|
|
@@ -2200,16 +2276,33 @@ THREE.GLTFLoader = ( function () {
|
|
|
|
|
|
}
|
|
|
|
|
|
- if ( primitiveDef.indices !== undefined && !geometry.index ) {
|
|
|
+ if ( primitiveDef.indices !== undefined && ! geometry.index ) {
|
|
|
|
|
|
geometry.setIndex( accessors[ primitiveDef.indices ] );
|
|
|
|
|
|
}
|
|
|
|
|
|
+ if ( primitiveDef.targets !== undefined ) {
|
|
|
+
|
|
|
+ addMorphTargets( geometry, primitiveDef.targets, accessors );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( primitiveDef.extras !== undefined ) {
|
|
|
+
|
|
|
+ geometry.userData = primitiveDef.extras;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#geometry
|
|
|
+ *
|
|
|
+ * Creates BufferGeometries from primitives.
|
|
|
+ * If we can build a single BufferGeometry with .groups from multiple primitives, returns one BufferGeometry.
|
|
|
+ * Otherwise, returns BufferGeometries without .groups as many as primitives.
|
|
|
+ *
|
|
|
* @param {Array<Object>} primitives
|
|
|
* @return {Promise<Array<THREE.BufferGeometry>>}
|
|
|
*/
|
|
@@ -2219,6 +2312,22 @@ THREE.GLTFLoader = ( function () {
|
|
|
var extensions = this.extensions;
|
|
|
var cache = this.primitiveCache;
|
|
|
|
|
|
+ var isMultiPass = isMultiPassGeometry( primitives );
|
|
|
+ var originalPrimitives;
|
|
|
+
|
|
|
+ if ( isMultiPass ) {
|
|
|
+
|
|
|
+ originalPrimitives = primitives; // save original primitives and use later
|
|
|
+
|
|
|
+ // We build a single BufferGeometry with .groups from multiple primitives
|
|
|
+ // because all primitives share the same attributes/morph/mode and have indices.
|
|
|
+
|
|
|
+ primitives = [ primitives[ 0 ] ];
|
|
|
+
|
|
|
+ // Sets .groups and combined indices to a geometry later in this method.
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
return this.getDependencies( 'accessor' ).then( function ( accessors ) {
|
|
|
|
|
|
var pending = [];
|
|
@@ -2262,12 +2371,7 @@ THREE.GLTFLoader = ( function () {
|
|
|
var geometryPromise = Promise.resolve( geometry );
|
|
|
|
|
|
// Cache this geometry
|
|
|
- cache.push( {
|
|
|
-
|
|
|
- primitive: primitive,
|
|
|
- promise: geometryPromise
|
|
|
-
|
|
|
- } );
|
|
|
+ cache.push( { primitive: primitive, promise: geometryPromise } );
|
|
|
|
|
|
pending.push( geometryPromise );
|
|
|
|
|
@@ -2275,7 +2379,83 @@ THREE.GLTFLoader = ( function () {
|
|
|
|
|
|
}
|
|
|
|
|
|
- return Promise.all( pending );
|
|
|
+ return Promise.all( pending ).then( function ( geometries ) {
|
|
|
+
|
|
|
+ if ( isMultiPass ) {
|
|
|
+
|
|
|
+ var baseGeometry = geometries[ 0 ];
|
|
|
+
|
|
|
+ // See if we've already created this combined geometry
|
|
|
+ var cache = parser.multiPassGeometryCache;
|
|
|
+ var cached = getCachedMultiPassGeometry( cache, baseGeometry, originalPrimitives );
|
|
|
+
|
|
|
+ if ( cached !== null ) return [ cached.geometry ];
|
|
|
+
|
|
|
+ // Cloning geometry because of index override.
|
|
|
+ // Attributes can be reused so cloning by myself here.
|
|
|
+ var geometry = new THREE.BufferGeometry();
|
|
|
+
|
|
|
+ geometry.name = baseGeometry.name;
|
|
|
+ geometry.userData = baseGeometry.userData;
|
|
|
+
|
|
|
+ for ( var key in baseGeometry.attributes ) geometry.addAttribute( key, baseGeometry.attributes[ key ] );
|
|
|
+ for ( var key in baseGeometry.morphAttributes ) geometry.morphAttributes[ key ] = baseGeometry.morphAttributes[ key ];
|
|
|
+
|
|
|
+ var indices = [];
|
|
|
+ var offset = 0;
|
|
|
+
|
|
|
+ for ( var i = 0, il = originalPrimitives.length; i < il; i ++ ) {
|
|
|
+
|
|
|
+ var accessor = accessors[ originalPrimitives[ i ].indices ];
|
|
|
+
|
|
|
+ for ( var j = 0, jl = accessor.count; j < jl; j ++ ) indices.push( accessor.array[ j ] );
|
|
|
+
|
|
|
+ geometry.addGroup( offset, accessor.count, i );
|
|
|
+
|
|
|
+ offset += accessor.count;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ geometry.setIndex( indices );
|
|
|
+
|
|
|
+ cache.push( { geometry: geometry, baseGeometry: baseGeometry, primitives: originalPrimitives } );
|
|
|
+
|
|
|
+ return [ geometry ];
|
|
|
+
|
|
|
+ } else if ( geometries.length > 1 && THREE.BufferGeometryUtils !== undefined ) {
|
|
|
+
|
|
|
+ // Tries to merge geometries with BufferGeometryUtils if possible
|
|
|
+
|
|
|
+ for ( var i = 1, il = primitives.length; i < il; i ++ ) {
|
|
|
+
|
|
|
+ // can't merge if draw mode is different
|
|
|
+ if ( primitives[ 0 ].mode !== primitives[ i ].mode ) return geometries;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ // See if we've already created this combined geometry
|
|
|
+ var cache = parser.multiplePrimitivesCache;
|
|
|
+ var cached = getCachedCombinedGeometry( cache, geometries );
|
|
|
+
|
|
|
+ if ( cached ) {
|
|
|
+
|
|
|
+ if ( cached.geometry !== null ) return [ cached.geometry ];
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ var geometry = THREE.BufferGeometryUtils.mergeBufferGeometries( geometries, true );
|
|
|
+
|
|
|
+ cache.push( { geometry: geometry, baseGeometries: geometries } );
|
|
|
+
|
|
|
+ if ( geometry !== null ) return [ geometry ];
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ return geometries;
|
|
|
+
|
|
|
+ } );
|
|
|
|
|
|
} );
|
|
|
|
|
@@ -2301,188 +2481,220 @@ THREE.GLTFLoader = ( function () {
|
|
|
|
|
|
] ).then( function ( dependencies ) {
|
|
|
|
|
|
- var group = new THREE.Group();
|
|
|
-
|
|
|
var primitives = meshDef.primitives;
|
|
|
+ var originalMaterials = [];
|
|
|
+
|
|
|
+ for ( var i = 0, il = primitives.length; i < il; i ++ ) {
|
|
|
+
|
|
|
+ originalMaterials[ i ] = primitives[ i ].material === undefined
|
|
|
+ ? createDefaultMaterial()
|
|
|
+ : dependencies.materials[ primitives[ i ].material ];
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
return scope.loadGeometries( primitives ).then( function ( geometries ) {
|
|
|
|
|
|
- for ( var i = 0, il = primitives.length; i < il; i ++ ) {
|
|
|
+ var isMultiMaterial = geometries.length === 1 && geometries[ 0 ].groups.length > 0;
|
|
|
|
|
|
- var primitive = primitives[ i ];
|
|
|
- var geometry = geometries[ i ];
|
|
|
+ var meshes = [];
|
|
|
|
|
|
- var material = primitive.material === undefined
|
|
|
- ? createDefaultMaterial()
|
|
|
- : dependencies.materials[ primitive.material ];
|
|
|
+ for ( var i = 0, il = geometries.length; i < il; i ++ ) {
|
|
|
|
|
|
- if ( material.aoMap
|
|
|
- && geometry.attributes.uv2 === undefined
|
|
|
- && geometry.attributes.uv !== undefined ) {
|
|
|
+ var geometry = geometries[ i ];
|
|
|
+ var primitive = primitives[ i ];
|
|
|
|
|
|
- console.log( 'THREE.GLTFLoader: Duplicating UVs to support aoMap.' );
|
|
|
- geometry.addAttribute( 'uv2', new THREE.BufferAttribute( geometry.attributes.uv.array, 2 ) );
|
|
|
+ // 1. create Mesh
|
|
|
|
|
|
- }
|
|
|
+ var mesh;
|
|
|
|
|
|
- // If the material will be modified later on, clone it now.
|
|
|
- var useVertexColors = geometry.attributes.color !== undefined;
|
|
|
- var useFlatShading = geometry.attributes.normal === undefined;
|
|
|
- var useSkinning = meshDef.isSkinnedMesh === true;
|
|
|
- var useMorphTargets = primitive.targets !== undefined;
|
|
|
+ var material = isMultiMaterial ? originalMaterials : originalMaterials[ i ]
|
|
|
|
|
|
- if ( useVertexColors || useFlatShading || useSkinning || useMorphTargets ) {
|
|
|
+ if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLES ||
|
|
|
+ primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP ||
|
|
|
+ primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN ||
|
|
|
+ primitive.mode === undefined ) {
|
|
|
|
|
|
- if ( material.isGLTFSpecularGlossinessMaterial ) {
|
|
|
+ // .isSkinnedMesh isn't in glTF spec. See .markDefs()
|
|
|
+ mesh = meshDef.isSkinnedMesh === true
|
|
|
+ ? new THREE.SkinnedMesh( geometry, material )
|
|
|
+ : new THREE.Mesh( geometry, material );
|
|
|
|
|
|
- var specGlossExtension = extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ];
|
|
|
- material = specGlossExtension.cloneMaterial( material );
|
|
|
+ if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP ) {
|
|
|
|
|
|
- } else {
|
|
|
+ mesh.drawMode = THREE.TriangleStripDrawMode;
|
|
|
|
|
|
- material = material.clone();
|
|
|
+ } else if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN ) {
|
|
|
+
|
|
|
+ mesh.drawMode = THREE.TriangleFanDrawMode;
|
|
|
|
|
|
}
|
|
|
|
|
|
- }
|
|
|
+ } else if ( primitive.mode === WEBGL_CONSTANTS.LINES ) {
|
|
|
+
|
|
|
+ mesh = new THREE.LineSegments( geometry, material );
|
|
|
+
|
|
|
+ } else if ( primitive.mode === WEBGL_CONSTANTS.LINE_STRIP ) {
|
|
|
+
|
|
|
+ mesh = new THREE.Line( geometry, material );
|
|
|
+
|
|
|
+ } else if ( primitive.mode === WEBGL_CONSTANTS.LINE_LOOP ) {
|
|
|
+
|
|
|
+ mesh = new THREE.LineLoop( geometry, material );
|
|
|
+
|
|
|
+ } else if ( primitive.mode === WEBGL_CONSTANTS.POINTS ) {
|
|
|
+
|
|
|
+ mesh = new THREE.Points( geometry, material );
|
|
|
|
|
|
- if ( useVertexColors ) {
|
|
|
+ } else {
|
|
|
|
|
|
- material.vertexColors = THREE.VertexColors;
|
|
|
- material.needsUpdate = true;
|
|
|
+ throw new Error( 'THREE.GLTFLoader: Primitive mode unsupported: ' + primitive.mode );
|
|
|
|
|
|
}
|
|
|
|
|
|
- if ( useFlatShading ) {
|
|
|
+ if ( Object.keys( mesh.geometry.morphAttributes ).length > 0 ) {
|
|
|
|
|
|
- material.flatShading = true;
|
|
|
+ updateMorphTargets( mesh, meshDef );
|
|
|
|
|
|
}
|
|
|
|
|
|
- var mesh;
|
|
|
+ mesh.name = meshDef.name || ( 'mesh_' + meshIndex );
|
|
|
|
|
|
- if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLES ||
|
|
|
- primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP ||
|
|
|
- primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN ||
|
|
|
- primitive.mode === undefined ) {
|
|
|
+ if ( geometries.length > 1 ) mesh.name += '_' + i;
|
|
|
|
|
|
- if ( useSkinning ) {
|
|
|
+ if ( meshDef.extras !== undefined ) mesh.userData = meshDef.extras;
|
|
|
|
|
|
- mesh = new THREE.SkinnedMesh( geometry, material );
|
|
|
- material.skinning = true;
|
|
|
+ meshes.push( mesh );
|
|
|
|
|
|
- } else {
|
|
|
+ // 2. update Material depending on Mesh and BufferGeometry
|
|
|
|
|
|
- mesh = new THREE.Mesh( geometry, material );
|
|
|
+ var materials = isMultiMaterial ? mesh.material : [ mesh.material ];
|
|
|
|
|
|
- }
|
|
|
+ var useVertexColors = geometry.attributes.color !== undefined;
|
|
|
+ var useFlatShading = geometry.attributes.normal === undefined;
|
|
|
+ var useSkinning = mesh.isSkinnedMesh === true;
|
|
|
+ var useMorphTargets = Object.keys( geometry.morphAttributes ).length > 0;
|
|
|
+ var useMorphNormals = useMorphTargets && geometry.morphAttributes.normal !== undefined;
|
|
|
|
|
|
- if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP ) {
|
|
|
+ for ( var j = 0, jl = materials.length; j < jl; j ++ ) {
|
|
|
|
|
|
- mesh.drawMode = THREE.TriangleStripDrawMode;
|
|
|
+ var material = materials[ j ];
|
|
|
|
|
|
- } else if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN ) {
|
|
|
+ if ( mesh.isPoints ) {
|
|
|
|
|
|
- mesh.drawMode = THREE.TriangleFanDrawMode;
|
|
|
+ var cacheKey = 'PointsMaterial:' + material.uuid;
|
|
|
|
|
|
- }
|
|
|
+ var pointsMaterial = scope.cache.get( cacheKey );
|
|
|
|
|
|
- } else if ( primitive.mode === WEBGL_CONSTANTS.LINES ||
|
|
|
- primitive.mode === WEBGL_CONSTANTS.LINE_STRIP ||
|
|
|
- primitive.mode === WEBGL_CONSTANTS.LINE_LOOP ) {
|
|
|
+ if ( ! pointsMaterial ) {
|
|
|
|
|
|
- var cacheKey = 'LineBasicMaterial:' + material.uuid;
|
|
|
+ pointsMaterial = new THREE.PointsMaterial();
|
|
|
+ THREE.Material.prototype.copy.call( pointsMaterial, material );
|
|
|
+ pointsMaterial.color.copy( material.color );
|
|
|
+ pointsMaterial.map = material.map;
|
|
|
+ pointsMaterial.lights = false; // PointsMaterial doesn't support lights yet
|
|
|
|
|
|
- var lineMaterial = scope.cache.get( cacheKey );
|
|
|
+ scope.cache.add( cacheKey, pointsMaterial );
|
|
|
|
|
|
- if ( ! lineMaterial ) {
|
|
|
+ }
|
|
|
|
|
|
- lineMaterial = new THREE.LineBasicMaterial();
|
|
|
- THREE.Material.prototype.copy.call( lineMaterial, material );
|
|
|
- lineMaterial.color.copy( material.color );
|
|
|
- lineMaterial.lights = false; // LineBasicMaterial doesn't support lights yet
|
|
|
+ material = pointsMaterial;
|
|
|
|
|
|
- scope.cache.add( cacheKey, lineMaterial );
|
|
|
+ } else if ( mesh.isLine ) {
|
|
|
|
|
|
- }
|
|
|
+ var cacheKey = 'LineBasicMaterial:' + material.uuid;
|
|
|
|
|
|
- material = lineMaterial;
|
|
|
+ var lineMaterial = scope.cache.get( cacheKey );
|
|
|
|
|
|
- if ( primitive.mode === WEBGL_CONSTANTS.LINES ) {
|
|
|
+ if ( ! lineMaterial ) {
|
|
|
|
|
|
- mesh = new THREE.LineSegments( geometry, material );
|
|
|
+ lineMaterial = new THREE.LineBasicMaterial();
|
|
|
+ THREE.Material.prototype.copy.call( lineMaterial, material );
|
|
|
+ lineMaterial.color.copy( material.color );
|
|
|
+ lineMaterial.lights = false; // LineBasicMaterial doesn't support lights yet
|
|
|
|
|
|
- } else if ( primitive.mode === WEBGL_CONSTANTS.LINE_STRIP ) {
|
|
|
+ scope.cache.add( cacheKey, lineMaterial );
|
|
|
|
|
|
- mesh = new THREE.Line( geometry, material );
|
|
|
+ }
|
|
|
|
|
|
- } else {
|
|
|
+ material = lineMaterial;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ // If the material will be modified later on, clone it now.
|
|
|
+ if ( useVertexColors || useFlatShading || useSkinning || useMorphTargets ) {
|
|
|
|
|
|
- mesh = new THREE.LineLoop( geometry, material );
|
|
|
+ material = material.isGLTFSpecularGlossinessMaterial
|
|
|
+ ? extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ].cloneMaterial( material )
|
|
|
+ : material.clone();
|
|
|
|
|
|
}
|
|
|
|
|
|
- } else if ( primitive.mode === WEBGL_CONSTANTS.POINTS ) {
|
|
|
+ if ( useSkinning ) {
|
|
|
|
|
|
- var cacheKey = 'PointsMaterial:' + material.uuid;
|
|
|
+ material.skinning = true;
|
|
|
|
|
|
- var pointsMaterial = scope.cache.get( cacheKey );
|
|
|
+ }
|
|
|
|
|
|
- if ( ! pointsMaterial ) {
|
|
|
+ if ( useVertexColors ) {
|
|
|
+
|
|
|
+ material.vertexColors = THREE.VertexColors;
|
|
|
+ material.needsUpdate = true;
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
- pointsMaterial = new THREE.PointsMaterial();
|
|
|
- THREE.Material.prototype.copy.call( pointsMaterial, material );
|
|
|
- pointsMaterial.color.copy( material.color );
|
|
|
- pointsMaterial.map = material.map;
|
|
|
- pointsMaterial.lights = false; // PointsMaterial doesn't support lights yet
|
|
|
+ if ( useFlatShading ) {
|
|
|
|
|
|
- scope.cache.add( cacheKey, pointsMaterial );
|
|
|
+ material.flatShading = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
- material = pointsMaterial;
|
|
|
+ if ( useMorphTargets ) {
|
|
|
|
|
|
- mesh = new THREE.Points( geometry, material );
|
|
|
+ material.morphTargets = true;
|
|
|
|
|
|
- } else {
|
|
|
+ }
|
|
|
|
|
|
- throw new Error( 'THREE.GLTFLoader: Primitive mode unsupported: ' + primitive.mode );
|
|
|
+ if ( useMorphNormals ) {
|
|
|
|
|
|
- }
|
|
|
+ material.morphNormals = true;
|
|
|
|
|
|
- mesh.name = meshDef.name || ( 'mesh_' + meshIndex );
|
|
|
+ }
|
|
|
|
|
|
- if ( useMorphTargets ) {
|
|
|
+ materials[ j ] = material;
|
|
|
|
|
|
- addMorphTargets( mesh, meshDef, primitive, dependencies.accessors );
|
|
|
+ // workarounds for mesh and geometry
|
|
|
|
|
|
- material.morphTargets = true;
|
|
|
+ if ( material.aoMap && geometry.attributes.uv2 === undefined && geometry.attributes.uv !== undefined ) {
|
|
|
|
|
|
- if ( mesh.geometry.morphAttributes.normal !== undefined ) material.morphNormals = true;
|
|
|
+ console.log( 'THREE.GLTFLoader: Duplicating UVs to support aoMap.' );
|
|
|
+ geometry.addAttribute( 'uv2', new THREE.BufferAttribute( geometry.attributes.uv.array, 2 ) );
|
|
|
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
- if ( meshDef.extras !== undefined ) mesh.userData = meshDef.extras;
|
|
|
- if ( primitive.extras !== undefined ) mesh.geometry.userData = primitive.extras;
|
|
|
+ if ( material.isGLTFSpecularGlossinessMaterial ) {
|
|
|
|
|
|
- // for Specular-Glossiness.
|
|
|
- if ( material.isGLTFSpecularGlossinessMaterial === true ) {
|
|
|
+ // for GLTFSpecularGlossinessMaterial(ShaderMaterial) uniforms runtime update
|
|
|
+ mesh.onBeforeRender = extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ].refreshUniforms;
|
|
|
|
|
|
- mesh.onBeforeRender = extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ].refreshUniforms;
|
|
|
+ }
|
|
|
|
|
|
}
|
|
|
|
|
|
- if ( primitives.length > 1 ) {
|
|
|
+ mesh.material = isMultiMaterial ? materials : materials[ 0 ];
|
|
|
|
|
|
- mesh.name += '_' + i;
|
|
|
+ }
|
|
|
|
|
|
- group.add( mesh );
|
|
|
+ if ( meshes.length === 1 ) {
|
|
|
|
|
|
- } else {
|
|
|
+ return meshes[ 0 ];
|
|
|
|
|
|
- return mesh;
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
+ var group = new THREE.Group();
|
|
|
+
|
|
|
+ for ( var i = 0, il = meshes.length; i < il; i ++ ) {
|
|
|
+
|
|
|
+ group.add( meshes[ i ] );
|
|
|
|
|
|
}
|
|
|
|
|
@@ -2726,6 +2938,7 @@ THREE.GLTFLoader = ( function () {
|
|
|
|
|
|
var node;
|
|
|
|
|
|
+ // .isBone isn't in glTF spec. See .markDefs
|
|
|
if ( nodeDef.isBone === true ) {
|
|
|
|
|
|
node = new THREE.Bone();
|