Răsfoiți Sursa

JSM: Added module and TS file for AMFLoader.

Mugen87 6 ani în urmă
părinte
comite
e6558253c5

+ 1 - 0
docs/manual/en/introduction/Import-via-modules.html

@@ -117,6 +117,7 @@
 				<li>loaders
 					<ul>
 						<li>3MFLoader</li>
+						<li>AMFLoader</li>
 						<li>AssimpJSONLoader</li>
 						<li>AssimpLoader</li>
 						<li>BabylonLoader</li>

+ 14 - 0
examples/jsm/loaders/AMFLoader.d.ts

@@ -0,0 +1,14 @@
+import {
+  LoadingManager,
+  Group
+} from '../../../src/Three';
+
+export class AMFLoader {
+  constructor(manager?: LoadingManager);
+  manager: LoadingManager;
+  path: string;
+
+  load(url: string, onLoad: (object: Group) => void, onProgress?: (event: ProgressEvent) => void, onError?: (event: ErrorEvent) => void): void;
+  setPath(value: string): this;
+  parse(data: ArrayBuffer): Group;
+}

+ 509 - 0
examples/jsm/loaders/AMFLoader.js

@@ -0,0 +1,509 @@
+/*
+ * @author tamarintech / https://tamarintech.com
+ *
+ * Description: Early release of an AMF Loader following the pattern of the
+ * example loaders in the three.js project.
+ *
+ * More information about the AMF format: http://amf.wikispaces.com
+ *
+ * Usage:
+ *	var loader = new AMFLoader();
+ *	loader.load('/path/to/project.amf', function(objecttree) {
+ *		scene.add(objecttree);
+ *	});
+ *
+ * Materials now supported, material colors supported
+ * Zip support, requires jszip
+ * No constellation support (yet)!
+ *
+ */
+
+import {
+	BufferGeometry,
+	Color,
+	DefaultLoadingManager,
+	FileLoader,
+	Float32BufferAttribute,
+	Group,
+	LoaderUtils,
+	Mesh,
+	MeshPhongMaterial
+} from "../../../build/three.module.js";
+
+var AMFLoader = function ( manager ) {
+
+	this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
+
+};
+
+AMFLoader.prototype = {
+
+	constructor: AMFLoader,
+
+	load: function ( url, onLoad, onProgress, onError ) {
+
+		var scope = this;
+
+		var loader = new FileLoader( scope.manager );
+		loader.setPath( scope.path );
+		loader.setResponseType( 'arraybuffer' );
+		loader.load( url, function ( text ) {
+
+			onLoad( scope.parse( text ) );
+
+		}, onProgress, onError );
+
+	},
+
+	setPath: function ( value ) {
+
+		this.path = value;
+		return this;
+
+	},
+
+	parse: function ( data ) {
+
+		function loadDocument( data ) {
+
+			var view = new DataView( data );
+			var magic = String.fromCharCode( view.getUint8( 0 ), view.getUint8( 1 ) );
+
+			if ( magic === 'PK' ) {
+
+				var zip = null;
+				var file = null;
+
+				console.log( 'THREE.AMFLoader: Loading Zip' );
+
+				try {
+
+					zip = new JSZip( data ); // eslint-disable-line no-undef
+
+				} catch ( e ) {
+
+					if ( e instanceof ReferenceError ) {
+
+						console.log( 'THREE.AMFLoader: jszip missing and file is compressed.' );
+						return null;
+
+					}
+
+				}
+
+				for ( file in zip.files ) {
+
+					if ( file.toLowerCase().substr( - 4 ) === '.amf' ) {
+
+						break;
+
+					}
+
+				}
+
+				console.log( 'THREE.AMFLoader: Trying to load file asset: ' + file );
+				view = new DataView( zip.file( file ).asArrayBuffer() );
+
+			}
+
+			var fileText = LoaderUtils.decodeText( view );
+			var xmlData = new DOMParser().parseFromString( fileText, 'application/xml' );
+
+			if ( xmlData.documentElement.nodeName.toLowerCase() !== 'amf' ) {
+
+				console.log( 'THREE.AMFLoader: Error loading AMF - no AMF document found.' );
+				return null;
+
+			}
+
+			return xmlData;
+
+		}
+
+		function loadDocumentScale( node ) {
+
+			var scale = 1.0;
+			var unit = 'millimeter';
+
+			if ( node.documentElement.attributes.unit !== undefined ) {
+
+				unit = node.documentElement.attributes.unit.value.toLowerCase();
+
+			}
+
+			var scaleUnits = {
+				millimeter: 1.0,
+				inch: 25.4,
+				feet: 304.8,
+				meter: 1000.0,
+				micron: 0.001
+			};
+
+			if ( scaleUnits[ unit ] !== undefined ) {
+
+				scale = scaleUnits[ unit ];
+
+			}
+
+			console.log( 'THREE.AMFLoader: Unit scale: ' + scale );
+			return scale;
+
+		}
+
+		function loadMaterials( node ) {
+
+			var matName = 'AMF Material';
+			var matId = node.attributes.id.textContent;
+			var color = { r: 1.0, g: 1.0, b: 1.0, a: 1.0 };
+
+			var loadedMaterial = null;
+
+			for ( var i = 0; i < node.childNodes.length; i ++ ) {
+
+				var matChildEl = node.childNodes[ i ];
+
+				if ( matChildEl.nodeName === 'metadata' && matChildEl.attributes.type !== undefined ) {
+
+					if ( matChildEl.attributes.type.value === 'name' ) {
+
+						matName = matChildEl.textContent;
+
+					}
+
+				} else if ( matChildEl.nodeName === 'color' ) {
+
+					color = loadColor( matChildEl );
+
+				}
+
+			}
+
+			loadedMaterial = new MeshPhongMaterial( {
+				flatShading: true,
+				color: new Color( color.r, color.g, color.b ),
+				name: matName
+			} );
+
+			if ( color.a !== 1.0 ) {
+
+				loadedMaterial.transparent = true;
+				loadedMaterial.opacity = color.a;
+
+			}
+
+			return { id: matId, material: loadedMaterial };
+
+		}
+
+		function loadColor( node ) {
+
+			var color = { r: 1.0, g: 1.0, b: 1.0, a: 1.0 };
+
+			for ( var i = 0; i < node.childNodes.length; i ++ ) {
+
+				var matColor = node.childNodes[ i ];
+
+				if ( matColor.nodeName === 'r' ) {
+
+					color.r = matColor.textContent;
+
+				} else if ( matColor.nodeName === 'g' ) {
+
+					color.g = matColor.textContent;
+
+				} else if ( matColor.nodeName === 'b' ) {
+
+					color.b = matColor.textContent;
+
+				} else if ( matColor.nodeName === 'a' ) {
+
+					color.a = matColor.textContent;
+
+				}
+
+			}
+
+			return color;
+
+		}
+
+		function loadMeshVolume( node ) {
+
+			var volume = { name: '', triangles: [], materialid: null };
+
+			var currVolumeNode = node.firstElementChild;
+
+			if ( node.attributes.materialid !== undefined ) {
+
+				volume.materialId = node.attributes.materialid.nodeValue;
+
+			}
+
+			while ( currVolumeNode ) {
+
+				if ( currVolumeNode.nodeName === 'metadata' ) {
+
+					if ( currVolumeNode.attributes.type !== undefined ) {
+
+						if ( currVolumeNode.attributes.type.value === 'name' ) {
+
+							volume.name = currVolumeNode.textContent;
+
+						}
+
+					}
+
+				} else if ( currVolumeNode.nodeName === 'triangle' ) {
+
+					var v1 = currVolumeNode.getElementsByTagName( 'v1' )[ 0 ].textContent;
+					var v2 = currVolumeNode.getElementsByTagName( 'v2' )[ 0 ].textContent;
+					var v3 = currVolumeNode.getElementsByTagName( 'v3' )[ 0 ].textContent;
+
+					volume.triangles.push( v1, v2, v3 );
+
+				}
+
+				currVolumeNode = currVolumeNode.nextElementSibling;
+
+			}
+
+			return volume;
+
+		}
+
+		function loadMeshVertices( node ) {
+
+			var vertArray = [];
+			var normalArray = [];
+			var currVerticesNode = node.firstElementChild;
+
+			while ( currVerticesNode ) {
+
+				if ( currVerticesNode.nodeName === 'vertex' ) {
+
+					var vNode = currVerticesNode.firstElementChild;
+
+					while ( vNode ) {
+
+						if ( vNode.nodeName === 'coordinates' ) {
+
+							var x = vNode.getElementsByTagName( 'x' )[ 0 ].textContent;
+							var y = vNode.getElementsByTagName( 'y' )[ 0 ].textContent;
+							var z = vNode.getElementsByTagName( 'z' )[ 0 ].textContent;
+
+							vertArray.push( x, y, z );
+
+						} else if ( vNode.nodeName === 'normal' ) {
+
+							var nx = vNode.getElementsByTagName( 'nx' )[ 0 ].textContent;
+							var ny = vNode.getElementsByTagName( 'ny' )[ 0 ].textContent;
+							var nz = vNode.getElementsByTagName( 'nz' )[ 0 ].textContent;
+
+							normalArray.push( nx, ny, nz );
+
+						}
+
+						vNode = vNode.nextElementSibling;
+
+					}
+
+				}
+				currVerticesNode = currVerticesNode.nextElementSibling;
+
+			}
+
+			return { 'vertices': vertArray, 'normals': normalArray };
+
+		}
+
+		function loadObject( node ) {
+
+			var objId = node.attributes.id.textContent;
+			var loadedObject = { name: 'amfobject', meshes: [] };
+			var currColor = null;
+			var currObjNode = node.firstElementChild;
+
+			while ( currObjNode ) {
+
+				if ( currObjNode.nodeName === 'metadata' ) {
+
+					if ( currObjNode.attributes.type !== undefined ) {
+
+						if ( currObjNode.attributes.type.value === 'name' ) {
+
+							loadedObject.name = currObjNode.textContent;
+
+						}
+
+					}
+
+				} else if ( currObjNode.nodeName === 'color' ) {
+
+					currColor = loadColor( currObjNode );
+
+				} else if ( currObjNode.nodeName === 'mesh' ) {
+
+					var currMeshNode = currObjNode.firstElementChild;
+					var mesh = { vertices: [], normals: [], volumes: [], color: currColor };
+
+					while ( currMeshNode ) {
+
+						if ( currMeshNode.nodeName === 'vertices' ) {
+
+							var loadedVertices = loadMeshVertices( currMeshNode );
+
+							mesh.normals = mesh.normals.concat( loadedVertices.normals );
+							mesh.vertices = mesh.vertices.concat( loadedVertices.vertices );
+
+						} else if ( currMeshNode.nodeName === 'volume' ) {
+
+							mesh.volumes.push( loadMeshVolume( currMeshNode ) );
+
+						}
+
+						currMeshNode = currMeshNode.nextElementSibling;
+
+					}
+
+					loadedObject.meshes.push( mesh );
+
+				}
+
+				currObjNode = currObjNode.nextElementSibling;
+
+			}
+
+			return { 'id': objId, 'obj': loadedObject };
+
+		}
+
+		var xmlData = loadDocument( data );
+		var amfName = '';
+		var amfAuthor = '';
+		var amfScale = loadDocumentScale( xmlData );
+		var amfMaterials = {};
+		var amfObjects = {};
+		var childNodes = xmlData.documentElement.childNodes;
+
+		var i, j;
+
+		for ( i = 0; i < childNodes.length; i ++ ) {
+
+			var child = childNodes[ i ];
+
+			if ( child.nodeName === 'metadata' ) {
+
+				if ( child.attributes.type !== undefined ) {
+
+					if ( child.attributes.type.value === 'name' ) {
+
+						amfName = child.textContent;
+
+					} else if ( child.attributes.type.value === 'author' ) {
+
+						amfAuthor = child.textContent;
+
+					}
+
+				}
+
+			} else if ( child.nodeName === 'material' ) {
+
+				var loadedMaterial = loadMaterials( child );
+
+				amfMaterials[ loadedMaterial.id ] = loadedMaterial.material;
+
+			} else if ( child.nodeName === 'object' ) {
+
+				var loadedObject = loadObject( child );
+
+				amfObjects[ loadedObject.id ] = loadedObject.obj;
+
+			}
+
+		}
+
+		var sceneObject = new Group();
+		var defaultMaterial = new MeshPhongMaterial( { color: 0xaaaaff, flatShading: true } );
+
+		sceneObject.name = amfName;
+		sceneObject.userData.author = amfAuthor;
+		sceneObject.userData.loader = 'AMF';
+
+		for ( var id in amfObjects ) {
+
+			var part = amfObjects[ id ];
+			var meshes = part.meshes;
+			var newObject = new Group();
+			newObject.name = part.name || '';
+
+			for ( i = 0; i < meshes.length; i ++ ) {
+
+				var objDefaultMaterial = defaultMaterial;
+				var mesh = meshes[ i ];
+				var vertices = new Float32BufferAttribute( mesh.vertices, 3 );
+				var normals = null;
+
+				if ( mesh.normals.length ) {
+
+					normals = new Float32BufferAttribute( mesh.normals, 3 );
+
+				}
+
+				if ( mesh.color ) {
+
+					var color = mesh.color;
+
+					objDefaultMaterial = defaultMaterial.clone();
+					objDefaultMaterial.color = new Color( color.r, color.g, color.b );
+
+					if ( color.a !== 1.0 ) {
+
+						objDefaultMaterial.transparent = true;
+						objDefaultMaterial.opacity = color.a;
+
+					}
+
+				}
+
+				var volumes = mesh.volumes;
+
+				for ( j = 0; j < volumes.length; j ++ ) {
+
+					var volume = volumes[ j ];
+					var newGeometry = new BufferGeometry();
+					var material = objDefaultMaterial;
+
+					newGeometry.setIndex( volume.triangles );
+					newGeometry.addAttribute( 'position', vertices.clone() );
+
+					if ( normals ) {
+
+						newGeometry.addAttribute( 'normal', normals.clone() );
+
+					}
+
+					if ( amfMaterials[ volume.materialId ] !== undefined ) {
+
+						material = amfMaterials[ volume.materialId ];
+
+					}
+
+					newGeometry.scale( amfScale, amfScale, amfScale );
+					newObject.add( new Mesh( newGeometry, material.clone() ) );
+
+				}
+
+			}
+
+			sceneObject.add( newObject );
+
+		}
+
+		return sceneObject;
+
+	}
+
+};
+
+export { AMFLoader };

+ 1 - 0
utils/modularize.js

@@ -35,6 +35,7 @@ var files = [
 	{ path: 'exporters/TypedGeometryExporter.js', dependencies: [], ignoreList: [] },
 
 	{ path: 'loaders/3MFLoader.js', dependencies: [], ignoreList: [] },
+	{ path: 'loaders/AMFLoader.js', dependencies: [], ignoreList: [] },
 	{ path: 'loaders/AssimpJSONLoader.js', dependencies: [], ignoreList: [] },
 	{ path: 'loaders/AssimpLoader.js', dependencies: [], ignoreList: [] },
 	{ path: 'loaders/BabylonLoader.js', dependencies: [], ignoreList: [] },