ソースを参照

Merge pull request #11903 from donmccurdy/feat-gltf-draco-extension-v2

[gltf] Refactor loadMeshes.
Mr.doob 8 年 前
コミット
945e759cb1
1 ファイル変更217 行追加213 行削除
  1. 217 213
      examples/js/loaders/GLTF2Loader.js

+ 217 - 213
examples/js/loaders/GLTF2Loader.js

@@ -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;
+				} );
 
 			} );