|
@@ -1579,6 +1579,125 @@ THREE.GLTF2Loader = ( 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 {Object} dependencies
|
|
|
+ */
|
|
|
+ function addMorphTargets ( mesh, meshDef, primitiveDef, dependencies ) {
|
|
|
+
|
|
|
+ var geometry = mesh.geometry;
|
|
|
+ var material = mesh.material;
|
|
|
+
|
|
|
+ var targets = primitiveDef.targets;
|
|
|
+ var morphAttributes = geometry.morphAttributes;
|
|
|
+
|
|
|
+ morphAttributes.position = [];
|
|
|
+ morphAttributes.normal = [];
|
|
|
+
|
|
|
+ material.morphTargets = true;
|
|
|
+
|
|
|
+ for ( var i = 0, il = targets.length; i < il; i ++ ) {
|
|
|
+
|
|
|
+ var target = targets[ i ];
|
|
|
+ var attributeName = 'morphTarget' + i;
|
|
|
+
|
|
|
+ var positionAttribute, normalAttribute;
|
|
|
+
|
|
|
+ if ( target.POSITION !== undefined ) {
|
|
|
+
|
|
|
+ // Three.js morph formula is
|
|
|
+ // position
|
|
|
+ // + weight0 * ( morphTarget0 - position )
|
|
|
+ // + weight1 * ( morphTarget1 - position )
|
|
|
+ // ...
|
|
|
+ // while the glTF one is
|
|
|
+ // position
|
|
|
+ // + weight0 * morphTarget0
|
|
|
+ // + weight1 * morphTarget1
|
|
|
+ // ...
|
|
|
+ // then adding position to morphTarget.
|
|
|
+ // So morphTarget value will depend on mesh's position, then cloning attribute
|
|
|
+ // for the case if attribute is shared among two or more meshes.
|
|
|
+
|
|
|
+ positionAttribute = dependencies.accessors[ target.POSITION ].clone();
|
|
|
+ var position = geometry.attributes.position;
|
|
|
+
|
|
|
+ for ( var j = 0, jl = positionAttribute.count; j < jl; j ++ ) {
|
|
|
+
|
|
|
+ positionAttribute.setXYZ(
|
|
|
+ j,
|
|
|
+ positionAttribute.getX( j ) + position.getX( j ),
|
|
|
+ positionAttribute.getY( j ) + position.getY( j ),
|
|
|
+ positionAttribute.getZ( j ) + position.getZ( j )
|
|
|
+ );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ // Copying the original position not to affect the final position.
|
|
|
+ // See the formula above.
|
|
|
+ positionAttribute = geometry.attributes.position.clone();
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( target.NORMAL !== undefined ) {
|
|
|
+
|
|
|
+ material.morphNormals = true;
|
|
|
+
|
|
|
+ // see target.POSITION's comment
|
|
|
+
|
|
|
+ normalAttribute = dependencies.accessors[ target.NORMAL ].clone();
|
|
|
+ var normal = geometry.attributes.normal;
|
|
|
+
|
|
|
+ for ( var j = 0, jl = normalAttribute.count; j < jl; j ++ ) {
|
|
|
+
|
|
|
+ normalAttribute.setXYZ(
|
|
|
+ j,
|
|
|
+ normalAttribute.getX( j ) + normal.getX( j ),
|
|
|
+ normalAttribute.getY( j ) + normal.getY( j ),
|
|
|
+ normalAttribute.getZ( j ) + normal.getZ( j )
|
|
|
+ );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ normalAttribute = geometry.attributes.normal.clone();
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( target.TANGENT !== undefined ) {
|
|
|
+
|
|
|
+ // TODO: implement
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ positionAttribute.name = attributeName;
|
|
|
+ normalAttribute.name = attributeName;
|
|
|
+
|
|
|
+ morphAttributes.position.push( positionAttribute );
|
|
|
+ morphAttributes.normal.push( normalAttribute );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ mesh.updateMorphTargets();
|
|
|
+
|
|
|
+ if ( meshDef.weights !== undefined ) {
|
|
|
+
|
|
|
+ for ( var i = 0, il = meshDef.weights.length; i < il; i ++ ) {
|
|
|
+
|
|
|
+ mesh.morphTargetInfluences[ i ] = meshDef.weights[ i ];
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
// Deferred constructor for RawShaderMaterial types
|
|
|
function DeferredShaderMaterial( params ) {
|
|
|
|
|
@@ -2116,102 +2235,126 @@ THREE.GLTF2Loader = ( function () {
|
|
|
|
|
|
};
|
|
|
|
|
|
- GLTFParser.prototype.loadMeshes = function () {
|
|
|
+ GLTFParser.prototype.loadGeometries = function ( primitives ) {
|
|
|
|
|
|
- var json = this.json;
|
|
|
+ var extensions = this.extensions;
|
|
|
|
|
|
return this._withDependencies( [
|
|
|
|
|
|
'accessors',
|
|
|
- 'materials'
|
|
|
+ 'bufferViews',
|
|
|
|
|
|
] ).then( function ( dependencies ) {
|
|
|
|
|
|
- return _each( json.meshes, function ( mesh ) {
|
|
|
+ return _each( primitives, function ( primitive ) {
|
|
|
|
|
|
- var group = new THREE.Group();
|
|
|
- if ( mesh.name !== undefined ) group.name = mesh.name;
|
|
|
+ var geometry = new THREE.BufferGeometry();
|
|
|
|
|
|
- if ( mesh.extras ) group.userData = mesh.extras;
|
|
|
+ var attributes = primitive.attributes;
|
|
|
|
|
|
- var primitives = mesh.primitives || [];
|
|
|
+ for ( var attributeId in attributes ) {
|
|
|
|
|
|
- for ( var name in primitives ) {
|
|
|
+ var attributeEntry = attributes[ attributeId ];
|
|
|
|
|
|
- var primitive = primitives[ name ];
|
|
|
+ if ( attributeEntry === undefined ) return;
|
|
|
|
|
|
- var material = primitive.material !== undefined ? dependencies.materials[ primitive.material ] : createDefaultMaterial();
|
|
|
+ var bufferAttribute = dependencies.accessors[ attributeEntry ];
|
|
|
|
|
|
- var geometry;
|
|
|
+ switch ( attributeId ) {
|
|
|
|
|
|
- var meshNode;
|
|
|
+ case 'POSITION':
|
|
|
|
|
|
- if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLES || primitive.mode === undefined ) {
|
|
|
+ geometry.addAttribute( 'position', bufferAttribute );
|
|
|
+ break;
|
|
|
|
|
|
- geometry = new THREE.BufferGeometry();
|
|
|
+ case 'NORMAL':
|
|
|
|
|
|
- var attributes = primitive.attributes;
|
|
|
+ geometry.addAttribute( 'normal', bufferAttribute );
|
|
|
+ break;
|
|
|
|
|
|
- for ( var attributeId in attributes ) {
|
|
|
+ case 'TEXCOORD_0':
|
|
|
+ case 'TEXCOORD0':
|
|
|
+ case 'TEXCOORD':
|
|
|
|
|
|
- var attributeEntry = attributes[ attributeId ];
|
|
|
+ geometry.addAttribute( 'uv', bufferAttribute );
|
|
|
+ break;
|
|
|
|
|
|
- if ( attributeEntry === undefined ) return;
|
|
|
+ case 'TEXCOORD_1':
|
|
|
|
|
|
- var bufferAttribute = dependencies.accessors[ attributeEntry ];
|
|
|
+ geometry.addAttribute( 'uv2', bufferAttribute );
|
|
|
+ break;
|
|
|
|
|
|
- switch ( attributeId ) {
|
|
|
+ case 'COLOR_0':
|
|
|
+ case 'COLOR0':
|
|
|
+ case 'COLOR':
|
|
|
|
|
|
- case 'POSITION':
|
|
|
+ geometry.addAttribute( 'color', bufferAttribute );
|
|
|
+ break;
|
|
|
|
|
|
- geometry.addAttribute( 'position', bufferAttribute );
|
|
|
- break;
|
|
|
+ case 'WEIGHTS_0':
|
|
|
+ case 'WEIGHT': // WEIGHT semantic deprecated.
|
|
|
|
|
|
- case 'NORMAL':
|
|
|
+ geometry.addAttribute( 'skinWeight', bufferAttribute );
|
|
|
+ break;
|
|
|
|
|
|
- geometry.addAttribute( 'normal', bufferAttribute );
|
|
|
- break;
|
|
|
+ case 'JOINTS_0':
|
|
|
+ case 'JOINT': // JOINT semantic deprecated.
|
|
|
|
|
|
- case 'TEXCOORD_0':
|
|
|
- case 'TEXCOORD0':
|
|
|
- case 'TEXCOORD':
|
|
|
+ geometry.addAttribute( 'skinIndex', bufferAttribute );
|
|
|
+ break;
|
|
|
|
|
|
- geometry.addAttribute( 'uv', bufferAttribute );
|
|
|
- break;
|
|
|
+ }
|
|
|
|
|
|
- case 'TEXCOORD_1':
|
|
|
+ }
|
|
|
|
|
|
- geometry.addAttribute( 'uv2', bufferAttribute );
|
|
|
- break;
|
|
|
+ if ( primitive.indices !== undefined ) {
|
|
|
|
|
|
- case 'COLOR_0':
|
|
|
- case 'COLOR0':
|
|
|
- case 'COLOR':
|
|
|
+ geometry.setIndex( dependencies.accessors[ primitive.indices ] );
|
|
|
|
|
|
- geometry.addAttribute( 'color', bufferAttribute );
|
|
|
- break;
|
|
|
+ }
|
|
|
|
|
|
- case 'WEIGHTS_0':
|
|
|
- case 'WEIGHT': // WEIGHT semantic deprecated.
|
|
|
+ return geometry;
|
|
|
|
|
|
- geometry.addAttribute( 'skinWeight', bufferAttribute );
|
|
|
- break;
|
|
|
+ } );
|
|
|
|
|
|
- case 'JOINTS_0':
|
|
|
- case 'JOINT': // JOINT semantic deprecated.
|
|
|
+ } );
|
|
|
|
|
|
- geometry.addAttribute( 'skinIndex', bufferAttribute );
|
|
|
- break;
|
|
|
+ };
|
|
|
|
|
|
- }
|
|
|
+ /**
|
|
|
+ * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#meshes
|
|
|
+ */
|
|
|
+ GLTFParser.prototype.loadMeshes = function () {
|
|
|
|
|
|
- }
|
|
|
+ var scope = this;
|
|
|
+ var json = this.json;
|
|
|
+
|
|
|
+ return this._withDependencies( [
|
|
|
|
|
|
- if ( primitive.indices !== undefined ) {
|
|
|
+ 'accessors',
|
|
|
+ 'materials'
|
|
|
|
|
|
- geometry.setIndex( dependencies.accessors[ primitive.indices ] );
|
|
|
+ ] ).then( function ( dependencies ) {
|
|
|
|
|
|
- }
|
|
|
+ return _each( json.meshes, function ( meshDef ) {
|
|
|
+
|
|
|
+ var group = new THREE.Group();
|
|
|
+
|
|
|
+ if ( meshDef.name !== undefined ) group.name = meshDef.name;
|
|
|
+ if ( meshDef.extras ) group.userData = meshDef.extras;
|
|
|
+
|
|
|
+ var primitives = meshDef.primitives || [];
|
|
|
+
|
|
|
+ return scope.loadGeometries( primitives ).then( function ( geometries ) {
|
|
|
+
|
|
|
+ for ( var name in primitives ) {
|
|
|
+
|
|
|
+ var primitive = primitives[ name ];
|
|
|
+ var geometry = geometries[ name ];
|
|
|
+
|
|
|
+ var material = primitive.material === undefined
|
|
|
+ ? createDefaultMaterial()
|
|
|
+ : dependencies.materials[ primitive.material ];
|
|
|
|
|
|
if ( material.aoMap
|
|
|
&& geometry.attributes.uv2 === undefined
|
|
@@ -2222,6 +2365,13 @@ THREE.GLTF2Loader = ( function () {
|
|
|
|
|
|
}
|
|
|
|
|
|
+ if ( geometry.attributes.color !== undefined ) {
|
|
|
+
|
|
|
+ material.vertexColors = THREE.VertexColors;
|
|
|
+ material.needsUpdate = true;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
if ( geometry.attributes.normal === undefined ) {
|
|
|
|
|
|
if ( material.flatShading !== undefined ) {
|
|
@@ -2237,185 +2387,39 @@ THREE.GLTF2Loader = ( function () {
|
|
|
|
|
|
}
|
|
|
|
|
|
- meshNode = new THREE.Mesh( geometry, material );
|
|
|
- meshNode.castShadow = true;
|
|
|
-
|
|
|
- if ( primitive.targets !== undefined ) {
|
|
|
-
|
|
|
- var targets = primitive.targets;
|
|
|
- var morphAttributes = geometry.morphAttributes;
|
|
|
-
|
|
|
- morphAttributes.position = [];
|
|
|
- morphAttributes.normal = [];
|
|
|
-
|
|
|
- material.morphTargets = true;
|
|
|
-
|
|
|
- for ( var i = 0, il = targets.length; i < il; i ++ ) {
|
|
|
-
|
|
|
- var target = targets[ i ];
|
|
|
- var attributeName = 'morphTarget' + i;
|
|
|
-
|
|
|
- var positionAttribute, normalAttribute;
|
|
|
-
|
|
|
- if ( target.POSITION !== undefined ) {
|
|
|
-
|
|
|
- // Three.js morph formula is
|
|
|
- // position
|
|
|
- // + weight0 * ( morphTarget0 - position )
|
|
|
- // + weight1 * ( morphTarget1 - position )
|
|
|
- // ...
|
|
|
- // while the glTF one is
|
|
|
- // position
|
|
|
- // + weight0 * morphTarget0
|
|
|
- // + weight1 * morphTarget1
|
|
|
- // ...
|
|
|
- // then adding position to morphTarget.
|
|
|
- // So morphTarget value will depend on mesh's position, then cloning attribute
|
|
|
- // for the case if attribute is shared among two or more meshes.
|
|
|
-
|
|
|
- positionAttribute = dependencies.accessors[ target.POSITION ].clone();
|
|
|
- var position = geometry.attributes.position;
|
|
|
+ var mesh;
|
|
|
|
|
|
- for ( var j = 0, jl = positionAttribute.count; j < jl; j ++ ) {
|
|
|
+ if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLES || primitive.mode === undefined ) {
|
|
|
|
|
|
- positionAttribute.setXYZ(
|
|
|
- j,
|
|
|
- positionAttribute.getX( j ) + position.getX( j ),
|
|
|
- positionAttribute.getY( j ) + position.getY( j ),
|
|
|
- positionAttribute.getZ( j ) + position.getZ( j )
|
|
|
- );
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- } else if ( geometry.attributes.position ) {
|
|
|
-
|
|
|
- // Copying the original position not to affect the final position.
|
|
|
- // See the formula above.
|
|
|
- positionAttribute = geometry.attributes.position.clone();
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- if ( target.NORMAL !== undefined ) {
|
|
|
-
|
|
|
- material.morphNormals = true;
|
|
|
-
|
|
|
- // see target.POSITION's comment
|
|
|
-
|
|
|
- normalAttribute = dependencies.accessors[ target.NORMAL ].clone();
|
|
|
- var normal = geometry.attributes.normal;
|
|
|
-
|
|
|
- for ( var j = 0, jl = normalAttribute.count; j < jl; j ++ ) {
|
|
|
-
|
|
|
- normalAttribute.setXYZ(
|
|
|
- j,
|
|
|
- normalAttribute.getX( j ) + normal.getX( j ),
|
|
|
- normalAttribute.getY( j ) + normal.getY( j ),
|
|
|
- normalAttribute.getZ( j ) + normal.getZ( j )
|
|
|
- );
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- } else if ( geometry.attributes.normal ) {
|
|
|
-
|
|
|
- normalAttribute = geometry.attributes.normal.clone();
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- // TODO: implement
|
|
|
- if ( target.TANGENT !== undefined ) {
|
|
|
-
|
|
|
- }
|
|
|
+ mesh = new THREE.Mesh( geometry, material );
|
|
|
|
|
|
- if ( positionAttribute ) {
|
|
|
+ } else if ( primitive.mode === WEBGL_CONSTANTS.LINES ) {
|
|
|
|
|
|
- positionAttribute.name = attributeName;
|
|
|
- morphAttributes.position.push( positionAttribute );
|
|
|
+ mesh = new THREE.LineSegments( geometry, material );
|
|
|
|
|
|
- }
|
|
|
-
|
|
|
- if ( normalAttribute ) {
|
|
|
-
|
|
|
- normalAttribute.name = attributeName;
|
|
|
- morphAttributes.normal.push( normalAttribute );
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- meshNode.updateMorphTargets();
|
|
|
-
|
|
|
- if ( mesh.weights !== undefined ) {
|
|
|
-
|
|
|
- for ( var i = 0, il = mesh.weights.length; i < il; i ++ ) {
|
|
|
-
|
|
|
- meshNode.morphTargetInfluences[ i ] = mesh.weights[ i ];
|
|
|
+ } else {
|
|
|
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
+ throw new Error( 'THREE.GLTF2Loader: Only TRIANGLE and LINE primitives are supported.' );
|
|
|
|
|
|
}
|
|
|
|
|
|
- } else if ( primitive.mode === WEBGL_CONSTANTS.LINES ) {
|
|
|
-
|
|
|
- geometry = new THREE.BufferGeometry();
|
|
|
-
|
|
|
- var attributes = primitive.attributes;
|
|
|
-
|
|
|
- for ( var attributeId in attributes ) {
|
|
|
-
|
|
|
- var attributeEntry = attributes[ attributeId ];
|
|
|
-
|
|
|
- if ( ! attributeEntry ) return;
|
|
|
-
|
|
|
- var bufferAttribute = dependencies.accessors[ attributeEntry ];
|
|
|
+ mesh.name = group.name + '_' + name;
|
|
|
|
|
|
- switch ( attributeId ) {
|
|
|
-
|
|
|
- case 'POSITION':
|
|
|
- geometry.addAttribute( 'position', bufferAttribute );
|
|
|
- break;
|
|
|
-
|
|
|
- case 'COLOR_0':
|
|
|
- case 'COLOR0':
|
|
|
- case 'COLOR':
|
|
|
- geometry.addAttribute( 'color', bufferAttribute );
|
|
|
- break;
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- if ( primitive.indices !== undefined ) {
|
|
|
+ if ( primitive.targets !== undefined ) {
|
|
|
|
|
|
- geometry.setIndex( dependencies.accessors[ primitive.indices ] );
|
|
|
+ addMorphTargets( mesh, meshDef, primitive, dependencies );
|
|
|
|
|
|
}
|
|
|
|
|
|
- meshNode = new THREE.LineSegments( geometry, material );
|
|
|
+ if ( primitive.extras ) mesh.userData = primitive.extras;
|
|
|
|
|
|
- } else {
|
|
|
-
|
|
|
- throw new Error( 'THREE.GLTF2Loader: Only triangular and line primitives are supported.' );
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- if ( geometry.attributes.color !== undefined ) {
|
|
|
-
|
|
|
- material.vertexColors = THREE.VertexColors;
|
|
|
- material.needsUpdate = true;
|
|
|
+ group.add( mesh );
|
|
|
|
|
|
}
|
|
|
|
|
|
- meshNode.name = group.name + '_' + name;
|
|
|
+ return group;
|
|
|
|
|
|
- if ( primitive.extras ) meshNode.userData = primitive.extras;
|
|
|
-
|
|
|
- group.add( meshNode );
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- return group;
|
|
|
+ } );
|
|
|
|
|
|
} );
|
|
|
|