|
@@ -2344,6 +2344,9 @@ class GLTFParser {
|
|
|
// BufferGeometry caching
|
|
|
this.primitiveCache = {};
|
|
|
|
|
|
+ // Node cache
|
|
|
+ this.nodeCache = {};
|
|
|
+
|
|
|
// Object3D instance caches
|
|
|
this.meshCache = { refs: {}, uses: {} };
|
|
|
this.cameraCache = { refs: {}, uses: {} };
|
|
@@ -2414,6 +2417,7 @@ class GLTFParser {
|
|
|
|
|
|
// Clear the loader cache
|
|
|
this.cache.removeAll();
|
|
|
+ this.nodeCache = {};
|
|
|
|
|
|
// Mark the special nodes/meshes in json for efficient parse
|
|
|
this._invokeAll( function ( ext ) {
|
|
@@ -3702,7 +3706,7 @@ class GLTFParser {
|
|
|
|
|
|
for ( let i = 0, il = skinDef.joints.length; i < il; i ++ ) {
|
|
|
|
|
|
- pending.push( this.getDependency( 'node', skinDef.joints[ i ] ) );
|
|
|
+ pending.push( this._loadNodeShallow( skinDef.joints[ i ] ) );
|
|
|
|
|
|
}
|
|
|
|
|
@@ -3721,6 +3725,9 @@ class GLTFParser {
|
|
|
const inverseBindMatrices = results.pop();
|
|
|
const jointNodes = results;
|
|
|
|
|
|
+ // Note that bones (joint nodes) may or may not be in the
|
|
|
+ // scene graph at this time.
|
|
|
+
|
|
|
const bones = [];
|
|
|
const boneInverses = [];
|
|
|
|
|
@@ -3969,18 +3976,91 @@ class GLTFParser {
|
|
|
*/
|
|
|
loadNode( nodeIndex ) {
|
|
|
|
|
|
+ const json = this.json;
|
|
|
+ const parser = this;
|
|
|
+
|
|
|
+ const nodeDef = json.nodes[ nodeIndex ];
|
|
|
+
|
|
|
+ return ( function () {
|
|
|
+
|
|
|
+ const nodePending = parser._loadNodeShallow( nodeIndex );
|
|
|
+
|
|
|
+ const childPending = [];
|
|
|
+ const childrenDef = nodeDef.children || [];
|
|
|
+
|
|
|
+ for ( let i = 0, il = childrenDef.length; i < il; i ++ ) {
|
|
|
+
|
|
|
+ childPending.push( parser.getDependency( 'node', childrenDef[ i ] ) );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ const skeletonPending = nodeDef.skin === undefined
|
|
|
+ ? Promise.resolve( null )
|
|
|
+ : parser.getDependency( 'skin', nodeDef.skin );
|
|
|
+
|
|
|
+ return Promise.all( [
|
|
|
+ nodePending,
|
|
|
+ Promise.all( childPending ),
|
|
|
+ skeletonPending
|
|
|
+ ] );
|
|
|
+
|
|
|
+ }() ).then( function ( results ) {
|
|
|
+
|
|
|
+ const node = results[ 0 ];
|
|
|
+ const children = results[ 1 ];
|
|
|
+ const skeleton = results[ 2 ];
|
|
|
+
|
|
|
+ if ( skeleton !== null ) {
|
|
|
+
|
|
|
+ // This full traverse should be fine because
|
|
|
+ // child glTF nodes have not been added to this node yet.
|
|
|
+ node.traverse( function ( mesh ) {
|
|
|
+
|
|
|
+ if ( ! mesh.isSkinnedMesh ) return;
|
|
|
+
|
|
|
+ mesh.bind( skeleton, _identityMatrix );
|
|
|
+
|
|
|
+ } );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ for ( let i = 0, il = children.length; i < il; i ++ ) {
|
|
|
+
|
|
|
+ node.add( children[ i ] );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ return node;
|
|
|
+
|
|
|
+ } );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ // ._loadNodeShallow() parses a single node.
|
|
|
+ // skin and child nodes are created and added in .loadNode() (no '_' prefix).
|
|
|
+ _loadNodeShallow( nodeIndex ) {
|
|
|
+
|
|
|
const json = this.json;
|
|
|
const extensions = this.extensions;
|
|
|
const parser = this;
|
|
|
|
|
|
+ // This method is called from .loadNode() and .loadSkin().
|
|
|
+ // Cache a node to avoid duplication.
|
|
|
+
|
|
|
+ if ( this.nodeCache[ nodeIndex ] !== undefined ) {
|
|
|
+
|
|
|
+ return this.nodeCache[ nodeIndex ];
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
const nodeDef = json.nodes[ nodeIndex ];
|
|
|
|
|
|
// reserve node's name before its dependencies, so the root has the intended name.
|
|
|
const nodeName = nodeDef.name ? parser.createUniqueName( nodeDef.name ) : '';
|
|
|
|
|
|
- return ( function () {
|
|
|
+ this.nodeCache[ nodeIndex ] = ( function () {
|
|
|
|
|
|
- const objectPending = [];
|
|
|
+ const pending = [];
|
|
|
|
|
|
const meshPromise = parser._invokeOne( function ( ext ) {
|
|
|
|
|
@@ -3990,13 +4070,13 @@ class GLTFParser {
|
|
|
|
|
|
if ( meshPromise ) {
|
|
|
|
|
|
- objectPending.push( meshPromise );
|
|
|
+ pending.push( meshPromise );
|
|
|
|
|
|
}
|
|
|
|
|
|
if ( nodeDef.camera !== undefined ) {
|
|
|
|
|
|
- objectPending.push( parser.getDependency( 'camera', nodeDef.camera ).then( function ( camera ) {
|
|
|
+ pending.push( parser.getDependency( 'camera', nodeDef.camera ).then( function ( camera ) {
|
|
|
|
|
|
return parser._getNodeRef( parser.cameraCache, nodeDef.camera, camera );
|
|
|
|
|
@@ -4010,34 +4090,13 @@ class GLTFParser {
|
|
|
|
|
|
} ).forEach( function ( promise ) {
|
|
|
|
|
|
- objectPending.push( promise );
|
|
|
+ pending.push( promise );
|
|
|
|
|
|
} );
|
|
|
|
|
|
- const childPending = [];
|
|
|
- const childrenDef = nodeDef.children || [];
|
|
|
-
|
|
|
- for ( let i = 0, il = childrenDef.length; i < il; i ++ ) {
|
|
|
-
|
|
|
- childPending.push( parser.getDependency( 'node', childrenDef[ i ] ) );
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- const skeletonPending = nodeDef.skin === undefined
|
|
|
- ? Promise.resolve( null )
|
|
|
- : parser.getDependency( 'skin', nodeDef.skin );
|
|
|
-
|
|
|
- return Promise.all( [
|
|
|
- Promise.all( objectPending ),
|
|
|
- Promise.all( childPending ),
|
|
|
- skeletonPending
|
|
|
- ] );
|
|
|
-
|
|
|
- }() ).then( function ( results ) {
|
|
|
+ return Promise.all( pending );
|
|
|
|
|
|
- const objects = results[ 0 ];
|
|
|
- const children = results[ 1 ];
|
|
|
- const skeleton = results[ 2 ];
|
|
|
+ }() ).then( function ( objects ) {
|
|
|
|
|
|
let node;
|
|
|
|
|
@@ -4117,30 +4176,12 @@ class GLTFParser {
|
|
|
|
|
|
parser.associations.get( node ).nodes = nodeIndex;
|
|
|
|
|
|
- if ( skeleton !== null ) {
|
|
|
-
|
|
|
- // This full traverse should be fine because
|
|
|
- // child glTF nodes have not been added to this node yet.
|
|
|
- node.traverse( function ( mesh ) {
|
|
|
-
|
|
|
- if ( ! mesh.isSkinnedMesh ) return;
|
|
|
-
|
|
|
- mesh.bind( skeleton, _identityMatrix );
|
|
|
-
|
|
|
- } );
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- for ( let i = 0, il = children.length; i < il; i ++ ) {
|
|
|
-
|
|
|
- node.add( children[ i ] );
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
return node;
|
|
|
|
|
|
} );
|
|
|
|
|
|
+ return this.nodeCache[ nodeIndex ];
|
|
|
+
|
|
|
}
|
|
|
|
|
|
/**
|