Selaa lähdekoodia

partial morph target position support

Lewy Blue 7 vuotta sitten
vanhempi
commit
2d7b38a783
1 muutettua tiedostoa jossa 149 lisäystä ja 63 poistoa
  1. 149 63
      examples/js/loaders/FBXLoader.js

+ 149 - 63
examples/js/loaders/FBXLoader.js

@@ -426,6 +426,8 @@
 
 		var parameters = {};
 
+		parameters.morphTargets = true;
+
 		if ( properties.BumpFactor ) {
 
 			parameters.bumpScale = properties.BumpFactor.value;
@@ -719,12 +721,12 @@
 
 		if ( 'Geometry' in FBXTree.Objects ) {
 
-			var geometryNodes = FBXTree.Objects.Geometry;
+			var geoNodes = FBXTree.Objects.Geometry;
 
-			for ( var nodeID in geometryNodes ) {
+			for ( var nodeID in geoNodes ) {
 
 				var relationships = connections.get( parseInt( nodeID ) );
-				var geo = parseGeometry( FBXTree, relationships, geometryNodes[ nodeID ], deformers );
+				var geo = parseGeometry( FBXTree, relationships, geoNodes[ nodeID ], deformers );
 
 				geometryMap.set( parseInt( nodeID ), geo );
 
@@ -737,16 +739,16 @@
 	}
 
 	// Parse single node in FBXTree.Objects.Geometry
-	function parseGeometry( FBXTree, relationships, geometryNode, deformers ) {
+	function parseGeometry( FBXTree, relationships, geoNode, deformers ) {
 
-		switch ( geometryNode.attrType ) {
+		switch ( geoNode.attrType ) {
 
 			case 'Mesh':
-				return parseMeshGeometry( FBXTree, relationships, geometryNode, deformers );
+				return parseMeshGeometry( FBXTree, relationships, geoNode, deformers );
 				break;
 
 			case 'NurbsCurve':
-				return parseNurbsGeometry( geometryNode );
+				return parseNurbsGeometry( geoNode );
 				break;
 
 		}
@@ -754,7 +756,7 @@
 	}
 
 	// Parse single node mesh geometry in FBXTree.Objects.Geometry
-	function parseMeshGeometry( FBXTree, relationships, geometryNode, deformers ) {
+	function parseMeshGeometry( FBXTree, relationships, geoNode, deformers ) {
 
 		var skeletons = deformers.skeletons;
 		var morphTargets = deformers.morphTargets;
@@ -814,51 +816,20 @@
 
 		}
 
-		return genGeometry( FBXTree, geometryNode, skeleton, morphTarget, preTransform );
-
-	}
-
-	function addMorphTargets( FBXTree, parentGeo, morphTarget, preTransform ) {
-
-		if ( morphTarget === null ) return;
-
-		parentGeo.morphAttributes.position = [];
-		parentGeo.morphAttributes.normal = [];
-
-		morphTarget.rawTargets.forEach( function ( rawTarget, index ) {
-
-			var geoNode = FBXTree.Objects.Geometry[ rawTarget.geoID ];
-
-			if ( geoNode !== undefined ) {
-
-				genMorphGeometry( parentGeo, geoNode, preTransform, index );
-
-			}
-
-		} );
-
-	}
-
-	// a morph geometry is similar to a normal geometry, and the node is also included
-	// in FBXTree.Objects.Geometry, however it can only have attributes for position, normal
-	// and a special attribute Index defining which vertices of the original geometry
-	// it controls
-	function genMorphGeometry( parentGeo, geoNode, preTransform ) {
-
-		var vertexPositions = ( geoNode.Vertices !== undefined ) ? geoNode.Vertices.a : [];
-		var normalsPositions = ( geoNode.Normals !== undefined ) ? geoNode.Normals.a : [];
-		var indices = ( geoNode.Indexes !== undefined ) ? geoNode.Indexes.a : [];
+		return genGeometry( FBXTree, geoNode, skeleton, morphTarget, preTransform );
 
 	}
 
 	// Generate a THREE.BufferGeometry from a node in FBXTree.Objects.Geometry
-	function genGeometry( FBXTree, geometryNode, skeleton, morphTarget, preTransform, calledFrom ) {
+	function genGeometry( FBXTree, geoNode, skeleton, morphTarget, preTransform ) {
 
 		var geo = new THREE.BufferGeometry();
-		if ( geometryNode.attrName ) geo.name = geometryNode.attrName;
+		if ( geoNode.attrName ) geo.name = geoNode.attrName;
 
-		var vertexPositions = ( geometryNode.Vertices !== undefined ) ? geometryNode.Vertices.a : [];
-		var vertexIndices = ( geometryNode.PolygonVertexIndex !== undefined ) ? geometryNode.PolygonVertexIndex.a : [];
+		var vertexPositions = ( geoNode.Vertices !== undefined ) ? geoNode.Vertices.a : [];
+
+		// TEMP: Clone array so that it doesn't get changed and can be reused in genMorphGeo
+		var vertexIndices = ( geoNode.PolygonVertexIndex !== undefined ) ? geoNode.PolygonVertexIndex.a.slice( 0 ) : [];
 
 		// create arrays to hold the final data used to build the buffergeometry
 		var vertexBuffer = [];
@@ -869,31 +840,31 @@
 		var vertexWeightsBuffer = [];
 		var weightsIndicesBuffer = [];
 
-		if ( geometryNode.LayerElementColor ) {
+		if ( geoNode.LayerElementColor ) {
 
-			var colorInfo = getColors( geometryNode.LayerElementColor[ 0 ] );
+			var colorInfo = getColors( geoNode.LayerElementColor[ 0 ] );
 
 		}
 
-		if ( geometryNode.LayerElementMaterial ) {
+		if ( geoNode.LayerElementMaterial ) {
 
-			var materialInfo = getMaterials( geometryNode.LayerElementMaterial[ 0 ] );
+			var materialInfo = getMaterials( geoNode.LayerElementMaterial[ 0 ] );
 
 		}
 
-		if ( geometryNode.LayerElementNormal ) {
+		if ( geoNode.LayerElementNormal ) {
 
-			var normalInfo = getNormals( geometryNode.LayerElementNormal[ 0 ] );
+			var normalInfo = getNormals( geoNode.LayerElementNormal[ 0 ] );
 
 		}
 
-		if ( geometryNode.LayerElementUV ) {
+		if ( geoNode.LayerElementUV ) {
 
 			var uvInfo = [];
 			var i = 0;
-			while ( geometryNode.LayerElementUV[ i ] ) {
+			while ( geoNode.LayerElementUV[ i ] ) {
 
-				uvInfo.push( getUVs( geometryNode.LayerElementUV[ i ] ) );
+				uvInfo.push( getUVs( geoNode.LayerElementUV[ i ] ) );
 				i ++;
 
 			}
@@ -1207,6 +1178,8 @@
 
 		geo.addAttribute( 'position', positionAttribute );
 
+		console.log( 'orig positionAttribute', positionAttribute );
+
 		if ( colorsBuffer.length > 0 ) {
 
 			geo.addAttribute( 'color', new THREE.Float32BufferAttribute( colorsBuffer, 3 ) );
@@ -1294,12 +1267,125 @@
 
 		}
 
-		addMorphTargets( FBXTree, geo, morphTarget, preTransform );
+		addMorphTargets( FBXTree, geo, geoNode, morphTarget, preTransform );
+
+		// console.log( 'main geo ', geo );
 
 		return geo;
 
 	}
 
+	function addMorphTargets( FBXTree, parentGeo, parentGeoNode, morphTarget, preTransform ) {
+
+		if ( morphTarget === null ) return;
+
+		parentGeo.morphAttributes.position = [];
+		parentGeo.morphAttributes.normal = [];
+
+		morphTarget.rawTargets.forEach( function ( rawTarget, index ) {
+
+			var morphGeoNode = FBXTree.Objects.Geometry[ rawTarget.geoID ];
+
+			if ( morphGeoNode !== undefined ) {
+
+				genMorphGeometry( parentGeo, parentGeoNode, morphGeoNode, preTransform, index );
+
+			}
+
+		} );
+
+	}
+
+	// a morph geometry is similar to a normal geometry, and the node is also included
+	// in FBXTree.Objects.Geometry, however it can only have attributes for position, normal
+	// and a special attribute Index defining which vertices of the original geometry
+	// it controls
+	function genMorphGeometry( parentGeo, parentGeoNode, morphGeoNode, preTransform, index ) {
+
+		var morphGeo = new THREE.BufferGeometry();
+		if ( morphGeoNode.attrName ) morphGeo.name = morphGeoNode.attrName;
+
+		var vertexPositions = ( morphGeoNode.Vertices !== undefined ) ? morphGeoNode.Vertices.a : [];
+		// console.log( 'vertexPositions', vertexPositions );
+
+		// var normalsPositions = ( geoNode.Normals !== undefined ) ? geoNode.Normals.a : [];
+		// var indices = ( geoNode.Indexes !== undefined ) ? geoNode.Indexes.a : [];
+
+		var vertexIndices = ( parentGeoNode.PolygonVertexIndex !== undefined ) ? parentGeoNode.PolygonVertexIndex.a : [];
+		// console.log( 'vertexIndices', vertexIndices );
+
+
+		// create arrays to hold the final data used to build the buffergeometry
+		var vertexBuffer = [];
+
+		var faceLength = 0;
+
+		// these will hold data for a single face
+		var vertexPositionIndexes = [];
+		// var faceNormals = [];
+
+		vertexIndices.forEach( function ( vertexIndex, polygonVertexIndex ) {
+
+			// console.log( 'vertexIndex', vertexIndex);
+			var endOfFace = false;
+
+			if ( vertexIndex < 0 ) {
+
+				vertexIndex = vertexIndex ^ - 1; // equivalent to ( x * -1 ) - 1
+				vertexIndices[ polygonVertexIndex ] = vertexIndex;
+				endOfFace = true;
+
+			}
+
+			vertexPositionIndexes.push( vertexIndex * 3, vertexIndex * 3 + 1, vertexIndex * 3 + 2 );
+
+			faceLength ++;
+
+			// we have reached the end of a face - it may have 4 sides though
+			// in which case the data is split to represent two 3 sided faces
+			if ( endOfFace ) {
+
+				for ( var i = 2; i < faceLength; i ++ ) {
+
+					vertexBuffer.push( vertexPositions[ vertexPositionIndexes[ 0 ] ] );
+					vertexBuffer.push( vertexPositions[ vertexPositionIndexes[ 1 ] ] );
+					vertexBuffer.push( vertexPositions[ vertexPositionIndexes[ 2 ] ] );
+
+					vertexBuffer.push( vertexPositions[ vertexPositionIndexes[ ( i - 1 ) * 3 ] ] );
+					vertexBuffer.push( vertexPositions[ vertexPositionIndexes[ ( i - 1 ) * 3 + 1 ] ] );
+					vertexBuffer.push( vertexPositions[ vertexPositionIndexes[ ( i - 1 ) * 3 + 2 ] ] );
+
+					vertexBuffer.push( vertexPositions[ vertexPositionIndexes[ i * 3 ] ] );
+					vertexBuffer.push( vertexPositions[ vertexPositionIndexes[ i * 3 + 1 ] ] );
+					vertexBuffer.push( vertexPositions[ vertexPositionIndexes[ i * 3 + 2 ] ] );
+
+				}
+
+				faceLength = 0;
+
+				// reset arrays for the next face
+				vertexPositionIndexes = [];
+
+			}
+
+		} );
+
+		// console.log( 'vertexBuffer', vertexBuffer );
+
+		var positionAttribute = new THREE.Float32BufferAttribute( vertexBuffer, 3 );
+
+		preTransform.applyToBufferAttribute( positionAttribute );
+
+		parentGeo.morphAttributes.position[ index ] = positionAttribute;
+
+		morphGeo.addAttribute( 'position', positionAttribute );
+
+		console.log( 'morph positionAttribute', positionAttribute );
+
+		return morphGeo;
+
+	}
+
 	// Parse normal from FBXTree.Objects.Geometry.LayerElementNormal if it exists
 	function getNormals( NormalNode ) {
 
@@ -1453,7 +1539,7 @@
 	}
 
 	// Generate a NurbGeometry from a node in FBXTree.Objects.Geometry
-	function parseNurbsGeometry( geometryNode ) {
+	function parseNurbsGeometry( geoNode ) {
 
 		if ( THREE.NURBSCurve === undefined ) {
 
@@ -1462,20 +1548,20 @@
 
 		}
 
-		var order = parseInt( geometryNode.Order );
+		var order = parseInt( geoNode.Order );
 
 		if ( isNaN( order ) ) {
 
-			console.error( 'THREE.FBXLoader: Invalid Order %s given for geometry ID: %s', geometryNode.Order, geometryNode.id );
+			console.error( 'THREE.FBXLoader: Invalid Order %s given for geometry ID: %s', geoNode.Order, geoNode.id );
 			return new THREE.BufferGeometry();
 
 		}
 
 		var degree = order - 1;
 
-		var knots = geometryNode.KnotVector.a;
+		var knots = geoNode.KnotVector.a;
 		var controlPoints = [];
-		var pointsValues = geometryNode.Points.a;
+		var pointsValues = geoNode.Points.a;
 
 		for ( var i = 0, l = pointsValues.length; i < l; i += 4 ) {
 
@@ -1485,11 +1571,11 @@
 
 		var startKnot, endKnot;
 
-		if ( geometryNode.Form === 'Closed' ) {
+		if ( geoNode.Form === 'Closed' ) {
 
 			controlPoints.push( controlPoints[ 0 ] );
 
-		} else if ( geometryNode.Form === 'Periodic' ) {
+		} else if ( geoNode.Form === 'Periodic' ) {
 
 			startKnot = degree;
 			endKnot = knots.length - 1 - startKnot;