|
@@ -1197,6 +1197,59 @@ THREE.GLTFLoader = ( function () {
|
|
|
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * TODO(donmccurdy): Why is all this necessary, again?
|
|
|
+ * @param {GLTF.Node} nodeDef
|
|
|
+ * @param {THREE.Group} group
|
|
|
+ * @param {Array<THREE.Object3D>} nodes
|
|
|
+ * @param {Array<Object} skins
|
|
|
+ */
|
|
|
+ function deepCloneMeshGroup( group ) {
|
|
|
+
|
|
|
+ // Clone group's children manually.
|
|
|
+ var clonedGroup = group.clone( false );
|
|
|
+
|
|
|
+ for ( var i = 0; i < group.children.length; i ++ ) {
|
|
|
+
|
|
|
+ var child = group.children[ i ];
|
|
|
+ var clonedChild;
|
|
|
+
|
|
|
+ switch ( child.type ) {
|
|
|
+
|
|
|
+ case 'LineSegments':
|
|
|
+ clonedChild = new THREE.LineSegments( child.geometry, child.material );
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 'LineLoop':
|
|
|
+ clonedChild = new THREE.LineLoop( child.geometry, child.material );
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 'Line':
|
|
|
+ clonedChild = new THREE.Line( child.geometry, child.material );
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 'Points':
|
|
|
+ clonedChild = new THREE.Points( child.geometry, child.material );
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ clonedChild = new THREE.Mesh( child.geometry, child.material );
|
|
|
+ clonedChild.drawMode = child.drawMode;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ clonedChild.morphTargetInfluences = child.morphTargetInfluences;
|
|
|
+ clonedChild.userData = child.userData;
|
|
|
+ clonedChild.name = child.name;
|
|
|
+
|
|
|
+ clonedGroup.add( clonedChild );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ return clonedGroup;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
/* GLTF PARSER */
|
|
|
|
|
|
function GLTFParser( json, extensions, options ) {
|
|
@@ -2133,198 +2186,137 @@ THREE.GLTFLoader = ( function () {
|
|
|
|
|
|
} );
|
|
|
|
|
|
- return _each( json.nodes, function ( node ) {
|
|
|
-
|
|
|
- var matrix = new THREE.Matrix4();
|
|
|
+ return scope._withDependencies( [
|
|
|
|
|
|
- var _node = node.isBone === true ? new THREE.Bone() : new THREE.Object3D();
|
|
|
+ 'meshes',
|
|
|
+ 'skins',
|
|
|
+ 'cameras'
|
|
|
|
|
|
- if ( node.name !== undefined ) {
|
|
|
-
|
|
|
- _node.name = THREE.PropertyBinding.sanitizeNodeName( node.name );
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- if ( node.extras ) _node.userData = node.extras;
|
|
|
+ ] ).then( function ( dependencies ) {
|
|
|
|
|
|
- if ( node.matrix !== undefined ) {
|
|
|
+ return _each( json.nodes, function ( nodeDef ) {
|
|
|
|
|
|
- matrix.fromArray( node.matrix );
|
|
|
- _node.applyMatrix( matrix );
|
|
|
+ if ( nodeDef.isBone === true ) {
|
|
|
|
|
|
- } else {
|
|
|
+ return new THREE.Bone();
|
|
|
|
|
|
- if ( node.translation !== undefined ) {
|
|
|
+ } else if ( nodeDef.mesh !== undefined ) {
|
|
|
|
|
|
- _node.position.fromArray( node.translation );
|
|
|
+ return deepCloneMeshGroup( dependencies.meshes[ nodeDef.mesh ] );
|
|
|
|
|
|
- }
|
|
|
+ } else if ( nodeDef.camera !== undefined ) {
|
|
|
|
|
|
- if ( node.rotation !== undefined ) {
|
|
|
+ return dependencies.cameras[ nodeDef.camera ];
|
|
|
|
|
|
- _node.quaternion.fromArray( node.rotation );
|
|
|
+ } else if ( nodeDef.extensions
|
|
|
+ && nodeDef.extensions[ EXTENSIONS.KHR_LIGHTS ]
|
|
|
+ && nodeDef.extensions[ EXTENSIONS.KHR_LIGHTS ].light !== undefined ) {
|
|
|
|
|
|
- }
|
|
|
+ var lights = extensions[ EXTENSIONS.KHR_LIGHTS ].lights;
|
|
|
+ return lights[ nodeDef.extensions[ EXTENSIONS.KHR_LIGHTS ].light ];
|
|
|
|
|
|
- if ( node.scale !== undefined ) {
|
|
|
+ } else {
|
|
|
|
|
|
- _node.scale.fromArray( node.scale );
|
|
|
+ return new THREE.Object3D();
|
|
|
|
|
|
}
|
|
|
|
|
|
- }
|
|
|
-
|
|
|
- return _node;
|
|
|
-
|
|
|
- } ).then( function ( __nodes ) {
|
|
|
-
|
|
|
- return scope._withDependencies( [
|
|
|
-
|
|
|
- 'meshes',
|
|
|
- 'skins',
|
|
|
- 'cameras'
|
|
|
-
|
|
|
- ] ).then( function ( dependencies ) {
|
|
|
-
|
|
|
- return _each( __nodes, function ( _node, nodeId ) {
|
|
|
+ } ).then( function ( __nodes ) {
|
|
|
|
|
|
- var node = json.nodes[ nodeId ];
|
|
|
+ return _each( __nodes, function ( node, nodeIndex ) {
|
|
|
|
|
|
- var mesh = node.mesh;
|
|
|
+ var nodeDef = json.nodes[ nodeIndex ];
|
|
|
|
|
|
- if ( mesh !== undefined ) {
|
|
|
+ if ( nodeDef.name !== undefined ) {
|
|
|
|
|
|
- var group = dependencies.meshes[ mesh ];
|
|
|
+ node.name = THREE.PropertyBinding.sanitizeNodeName( nodeDef.name );
|
|
|
|
|
|
- if ( group !== undefined ) {
|
|
|
-
|
|
|
- // do not clone children as they will be replaced anyway
|
|
|
- var clonedgroup = group.clone( false );
|
|
|
-
|
|
|
- for ( var i = 0; i < group.children.length; i ++ ) {
|
|
|
-
|
|
|
- var child = group.children[ i ];
|
|
|
- var originalChild = child;
|
|
|
-
|
|
|
- // clone Mesh to add to _node
|
|
|
+ }
|
|
|
|
|
|
- var originalMaterial = child.material;
|
|
|
- var originalGeometry = child.geometry;
|
|
|
- var originalInfluences = child.morphTargetInfluences;
|
|
|
- var originalUserData = child.userData;
|
|
|
- var originalName = child.name;
|
|
|
+ if ( nodeDef.extras ) node.userData = nodeDef.extras;
|
|
|
|
|
|
- var material = originalMaterial;
|
|
|
+ if ( nodeDef.matrix !== undefined ) {
|
|
|
|
|
|
- switch ( child.type ) {
|
|
|
+ var matrix = new THREE.Matrix4();
|
|
|
+ matrix.fromArray( nodeDef.matrix );
|
|
|
+ node.applyMatrix( matrix );
|
|
|
|
|
|
- case 'LineSegments':
|
|
|
- child = new THREE.LineSegments( originalGeometry, material );
|
|
|
- break;
|
|
|
+ } else {
|
|
|
|
|
|
- case 'LineLoop':
|
|
|
- child = new THREE.LineLoop( originalGeometry, material );
|
|
|
- break;
|
|
|
+ if ( nodeDef.translation !== undefined ) {
|
|
|
|
|
|
- case 'Line':
|
|
|
- child = new THREE.Line( originalGeometry, material );
|
|
|
- break;
|
|
|
+ node.position.fromArray( nodeDef.translation );
|
|
|
|
|
|
- case 'Points':
|
|
|
- child = new THREE.Points( originalGeometry, material );
|
|
|
- break;
|
|
|
+ }
|
|
|
|
|
|
- default:
|
|
|
- child = new THREE.Mesh( originalGeometry, material );
|
|
|
- child.drawMode = originalChild.drawMode;
|
|
|
+ if ( nodeDef.rotation !== undefined ) {
|
|
|
|
|
|
- }
|
|
|
+ node.quaternion.fromArray( nodeDef.rotation );
|
|
|
|
|
|
- child.castShadow = true;
|
|
|
- child.morphTargetInfluences = originalInfluences;
|
|
|
- child.userData = originalUserData;
|
|
|
- child.name = originalName;
|
|
|
+ }
|
|
|
|
|
|
- var skinEntry;
|
|
|
+ if ( nodeDef.scale !== undefined ) {
|
|
|
|
|
|
- if ( node.skin !== undefined ) {
|
|
|
+ node.scale.fromArray( nodeDef.scale );
|
|
|
|
|
|
- skinEntry = dependencies.skins[ node.skin ];
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
- // Replace Mesh with SkinnedMesh in library
|
|
|
- if ( skinEntry ) {
|
|
|
+ if ( nodeDef.skin !== undefined ) {
|
|
|
|
|
|
- var geometry = originalGeometry;
|
|
|
- material = originalMaterial;
|
|
|
- material.skinning = true;
|
|
|
+ var skinnedMeshes = [];
|
|
|
|
|
|
- child = new THREE.SkinnedMesh( geometry, material );
|
|
|
- child.castShadow = true;
|
|
|
- child.userData = originalUserData;
|
|
|
- child.name = originalName;
|
|
|
+ for ( var i = 0; i < node.children.length; i ++ ) {
|
|
|
|
|
|
- var bones = [];
|
|
|
- var boneInverses = [];
|
|
|
+ var skinEntry = dependencies.skins[ nodeDef.skin ];
|
|
|
|
|
|
- for ( var i = 0, l = skinEntry.joints.length; i < l; i ++ ) {
|
|
|
+ // Replace Mesh with SkinnedMesh.
|
|
|
+ var geometry = node.children[ i ].geometry;
|
|
|
+ var material = node.children[ i ].material;
|
|
|
+ material.skinning = true;
|
|
|
|
|
|
- var jointId = skinEntry.joints[ i ];
|
|
|
- var jointNode = __nodes[ jointId ];
|
|
|
+ var child = new THREE.SkinnedMesh( geometry, material );
|
|
|
+ child.morphTargetInfluences = node.children[ i ].morphTargetInfluences;
|
|
|
+ child.userData = node.children[ i ].userData;
|
|
|
+ child.name = node.children[ i ].name;
|
|
|
|
|
|
- if ( jointNode ) {
|
|
|
+ var bones = [];
|
|
|
+ var boneInverses = [];
|
|
|
|
|
|
- bones.push( jointNode );
|
|
|
+ for ( var j = 0, l = skinEntry.joints.length; j < l; j ++ ) {
|
|
|
|
|
|
- var m = skinEntry.inverseBindMatrices.array;
|
|
|
- var mat = new THREE.Matrix4().fromArray( m, i * 16 );
|
|
|
- boneInverses.push( mat );
|
|
|
+ var jointId = skinEntry.joints[ j ];
|
|
|
+ var jointNode = __nodes[ jointId ];
|
|
|
|
|
|
- } else {
|
|
|
+ if ( jointNode ) {
|
|
|
|
|
|
- console.warn( 'THREE.GLTFLoader: Joint "%s" could not be found.', jointId );
|
|
|
+ bones.push( jointNode );
|
|
|
|
|
|
- }
|
|
|
+ var m = skinEntry.inverseBindMatrices.array;
|
|
|
+ var mat = new THREE.Matrix4().fromArray( m, j * 16 );
|
|
|
+ boneInverses.push( mat );
|
|
|
|
|
|
- }
|
|
|
+ } else {
|
|
|
|
|
|
- child.bind( new THREE.Skeleton( bones, boneInverses ), child.matrixWorld );
|
|
|
+ console.warn( 'THREE.GLTFLoader: Joint "%s" could not be found.', jointId );
|
|
|
|
|
|
}
|
|
|
|
|
|
- clonedgroup.add( child );
|
|
|
-
|
|
|
}
|
|
|
|
|
|
- _node.add( clonedgroup );
|
|
|
-
|
|
|
- } else {
|
|
|
+ child.bind( new THREE.Skeleton( bones, boneInverses ), child.matrixWorld );
|
|
|
|
|
|
- console.warn( 'THREE.GLTFLoader: Could not find node "' + mesh + '".' );
|
|
|
+ skinnedMeshes.push( child );
|
|
|
|
|
|
}
|
|
|
|
|
|
- }
|
|
|
-
|
|
|
- if ( node.camera !== undefined ) {
|
|
|
-
|
|
|
- var camera = dependencies.cameras[ node.camera ];
|
|
|
-
|
|
|
- _node.add( camera );
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- if ( node.extensions
|
|
|
- && node.extensions[ EXTENSIONS.KHR_LIGHTS ]
|
|
|
- && node.extensions[ EXTENSIONS.KHR_LIGHTS ].light !== undefined ) {
|
|
|
-
|
|
|
- var lights = extensions[ EXTENSIONS.KHR_LIGHTS ].lights;
|
|
|
- _node.add( lights[ node.extensions[ EXTENSIONS.KHR_LIGHTS ].light ] );
|
|
|
+ node.remove.apply( node, node.children );
|
|
|
+ node.add.apply( node, skinnedMeshes );
|
|
|
|
|
|
}
|
|
|
|
|
|
- return _node;
|
|
|
+ return node;
|
|
|
|
|
|
} );
|
|
|
|