Browse Source

USDZExporter: Add multi-material support. (#33598)

Michael Herzog 1 month ago
parent
commit
0edc965186
1 changed files with 79 additions and 23 deletions
  1. 79 23
      examples/jsm/exporters/USDZExporter.js

+ 79 - 23
examples/jsm/exporters/USDZExporter.js

@@ -567,35 +567,49 @@ function buildNode( object, parentNode, materials, usedNames, files, options ) {
 	if ( object.isMesh ) {
 
 		const geometry = object.geometry;
-		const material = object.material;
+		const isMultiMaterial = Array.isArray( object.material );
 
-		if ( ! material.isMeshStandardMaterial ) {
+		const meshMaterials = isMultiMaterial ? object.material : [ object.material ];
 
-			console.warn( 'THREE.USDZExporter: Use MeshStandardMaterial for best results.' );
+		for ( let i = 0; i < meshMaterials.length; i ++ ) {
 
-		}
+			const material = meshMaterials[ i ];
 
-		const geometryFileName = 'geometries/Geometry_' + geometry.id + '.usda';
+			if ( ! material.isMeshStandardMaterial ) {
 
-		if ( ! ( geometryFileName in files ) ) {
+				console.warn( 'THREE.USDZExporter: Use MeshStandardMaterial for best results.' );
 
-			const meshObject = buildMeshObject( geometry );
-			files[ geometryFileName ] = strToU8(
-				buildHeader() + '\n' + meshObject.toString()
-			);
+			}
+
+			if ( ! ( material.uuid in materials ) ) {
+
+				materials[ material.uuid ] = material;
+
+			}
 
 		}
 
-		if ( ! ( material.uuid in materials ) ) {
+		const resolvedMaterials = meshMaterials.map( ( m ) => materials[ m.uuid ] );
+
+		if ( isMultiMaterial === false ) {
+
+			const geometryFileName = `geometries/Geometry_${geometry.id}.usda`;
+
+			if ( ! ( geometryFileName in files ) ) {
 
-			materials[ material.uuid ] = material;
+				const meshObject = buildMeshObject( geometry );
+				files[ geometryFileName ] = strToU8(
+					buildHeader() + '\n' + meshObject.toString()
+				);
+
+			}
 
 		}
 
 		childNode = buildMesh(
 			object,
 			geometry,
-			materials[ material.uuid ],
+			resolvedMaterials,
 			usedNames,
 			options
 		);
@@ -706,19 +720,26 @@ function buildXform( object, usedNames, options ) {
 
 }
 
-function buildMesh( object, geometry, material, usedNames, options ) {
+function buildMesh( object, geometry, materials, usedNames, options ) {
 
 	const node = buildXform( object, usedNames, options );
 
-	node.addMetadata(
-		'prepend references',
-		`@./geometries/Geometry_${geometry.id}.usda@</Geometry>`
-	);
-	node.addMetadata( 'prepend apiSchemas', '["MaterialBindingAPI"]' );
+	if ( materials.length === 1 ) {
 
-	node.addProperty(
-		`rel material:binding = </Materials/Material_${material.id}>`
-	);
+		node.addMetadata(
+			'prepend references',
+			`@./geometries/Geometry_${geometry.id}.usda@</Geometry>`
+		);
+		node.addMetadata( 'prepend apiSchemas', '["MaterialBindingAPI"]' );
+		node.addProperty(
+			`rel material:binding = </Materials/Material_${materials[ 0 ].id}>`
+		);
+
+	} else {
+
+		node.addChild( buildMeshNode( geometry, materials ) );
+
+	}
 
 	return node;
 
@@ -756,7 +777,7 @@ function buildMeshObject( geometry ) {
 
 }
 
-function buildMeshNode( geometry ) {
+function buildMeshNode( geometry, materials = null ) {
 
 	const name = 'Geometry';
 	const attributes = geometry.attributes;
@@ -808,6 +829,41 @@ function buildMeshNode( geometry ) {
 
 	node.addProperty( 'uniform token subdivisionScheme = "none"' );
 
+	if ( materials !== null ) {
+
+		const groups = geometry.groups;
+
+		const totalFaces = ( geometry.index !== null
+			? geometry.index.count
+			: attributes.position.count ) / 3;
+
+		for ( let i = 0; i < groups.length; i ++ ) {
+
+			const group = groups[ i ];
+			const material = materials[ group.materialIndex ];
+
+			if ( material === undefined ) continue;
+
+			const startFace = Math.floor( group.start / 3 );
+			const endFace = Math.min( startFace + Math.floor( group.count / 3 ), totalFaces );
+
+			const indices = [];
+			for ( let j = startFace; j < endFace; j ++ ) indices.push( j );
+
+			const subsetNode = new USDNode( `subset_${i}`, 'GeomSubset' );
+			subsetNode.addMetadata( 'prepend apiSchemas', '["MaterialBindingAPI"]' );
+			subsetNode.addProperty( 'uniform token elementType = "face"' );
+			subsetNode.addProperty( 'uniform token familyName = "materialBind"' );
+			subsetNode.addProperty( `int[] indices = [${indices.join( ', ' )}]` );
+			subsetNode.addProperty(
+				`rel material:binding = </Materials/Material_${material.id}>`
+			);
+			node.addChild( subsetNode );
+
+		}
+
+	}
+
 	return node;
 
 }

粤ICP备19079148号