Selaa lähdekoodia

USDZLoader: Support files created with USDZExporter.

Mr.doob 2 vuotta sitten
vanhempi
commit
73581817a1
1 muutettua tiedostoa jossa 151 lisäystä ja 96 poistoa
  1. 151 96
      examples/jsm/loaders/USDZLoader.js

+ 151 - 96
examples/jsm/loaders/USDZLoader.js

@@ -11,6 +11,106 @@ import {
 
 import * as fflate from '../libs/fflate.module.js';
 
+class USDAParser {
+
+	parse( text ) {
+
+		const data = {};
+
+		const lines = text.split( '\n' );
+		const length = lines.length;
+
+		let current = 0;
+		let string = null;
+		let target = data;
+
+		const stack = [ data ];
+
+		// debugger;
+
+		function parseNextLine() {
+
+			const line = lines[ current ];
+
+			// console.log( line );
+
+			if ( line.includes( '=' ) ) {
+
+				const assignment = line.split( '=' );
+
+				const lhs = assignment[ 0 ].trim();
+				const rhs = assignment[ 1 ].trim();
+
+				if ( rhs.endsWith( '{' ) ) {
+
+					const group = {};
+					stack.push( group );
+
+					target[ lhs ] = group;
+					target = group;
+
+				} else {
+
+					target[ lhs ] = rhs;
+
+				}
+
+			} else if ( line.endsWith( '{' ) ) {
+
+				const group = target[ string ] || {};
+				stack.push( group );
+
+				target[ string ] = group;
+				target = group;
+
+			} else if ( line.endsWith( '}' ) ) {
+
+				stack.pop();
+
+				if ( stack.length === 0 ) return;
+
+				target = stack[ stack.length - 1 ];
+
+			} else if ( line.endsWith( '(' ) ) {
+
+				const meta = {};
+				stack.push( meta );
+
+				string = line.split( '(' )[ 0 ].trim() || string;
+
+				target[ string ] = meta;
+				target = meta;
+
+			} else if ( line.endsWith( ')' ) ) {
+
+				stack.pop();
+
+				target = stack[ stack.length - 1 ];
+
+			} else {
+
+				string = line.trim();
+
+			}
+
+			current ++;
+
+			if ( current < length ) {
+
+				parseNextLine();
+
+			}
+
+		}
+
+		parseNextLine();
+
+		return data;
+
+	}
+
+}
+
 class USDZLoader extends Loader {
 
 	constructor( manager ) {
@@ -56,7 +156,9 @@ class USDZLoader extends Loader {
 
 	parse( buffer ) {
 
-		function createImages( zip ) {
+		const parser = new USDAParser();
+
+		function parseAssets( zip ) {
 
 			const data = {};
 			const loader = new FileLoader();
@@ -71,6 +173,13 @@ class USDZLoader extends Loader {
 
 				}
 
+				if ( filename.endsWith( 'usd' ) ) {
+
+					const text = fflate.strFromU8( zip[ filename ] );
+					data[ filename ] = parser.parse( text );
+
+				}
+
 			}
 
 			return data;
@@ -95,7 +204,10 @@ class USDZLoader extends Loader {
 
 		// console.log( zip );
 
-		const images = createImages( zip );
+		const assets = parseAssets( zip );
+
+		// console.log( assets )
+
 		const file = findUSD( zip );
 
 		if ( file === undefined ) {
@@ -106,108 +218,51 @@ class USDZLoader extends Loader {
 
 		}
 
+
 		// Parse file
 
 		const text = fflate.strFromU8( file );
-		const lines = text.split( '\n' );
-		const length = lines.length;
-
-		const data = {};
+		const data = parser.parse( text );
 
-		let current = 0;
-		let string = null;
-		let target = data;
-
-		const stack = [ data ];
-
-		// debugger;
-
-		function parseNextLine() {
+		// Build scene
 
-			const line = lines[ current ];
+		function findGeometry( data, id ) {
 
-			// console.log( line );
+			if ( 'prepend references' in data ) {
 
-			if ( line.includes( '=' ) ) {
+				const reference = data[ 'prepend references' ];
+				const parts = reference.split( '@' );
+				const path = parts[ 1 ].replace( /^.\//, '' );
+				const id = parts[ 2 ].replace( /^<\//, '' ).replace( />$/, '' );
+				return findGeometry( assets[ path ], id );
 
-				const assignment = line.split( '=' );
-
-				const lhs = assignment[ 0 ].trim();
-				const rhs = assignment[ 1 ].trim();
-
-				if ( rhs.endsWith( '{' ) ) {
+			}
 
-					const group = {};
-					stack.push( group );
+			if ( id !== undefined ) {
 
-					target[ lhs ] = group;
-					target = group;
+				const def = `def "%{id}"`;
 
-				} else {
+				if ( def in data ) {
 
-					target[ lhs ] = rhs;
+					return data[ def ];
 
 				}
 
-			} else if ( line.endsWith( '{' ) ) {
-
-				const group = target[ string ] || {};
-				stack.push( group );
-
-				target[ string ] = group;
-				target = group;
-
-			} else if ( line.endsWith( '}' ) ) {
-
-				stack.pop();
-
-				if ( stack.length === 0 ) return;
-
-				target = stack[ stack.length - 1 ];
-
-			} else if ( line.endsWith( '(' ) ) {
-
-				const meta = {};
-				stack.push( meta );
-
-				string = line.split( '(' )[ 0 ].trim() || string;
-
-				target[ string ] = meta;
-				target = meta;
-
-			} else if ( line.endsWith( ')' ) ) {
-
-				stack.pop();
-
-				target = stack[ stack.length - 1 ];
-
-			} else {
-
-				string = line.trim();
-
 			}
 
-			current ++;
-
-			if ( current < length ) {
-
-				parseNextLine();
-
-			}
-
-		}
+			for ( const name in data ) {
 
-		parseNextLine();
+				const object = data[ name ];
 
-		// Build scene
+				if ( name.startsWith( 'def Mesh' ) ) {
 
-		function findGeometry( data ) {
+					// Move points to Mesh
 
-			for ( const name in data ) {
+					if ( data[ 'point3f[] points' ] ) {
 
-				const object = data[ name ];
+						object[ 'point3f[] points' ] = data[ 'point3f[] points' ];
 
-				if ( name.startsWith( 'def Mesh' ) ) {
+					}
 
 					// Move st indices to Mesh
 
@@ -241,7 +296,7 @@ class USDZLoader extends Loader {
 			const positions = JSON.parse( data[ 'point3f[] points' ].replace( /[()]*/g, '' ) );
 			const attribute = new BufferAttribute( new Float32Array( positions ), 3 );
 
-			if ( data[ 'int[] faceVertexIndices' ] ) {
+			if ( 'int[] faceVertexIndices' in data ) {
 
 				const indices = JSON.parse( data[ 'int[] faceVertexIndices' ] );
 				geometry.setAttribute( 'position', toFlatBufferAttribute( attribute, indices ) );
@@ -252,13 +307,12 @@ class USDZLoader extends Loader {
 
 			}
 
-
-			if ( data[ 'texCoord2f[] primvars:st' ] ) {
+			if ( 'texCoord2f[] primvars:st' in data ) {
 
 				const uvs = JSON.parse( data[ 'texCoord2f[] primvars:st' ].replace( /[()]*/g, '' ) );
 				const attribute = new BufferAttribute( new Float32Array( uvs ), 2 );
 
-				if ( data[ 'int[] primvars:st:indices' ] ) {
+				if ( 'int[] primvars:st:indices' in data ) {
 
 					const indices = JSON.parse( data[ 'int[] primvars:st:indices' ] );
 					geometry.setAttribute( 'uv', toFlatBufferAttribute( attribute, indices ) );
@@ -331,26 +385,27 @@ class USDZLoader extends Loader {
 
 			const material = new MeshStandardMaterial();
 
-			// console.log( data );
+			if ( data !== undefined ) {
 
-			if ( data[ 'def Shader "diffuseColor_texture"' ] ) {
+				if ( 'def Shader "diffuseColor_texture"' in data ) {
 
-				const texture = data[ 'def Shader "diffuseColor_texture"' ];
-				const file = texture[ 'asset inputs:file' ].replace( /@*/g, '' );
+					const texture = data[ 'def Shader "diffuseColor_texture"' ];
+					const file = texture[ 'asset inputs:file' ].replace( /@*/g, '' );
 
-				material.map = new TextureLoader().load( images[ file ] );
+					material.map = new TextureLoader().load( assets[ file ] );
 
-			}
+				}
 
-			if ( data[ 'def Shader "normal_texture"' ] ) {
+				if ( 'def Shader "normal_texture"' in data ) {
 
-				const texture = data[ 'def Shader "normal_texture"' ];
-				const file = texture[ 'asset inputs:file' ].replace( /@*/g, '' );
+					const texture = data[ 'def Shader "normal_texture"' ];
+					const file = texture[ 'asset inputs:file' ].replace( /@*/g, '' );
 
-				material.normalMap = new TextureLoader().load( images[ file ] );
+					material.normalMap = new TextureLoader().load( assets[ file ] );
 
-			}
+				}
 
+			}
 
 			return material;