ソースを参照

Examples: Removed misc_exporter_collada.

Mr.doob 2 年 前
コミット
973d751be7

+ 0 - 1
examples/files.json

@@ -387,7 +387,6 @@
 		"misc_controls_pointerlock",
 		"misc_controls_trackball",
 		"misc_controls_transform",
-		"misc_exporter_collada",
 		"misc_exporter_draco",
 		"misc_exporter_gltf",
 		"misc_exporter_obj",

+ 0 - 725
examples/jsm/exporters/ColladaExporter.js

@@ -1,725 +0,0 @@
-import {
-	Color,
-	DoubleSide,
-	Matrix4,
-	MeshBasicMaterial
-} from 'three';
-
-/**
- * https://github.com/gkjohnson/collada-exporter-js
- *
- * Usage:
- *  const exporter = new ColladaExporter();
- *
- *  const data = exporter.parse(mesh);
- *
- * Format Definition:
- *  https://www.khronos.org/collada/
- */
-
-class ColladaExporter {
-
-	parse( object, onDone, options = {} ) {
-
-		options = Object.assign( {
-			version: '1.4.1',
-			author: null,
-			textureDirectory: '',
-			upAxis: 'Y_UP',
-			unitName: null,
-			unitMeter: null,
-		}, options );
-
-		if ( options.upAxis.match( /^[XYZ]_UP$/ ) === null ) {
-
-			console.error( 'ColladaExporter: Invalid upAxis: valid values are X_UP, Y_UP or Z_UP.' );
-			return null;
-
-		}
-
-		if ( options.unitName !== null && options.unitMeter === null ) {
-
-			console.error( 'ColladaExporter: unitMeter needs to be specified if unitName is specified.' );
-			return null;
-
-		}
-
-		if ( options.unitMeter !== null && options.unitName === null ) {
-
-			console.error( 'ColladaExporter: unitName needs to be specified if unitMeter is specified.' );
-			return null;
-
-		}
-
-		if ( options.textureDirectory !== '' ) {
-
-			options.textureDirectory = `${ options.textureDirectory }/`
-				.replace( /\\/g, '/' )
-				.replace( /\/+/g, '/' );
-
-		}
-
-		const version = options.version;
-
-		if ( version !== '1.4.1' && version !== '1.5.0' ) {
-
-			console.warn( `ColladaExporter : Version ${ version } not supported for export. Only 1.4.1 and 1.5.0.` );
-			return null;
-
-		}
-
-		// Convert the urdf xml into a well-formatted, indented format
-		function format( urdf ) {
-
-			const IS_END_TAG = /^<\//;
-			const IS_SELF_CLOSING = /(\?>$)|(\/>$)/;
-			const HAS_TEXT = /<[^>]+>[^<]*<\/[^<]+>/;
-
-			const pad = ( ch, num ) => ( num > 0 ? ch + pad( ch, num - 1 ) : '' );
-
-			let tagnum = 0;
-
-			return urdf
-				.match( /(<[^>]+>[^<]+<\/[^<]+>)|(<[^>]+>)/g )
-				.map( tag => {
-
-					if ( ! HAS_TEXT.test( tag ) && ! IS_SELF_CLOSING.test( tag ) && IS_END_TAG.test( tag ) ) {
-
-						tagnum --;
-
-					}
-
-					const res = `${ pad( '  ', tagnum ) }${ tag }`;
-
-					if ( ! HAS_TEXT.test( tag ) && ! IS_SELF_CLOSING.test( tag ) && ! IS_END_TAG.test( tag ) ) {
-
-						tagnum ++;
-
-					}
-
-					return res;
-
-				} )
-				.join( '\n' );
-
-		}
-
-		// Convert an image into a png format for saving
-		function base64ToBuffer( str ) {
-
-			const b = atob( str );
-			const buf = new Uint8Array( b.length );
-
-			for ( let i = 0, l = buf.length; i < l; i ++ ) {
-
-				buf[ i ] = b.charCodeAt( i );
-
-			}
-
-			return buf;
-
-		}
-
-		let canvas, ctx;
-
-		function imageToData( image, ext ) {
-
-			if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) ||
-				( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) ||
-				( typeof OffscreenCanvas !== 'undefined' && image instanceof OffscreenCanvas ) ||
-				( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) {
-
-				canvas = canvas || document.createElement( 'canvas' );
-				ctx = ctx || canvas.getContext( '2d' );
-
-				canvas.width = image.width;
-				canvas.height = image.height;
-
-				ctx.drawImage( image, 0, 0 );
-
-				// Get the base64 encoded data
-				const base64data = canvas
-					.toDataURL( `image/${ ext }`, 1 )
-					.replace( /^data:image\/(png|jpg);base64,/, '' );
-
-				// Convert to a uint8 array
-				return base64ToBuffer( base64data );
-
-			} else {
-
-				throw new Error( 'THREE.ColladaExporter: No valid image data found. Unable to process texture.' );
-
-			}
-
-		}
-
-		// gets the attribute array. Generate a new array if the attribute is interleaved
-		const getFuncs = [ 'getX', 'getY', 'getZ', 'getW' ];
-		const tempColor = new Color();
-
-		function attrBufferToArray( attr, isColor = false ) {
-
-			if ( isColor ) {
-
-				// convert the colors to srgb before export
-				// colors are always written as floats
-				const arr = new Float32Array( attr.count * 3 );
-				for ( let i = 0, l = attr.count; i < l; i ++ ) {
-
-					tempColor
-						.fromBufferAttribute( attr, i )
-						.convertLinearToSRGB();
-
-					arr[ 3 * i + 0 ] = tempColor.r;
-					arr[ 3 * i + 1 ] = tempColor.g;
-					arr[ 3 * i + 2 ] = tempColor.b;
-
-				}
-
-				return arr;
-
-			} else if ( attr.isInterleavedBufferAttribute ) {
-
-				// use the typed array constructor to save on memory
-				const arr = new attr.array.constructor( attr.count * attr.itemSize );
-				const size = attr.itemSize;
-
-				for ( let i = 0, l = attr.count; i < l; i ++ ) {
-
-					for ( let j = 0; j < size; j ++ ) {
-
-						arr[ i * size + j ] = attr[ getFuncs[ j ] ]( i );
-
-					}
-
-				}
-
-				return arr;
-
-			} else {
-
-				return attr.array;
-
-			}
-
-		}
-
-		// Returns an array of the same type starting at the `st` index,
-		// and `ct` length
-		function subArray( arr, st, ct ) {
-
-			if ( Array.isArray( arr ) ) return arr.slice( st, st + ct );
-			else return new arr.constructor( arr.buffer, st * arr.BYTES_PER_ELEMENT, ct );
-
-		}
-
-		// Returns the string for a geometry's attribute
-		function getAttribute( attr, name, params, type, isColor = false ) {
-
-			const array = attrBufferToArray( attr, isColor );
-			const res =
-					`<source id="${ name }">` +
-
-					`<float_array id="${ name }-array" count="${ array.length }">` +
-					array.join( ' ' ) +
-					'</float_array>' +
-
-					'<technique_common>' +
-					`<accessor source="#${ name }-array" count="${ Math.floor( array.length / attr.itemSize ) }" stride="${ attr.itemSize }">` +
-
-					params.map( n => `<param name="${ n }" type="${ type }" />` ).join( '' ) +
-
-					'</accessor>' +
-					'</technique_common>' +
-					'</source>';
-
-			return res;
-
-		}
-
-		// Returns the string for a node's transform information
-		let transMat;
-		function getTransform( o ) {
-
-			// ensure the object's matrix is up to date
-			// before saving the transform
-			o.updateMatrix();
-
-			transMat = transMat || new Matrix4();
-			transMat.copy( o.matrix );
-			transMat.transpose();
-			return `<matrix>${ transMat.toArray().join( ' ' ) }</matrix>`;
-
-		}
-
-		// Process the given piece of geometry into the geometry library
-		// Returns the mesh id
-		function processGeometry( bufferGeometry ) {
-
-			let info = geometryInfo.get( bufferGeometry );
-
-			if ( ! info ) {
-
-				const meshid = `Mesh${ libraryGeometries.length + 1 }`;
-
-				const indexCount =
-					bufferGeometry.index ?
-						bufferGeometry.index.count * bufferGeometry.index.itemSize :
-						bufferGeometry.attributes.position.count;
-
-				const groups =
-					bufferGeometry.groups != null && bufferGeometry.groups.length !== 0 ?
-						bufferGeometry.groups :
-						[ { start: 0, count: indexCount, materialIndex: 0 } ];
-
-
-				const gname = bufferGeometry.name ? ` name="${ bufferGeometry.name }"` : '';
-				let gnode = `<geometry id="${ meshid }"${ gname }><mesh>`;
-
-				// define the geometry node and the vertices for the geometry
-				const posName = `${ meshid }-position`;
-				const vertName = `${ meshid }-vertices`;
-				gnode += getAttribute( bufferGeometry.attributes.position, posName, [ 'X', 'Y', 'Z' ], 'float' );
-				gnode += `<vertices id="${ vertName }"><input semantic="POSITION" source="#${ posName }" /></vertices>`;
-
-				// NOTE: We're not optimizing the attribute arrays here, so they're all the same length and
-				// can therefore share the same triangle indices. However, MeshLab seems to have trouble opening
-				// models with attributes that share an offset.
-				// MeshLab Bug#424: https://sourceforge.net/p/meshlab/bugs/424/
-
-				// serialize normals
-				let triangleInputs = `<input semantic="VERTEX" source="#${ vertName }" offset="0" />`;
-				if ( 'normal' in bufferGeometry.attributes ) {
-
-					const normName = `${ meshid }-normal`;
-					gnode += getAttribute( bufferGeometry.attributes.normal, normName, [ 'X', 'Y', 'Z' ], 'float' );
-					triangleInputs += `<input semantic="NORMAL" source="#${ normName }" offset="0" />`;
-
-				}
-
-				// serialize uvs
-				if ( 'uv' in bufferGeometry.attributes ) {
-
-					const uvName = `${ meshid }-texcoord`;
-					gnode += getAttribute( bufferGeometry.attributes.uv, uvName, [ 'S', 'T' ], 'float' );
-					triangleInputs += `<input semantic="TEXCOORD" source="#${ uvName }" offset="0" set="0" />`;
-
-				}
-
-				// serialize lightmap uvs
-				if ( 'uv1' in bufferGeometry.attributes ) {
-
-					const uvName = `${ meshid }-texcoord2`;
-					gnode += getAttribute( bufferGeometry.attributes.uv1, uvName, [ 'S', 'T' ], 'float' );
-					triangleInputs += `<input semantic="TEXCOORD" source="#${ uvName }" offset="0" set="1" />`;
-
-				}
-
-				// serialize colors
-				if ( 'color' in bufferGeometry.attributes ) {
-
-					// colors are always written as floats
-					const colName = `${ meshid }-color`;
-					gnode += getAttribute( bufferGeometry.attributes.color, colName, [ 'R', 'G', 'B' ], 'float', true );
-					triangleInputs += `<input semantic="COLOR" source="#${ colName }" offset="0" />`;
-
-				}
-
-				let indexArray = null;
-				if ( bufferGeometry.index ) {
-
-					indexArray = attrBufferToArray( bufferGeometry.index );
-
-				} else {
-
-					indexArray = new Array( indexCount );
-					for ( let i = 0, l = indexArray.length; i < l; i ++ ) indexArray[ i ] = i;
-
-				}
-
-				for ( let i = 0, l = groups.length; i < l; i ++ ) {
-
-					const group = groups[ i ];
-					const subarr = subArray( indexArray, group.start, group.count );
-					const polycount = subarr.length / 3;
-					gnode += `<triangles material="MESH_MATERIAL_${ group.materialIndex }" count="${ polycount }">`;
-					gnode += triangleInputs;
-
-					gnode += `<p>${ subarr.join( ' ' ) }</p>`;
-					gnode += '</triangles>';
-
-				}
-
-				gnode += '</mesh></geometry>';
-
-				libraryGeometries.push( gnode );
-
-				info = { meshid: meshid, bufferGeometry: bufferGeometry };
-				geometryInfo.set( bufferGeometry, info );
-
-			}
-
-			return info;
-
-		}
-
-		// Process the given texture into the image library
-		// Returns the image library
-		function processTexture( tex ) {
-
-			let texid = imageMap.get( tex );
-
-			if ( texid === undefined ) {
-
-				texid = `image-${ libraryImages.length + 1 }`;
-
-				const ext = 'png';
-				const name = tex.name || texid;
-				let imageNode = `<image id="${ texid }" name="${ name }">`;
-
-				if ( version === '1.5.0' ) {
-
-					imageNode += `<init_from><ref>${ options.textureDirectory }${ name }.${ ext }</ref></init_from>`;
-
-				} else {
-
-					// version image node 1.4.1
-					imageNode += `<init_from>${ options.textureDirectory }${ name }.${ ext }</init_from>`;
-
-				}
-
-				imageNode += '</image>';
-
-				libraryImages.push( imageNode );
-				imageMap.set( tex, texid );
-				textures.push( {
-					directory: options.textureDirectory,
-					name,
-					ext,
-					data: imageToData( tex.image, ext ),
-					original: tex
-				} );
-
-			}
-
-			return texid;
-
-		}
-
-		// Process the given material into the material and effect libraries
-		// Returns the material id
-		function processMaterial( m ) {
-
-			let matid = materialMap.get( m );
-
-			if ( matid == null ) {
-
-				matid = `Mat${ libraryEffects.length + 1 }`;
-
-				let type = 'phong';
-
-				if ( m.isMeshLambertMaterial === true ) {
-
-					type = 'lambert';
-
-				} else if ( m.isMeshBasicMaterial === true ) {
-
-					type = 'constant';
-
-					if ( m.map !== null ) {
-
-						// The Collada spec does not support diffuse texture maps with the
-						// constant shader type.
-						// mrdoob/three.js#15469
-						console.warn( 'ColladaExporter: Texture maps not supported with MeshBasicMaterial.' );
-
-					}
-
-				}
-
-				const emissive = m.emissive ? m.emissive : new Color( 0, 0, 0 );
-				const diffuse = m.color ? m.color : new Color( 0, 0, 0 );
-				const specular = m.specular ? m.specular : new Color( 1, 1, 1 );
-				const shininess = m.shininess || 0;
-				const reflectivity = m.reflectivity || 0;
-
-				emissive.convertLinearToSRGB();
-				specular.convertLinearToSRGB();
-				diffuse.convertLinearToSRGB();
-
-				// Do not export and alpha map for the reasons mentioned in issue (#13792)
-				// in three.js alpha maps are black and white, but collada expects the alpha
-				// channel to specify the transparency
-				let transparencyNode = '';
-				if ( m.transparent === true ) {
-
-					transparencyNode +=
-						'<transparent>' +
-						(
-							m.map ?
-								'<texture texture="diffuse-sampler"></texture>' :
-								'<float>1</float>'
-						) +
-						'</transparent>';
-
-					if ( m.opacity < 1 ) {
-
-						transparencyNode += `<transparency><float>${ m.opacity }</float></transparency>`;
-
-					}
-
-				}
-
-				const techniqueNode = `<technique sid="common"><${ type }>` +
-
-					'<emission>' +
-
-					(
-						m.emissiveMap ?
-							'<texture texture="emissive-sampler" texcoord="TEXCOORD" />' :
-							`<color sid="emission">${ emissive.r } ${ emissive.g } ${ emissive.b } 1</color>`
-					) +
-
-					'</emission>' +
-
-					(
-						type !== 'constant' ?
-							'<diffuse>' +
-
-						(
-							m.map ?
-								'<texture texture="diffuse-sampler" texcoord="TEXCOORD" />' :
-								`<color sid="diffuse">${ diffuse.r } ${ diffuse.g } ${ diffuse.b } 1</color>`
-						) +
-						'</diffuse>'
-							: ''
-					) +
-
-					(
-						type !== 'constant' ?
-							'<bump>' +
-
-						(
-							m.normalMap ? '<texture texture="bump-sampler" texcoord="TEXCOORD" />' : ''
-						) +
-						'</bump>'
-							: ''
-					) +
-
-					(
-						type === 'phong' ?
-							`<specular><color sid="specular">${ specular.r } ${ specular.g } ${ specular.b } 1</color></specular>` +
-
-						'<shininess>' +
-
-						(
-							m.specularMap ?
-								'<texture texture="specular-sampler" texcoord="TEXCOORD" />' :
-								`<float sid="shininess">${ shininess }</float>`
-						) +
-
-						'</shininess>'
-							: ''
-					) +
-
-					`<reflective><color>${ diffuse.r } ${ diffuse.g } ${ diffuse.b } 1</color></reflective>` +
-
-					`<reflectivity><float>${ reflectivity }</float></reflectivity>` +
-
-					transparencyNode +
-
-					`</${ type }></technique>`;
-
-				const effectnode =
-					`<effect id="${ matid }-effect">` +
-					'<profile_COMMON>' +
-
-					(
-						m.map ?
-							'<newparam sid="diffuse-surface"><surface type="2D">' +
-							`<init_from>${ processTexture( m.map ) }</init_from>` +
-							'</surface></newparam>' +
-							'<newparam sid="diffuse-sampler"><sampler2D><source>diffuse-surface</source></sampler2D></newparam>' :
-							''
-					) +
-
-					(
-						m.specularMap ?
-							'<newparam sid="specular-surface"><surface type="2D">' +
-							`<init_from>${ processTexture( m.specularMap ) }</init_from>` +
-							'</surface></newparam>' +
-							'<newparam sid="specular-sampler"><sampler2D><source>specular-surface</source></sampler2D></newparam>' :
-							''
-					) +
-
-					(
-						m.emissiveMap ?
-							'<newparam sid="emissive-surface"><surface type="2D">' +
-							`<init_from>${ processTexture( m.emissiveMap ) }</init_from>` +
-							'</surface></newparam>' +
-							'<newparam sid="emissive-sampler"><sampler2D><source>emissive-surface</source></sampler2D></newparam>' :
-							''
-					) +
-
-					(
-						m.normalMap ?
-							'<newparam sid="bump-surface"><surface type="2D">' +
-							`<init_from>${ processTexture( m.normalMap ) }</init_from>` +
-							'</surface></newparam>' +
-							'<newparam sid="bump-sampler"><sampler2D><source>bump-surface</source></sampler2D></newparam>' :
-							''
-					) +
-
-					techniqueNode +
-
-					(
-						m.side === DoubleSide ?
-							'<extra><technique profile="THREEJS"><double_sided sid="double_sided" type="int">1</double_sided></technique></extra>' :
-							''
-					) +
-
-					'</profile_COMMON>' +
-
-					'</effect>';
-
-				const materialName = m.name ? ` name="${ m.name }"` : '';
-				const materialNode = `<material id="${ matid }"${ materialName }><instance_effect url="#${ matid }-effect" /></material>`;
-
-				libraryMaterials.push( materialNode );
-				libraryEffects.push( effectnode );
-				materialMap.set( m, matid );
-
-			}
-
-			return matid;
-
-		}
-
-		// Recursively process the object into a scene
-		function processObject( o ) {
-
-			let node = `<node name="${ o.name }">`;
-
-			node += getTransform( o );
-
-			if ( o.isMesh === true && o.geometry !== null ) {
-
-				// function returns the id associated with the mesh and a "BufferGeometry" version
-				// of the geometry in case it's not a geometry.
-				const geomInfo = processGeometry( o.geometry );
-				const meshid = geomInfo.meshid;
-				const geometry = geomInfo.bufferGeometry;
-
-				// ids of the materials to bind to the geometry
-				let matids = null;
-				let matidsArray;
-
-				// get a list of materials to bind to the sub groups of the geometry.
-				// If the amount of subgroups is greater than the materials, than reuse
-				// the materials.
-				const mat = o.material || new MeshBasicMaterial();
-				const materials = Array.isArray( mat ) ? mat : [ mat ];
-
-				if ( geometry.groups.length > materials.length ) {
-
-					matidsArray = new Array( geometry.groups.length );
-
-				} else {
-
-					matidsArray = new Array( materials.length );
-
-				}
-
-				matids = matidsArray.fill().map( ( v, i ) => processMaterial( materials[ i % materials.length ] ) );
-
-				node +=
-					`<instance_geometry url="#${ meshid }">` +
-
-					(
-						matids.length > 0 ?
-							'<bind_material><technique_common>' +
-							matids.map( ( id, i ) =>
-
-								`<instance_material symbol="MESH_MATERIAL_${ i }" target="#${ id }" >` +
-
-								'<bind_vertex_input semantic="TEXCOORD" input_semantic="TEXCOORD" input_set="0" />' +
-
-								'</instance_material>'
-							).join( '' ) +
-							'</technique_common></bind_material>' :
-							''
-					) +
-
-					'</instance_geometry>';
-
-			}
-
-			o.children.forEach( c => node += processObject( c ) );
-
-			node += '</node>';
-
-			return node;
-
-		}
-
-		const geometryInfo = new WeakMap();
-		const materialMap = new WeakMap();
-		const imageMap = new WeakMap();
-		const textures = [];
-
-		const libraryImages = [];
-		const libraryGeometries = [];
-		const libraryEffects = [];
-		const libraryMaterials = [];
-		const libraryVisualScenes = processObject( object );
-
-		const specLink = version === '1.4.1' ? 'http://www.collada.org/2005/11/COLLADASchema' : 'https://www.khronos.org/collada/';
-		let dae =
-			'<?xml version="1.0" encoding="UTF-8" standalone="no" ?>' +
-			`<COLLADA xmlns="${ specLink }" version="${ version }">` +
-			'<asset>' +
-			(
-				'<contributor>' +
-				'<authoring_tool>three.js Collada Exporter</authoring_tool>' +
-				( options.author !== null ? `<author>${ options.author }</author>` : '' ) +
-				'</contributor>' +
-				`<created>${ ( new Date() ).toISOString() }</created>` +
-				`<modified>${ ( new Date() ).toISOString() }</modified>` +
-				( options.unitName !== null ? `<unit name="${ options.unitName }" meter="${ options.unitMeter }" />` : '' ) +
-				`<up_axis>${ options.upAxis }</up_axis>`
-			) +
-			'</asset>';
-
-		dae += `<library_images>${ libraryImages.join( '' ) }</library_images>`;
-
-		dae += `<library_effects>${ libraryEffects.join( '' ) }</library_effects>`;
-
-		dae += `<library_materials>${ libraryMaterials.join( '' ) }</library_materials>`;
-
-		dae += `<library_geometries>${ libraryGeometries.join( '' ) }</library_geometries>`;
-
-		dae += `<library_visual_scenes><visual_scene id="Scene" name="scene">${ libraryVisualScenes }</visual_scene></library_visual_scenes>`;
-
-		dae += '<scene><instance_visual_scene url="#Scene"/></scene>';
-
-		dae += '</COLLADA>';
-
-		const res = {
-			data: format( dae ),
-			textures
-		};
-
-		if ( typeof onDone === 'function' ) {
-
-			requestAnimationFrame( () => onDone( res ) );
-
-		}
-
-		return res;
-
-	}
-
-}
-
-
-export { ColladaExporter };

+ 0 - 457
examples/misc_exporter_collada.html

@@ -1,457 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-	<head>
-		<title>three.js webgl - exporter - collada</title>
-		<meta charset="utf-8">
-		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
-		<link type="text/css" rel="stylesheet" href="main.css">
-	</head>
-	<body>
-		<div id="info">
-			<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> webgl - exporter - collada
-		</div>
-
-		<!-- Import maps polyfill -->
-		<!-- Remove this when import maps will be widely supported -->
-		<script async src="https://unpkg.com/[email protected]/dist/es-module-shims.js"></script>
-
-		<script type="importmap">
-			{
-				"imports": {
-					"three": "../build/three.module.js",
-					"three/addons/": "./jsm/"
-				}
-			}
-		</script>
-
-		<script type="module">
-
-			import * as THREE from 'three';
-
-			import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
-
-			import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
-			import { ColladaExporter } from 'three/addons/exporters/ColladaExporter.js';
-			import { TeapotGeometry } from 'three/addons/geometries/TeapotGeometry.js';
-
-			////////////////////////////////////////////////////////////////////////////////
-			// Utah/Newell Teapot demo
-			////////////////////////////////////////////////////////////////////////////////
-			/*global window */
-
-			let camera, scene, renderer;
-			let cameraControls;
-			let effectController;
-			const teapotSize = 100; // vertical height of the teapot is about 2x this, we scale it to millimeters.
-			let ambientLight, light;
-
-			let tess = - 1;	// force initialization
-			let bBottom;
-			let bLid;
-			let bBody;
-			let bFitLid;
-			let bNonBlinn;
-			let shading;
-			let vertexColors;
-			let wireMaterial, flatMaterial, gouraudMaterial, phongMaterial, texturedMaterial, normalMaterial, reflectiveMaterial;
-
-			let teapot, textureCube;
-
-			// allocate these just once
-			const diffuseColor = new THREE.Color();
-			const specularColor = new THREE.Color();
-
-			init();
-			render();
-
-			function init() {
-
-				const container = document.createElement( 'div' );
-				document.body.appendChild( container );
-
-				const canvasWidth = window.innerWidth;
-				const canvasHeight = window.innerHeight;
-
-				// CAMERA
-				camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 20000 );
-				camera.position.set( - 150, 137.5, 325 );
-
-				// LIGHTS
-				ambientLight = new THREE.AmbientLight( 0x333333 );	// 0.2
-
-				light = new THREE.DirectionalLight( 0xFFFFFF, 1.0 );
-				// direction is set in GUI
-
-				// RENDERER
-				renderer = new THREE.WebGLRenderer( { antialias: true } );
-				renderer.setPixelRatio( window.devicePixelRatio );
-				renderer.setSize( canvasWidth, canvasHeight );
-				container.appendChild( renderer.domElement );
-
-				// EVENTS
-				window.addEventListener( 'resize', onWindowResize );
-
-				// CONTROLS
-				cameraControls = new OrbitControls( camera, renderer.domElement );
-				cameraControls.addEventListener( 'change', render );
-
-				// TEXTURE MAP
-				const loader = new THREE.TextureLoader();
-
-				const textureMap = loader.load( 'textures/uv_grid_opengl.jpg' );
-				textureMap.wrapS = textureMap.wrapT = THREE.RepeatWrapping;
-				textureMap.anisotropy = 16;
-				textureMap.colorSpace = THREE.SRGBColorSpace;
-
-				// NORMAL MAP
-
-				const diffuseMap = loader.load( 'textures/floors/FloorsCheckerboard_S_Diffuse.jpg' );
-				const normalMap = loader.load( 'textures/floors/FloorsCheckerboard_S_Normal.jpg' );
-
-				// REFLECTION MAP
-				const path = 'textures/cube/pisa/';
-				const urls = [
-					path + 'px.png', path + 'nx.png',
-					path + 'py.png', path + 'ny.png',
-					path + 'pz.png', path + 'nz.png'
-				];
-
-				textureCube = new THREE.CubeTextureLoader().load( urls );
-				textureCube.colorSpace = THREE.SRGBColorSpace;
-
-				// MATERIALS
-				const materialColor = new THREE.Color();
-				materialColor.setRGB( 1.0, 1.0, 1.0 );
-
-				wireMaterial = new THREE.MeshBasicMaterial( { color: 0xFFFFFF, wireframe: true } );
-
-				flatMaterial = new THREE.MeshPhongMaterial( { color: materialColor, specular: 0x000000, flatShading: true, side: THREE.DoubleSide } );
-
-				gouraudMaterial = new THREE.MeshLambertMaterial( { color: materialColor, side: THREE.DoubleSide } );
-
-				phongMaterial = new THREE.MeshPhongMaterial( { color: materialColor, side: THREE.DoubleSide } );
-
-				texturedMaterial = new THREE.MeshPhongMaterial( { color: materialColor, map: textureMap, side: THREE.DoubleSide } );
-
-				normalMaterial = new THREE.MeshPhongMaterial( { color: materialColor, map: diffuseMap, normalMap: normalMap, side: THREE.DoubleSide } );
-
-				reflectiveMaterial = new THREE.MeshPhongMaterial( { color: materialColor, envMap: textureCube, side: THREE.DoubleSide } );
-
-				// scene itself
-				scene = new THREE.Scene();
-				scene.background = new THREE.Color( 0xAAAAAA );
-
-				scene.add( ambientLight );
-				scene.add( light );
-
-				// GUI
-				setupGui();
-
-			}
-
-			// EVENT HANDLERS
-
-			function onWindowResize() {
-
-				const canvasWidth = window.innerWidth;
-				const canvasHeight = window.innerHeight;
-
-				renderer.setSize( canvasWidth, canvasHeight );
-
-				camera.aspect = canvasWidth / canvasHeight;
-				camera.updateProjectionMatrix();
-
-				render();
-
-			}
-
-			function setupGui() {
-
-				effectController = {
-
-					shininess: 40.0,
-					ka: 0.17,
-					kd: 0.51,
-					ks: 0.2,
-					metallic: true,
-
-					hue:	0.121,
-					saturation: 0.73,
-					lightness: 0.66,
-
-					lhue:	0.04,
-					lsaturation: 0.01,	// non-zero so that fractions will be shown
-					llightness: 1.0,
-					vertexColors: false,
-
-					// bizarrely, if you initialize these with negative numbers, the sliders
-					// will not show any decimal places.
-					lx: 0.32,
-					ly: 0.39,
-					lz: 0.7,
-					newTess: 15,
-					bottom: true,
-					lid: true,
-					body: true,
-					fitLid: false,
-					nonblinn: false,
-					newShading: 'glossy',
-
-					export: exportCollada
-				};
-
-				let h;
-
-				const gui = new GUI();
-
-				// material (attributes)
-
-				h = gui.addFolder( 'Material control' );
-
-				h.add( effectController, 'shininess', 1.0, 400.0, 1.0 ).name( 'shininess' ).onChange( render );
-				h.add( effectController, 'kd', 0.0, 1.0, 0.025 ).name( 'diffuse strength' ).onChange( render );
-				h.add( effectController, 'ks', 0.0, 1.0, 0.025 ).name( 'specular strength' ).onChange( render );
-				h.add( effectController, 'metallic' ).onChange( render );
-
-				// material (color)
-
-				h = gui.addFolder( 'Material color' );
-
-				h.add( effectController, 'hue', 0.0, 1.0, 0.025 ).name( 'hue' ).onChange( render );
-				h.add( effectController, 'saturation', 0.0, 1.0, 0.025 ).name( 'saturation' ).onChange( render );
-				h.add( effectController, 'lightness', 0.0, 1.0, 0.025 ).name( 'lightness' ).onChange( render );
-				h.add( effectController, 'vertexColors' ).onChange( render );
-
-				// light (point)
-
-				h = gui.addFolder( 'Lighting' );
-
-				h.add( effectController, 'lhue', 0.0, 1.0, 0.025 ).name( 'hue' ).onChange( render );
-				h.add( effectController, 'lsaturation', 0.0, 1.0, 0.025 ).name( 'saturation' ).onChange( render );
-				h.add( effectController, 'llightness', 0.0, 1.0, 0.025 ).name( 'lightness' ).onChange( render );
-				h.add( effectController, 'ka', 0.0, 1.0, 0.025 ).name( 'ambient' ).onChange( render );
-
-				// light (directional)
-
-				h = gui.addFolder( 'Light direction' );
-
-				h.add( effectController, 'lx', - 1.0, 1.0, 0.025 ).name( 'x' ).onChange( render );
-				h.add( effectController, 'ly', - 1.0, 1.0, 0.025 ).name( 'y' ).onChange( render );
-				h.add( effectController, 'lz', - 1.0, 1.0, 0.025 ).name( 'z' ).onChange( render );
-
-				h = gui.addFolder( 'Tessellation control' );
-				h.add( effectController, 'newTess', [ 2, 3, 4, 5, 6, 8, 10, 15, 20, 30, 40, 50 ] ).name( 'Tessellation Level' ).onChange( render );
-				h.add( effectController, 'lid' ).name( 'display lid' ).onChange( render );
-				h.add( effectController, 'body' ).name( 'display body' ).onChange( render );
-				h.add( effectController, 'bottom' ).name( 'display bottom' ).onChange( render );
-				h.add( effectController, 'fitLid' ).name( 'snug lid' ).onChange( render );
-				h.add( effectController, 'nonblinn' ).name( 'original scale' ).onChange( render );
-
-				// shading
-
-				gui.add( effectController, 'newShading', [ 'wireframe', 'flat', 'smooth', 'glossy', 'textured', 'normal', 'reflective' ] ).name( 'Shading' ).onChange( render );
-
-				h = gui.addFolder( 'Export' );
-				h.add( effectController, 'export' ).name( 'Export Collada' );
-
-			}
-
-
-			//
-
-			function render() {
-
-				if ( effectController.newTess !== tess ||
-					effectController.bottom !== bBottom ||
-					effectController.lid !== bLid ||
-					effectController.body !== bBody ||
-					effectController.fitLid !== bFitLid ||
-					effectController.nonblinn !== bNonBlinn ||
-					effectController.newShading !== shading ||
-					effectController.vertexColors !== vertexColors ) {
-
-					tess = effectController.newTess;
-					bBottom = effectController.bottom;
-					bLid = effectController.lid;
-					bBody = effectController.body;
-					bFitLid = effectController.fitLid;
-					bNonBlinn = effectController.nonblinn;
-					shading = effectController.newShading;
-					vertexColors = effectController.vertexColors;
-
-					createNewTeapot();
-
-				}
-
-				// We're a bit lazy here. We could check to see if any material attributes changed and update
-				// only if they have. But, these calls are cheap enough and this is just a demo.
-				phongMaterial.shininess = effectController.shininess;
-				texturedMaterial.shininess = effectController.shininess;
-				normalMaterial.shininess = effectController.shininess;
-
-				diffuseColor.setHSL( effectController.hue, effectController.saturation, effectController.lightness );
-				if ( effectController.metallic ) {
-
-					// make colors match to give a more metallic look
-					specularColor.copy( diffuseColor );
-
-				} else {
-
-					// more of a plastic look
-					specularColor.setRGB( 1, 1, 1 );
-
-				}
-
-				diffuseColor.multiplyScalar( effectController.kd );
-				flatMaterial.color.copy( diffuseColor );
-				gouraudMaterial.color.copy( diffuseColor );
-				phongMaterial.color.copy( diffuseColor );
-				texturedMaterial.color.copy( diffuseColor );
-				normalMaterial.color.copy( diffuseColor );
-
-				specularColor.multiplyScalar( effectController.ks );
-				phongMaterial.specular.copy( specularColor );
-				texturedMaterial.specular.copy( specularColor );
-				normalMaterial.specular.copy( specularColor );
-
-				// Ambient's actually controlled by the light for this demo
-				ambientLight.color.setHSL( effectController.hue, effectController.saturation, effectController.lightness * effectController.ka );
-
-				light.position.set( effectController.lx, effectController.ly, effectController.lz );
-				light.color.setHSL( effectController.lhue, effectController.lsaturation, effectController.llightness );
-
-				// skybox is rendered separately, so that it is always behind the teapot.
-				if ( shading === 'reflective' ) {
-
-					scene.background = textureCube;
-
-				} else {
-
-					scene.background = null;
-
-				}
-
-				renderer.render( scene, camera );
-
-			}
-
-			// Whenever the teapot changes, the scene is rebuilt from scratch (not much to it).
-			function createNewTeapot() {
-
-				if ( teapot !== undefined ) {
-
-					teapot.geometry.dispose();
-					scene.remove( teapot );
-
-				}
-
-				const teapotGeometry = new TeapotGeometry( teapotSize,
-					tess,
-					effectController.bottom,
-					effectController.lid,
-					effectController.body,
-					effectController.fitLid,
-					! effectController.nonblinn );
-
-				teapot = new THREE.Mesh(
-					teapotGeometry,
-					shading === 'wireframe' ? wireMaterial : (
-						shading === 'flat' ? flatMaterial : (
-							shading === 'smooth' ? gouraudMaterial : (
-								shading === 'glossy' ? phongMaterial : (
-									shading === 'textured' ? texturedMaterial : (
-										shading === 'normal' ? normalMaterial : reflectiveMaterial ) ) ) ) ) );	// if no match, pick Phong
-
-
-				if ( effectController.vertexColors ) {
-
-					teapot.geometry.computeBoundingBox();
-					const minY = teapot.geometry.boundingBox.min.y;
-					const maxY = teapot.geometry.boundingBox.max.y;
-					const sizeY = maxY - minY;
-
-					const colors = [];
-					const position = teapot.geometry.getAttribute( 'position' );
-					for ( let i = 0, l = position.count; i < l; i ++ ) {
-
-						const y = position.getY( i );
-						const r = ( y - minY ) / sizeY;
-						const b = 1.0 - r;
-
-						colors.push( r * 128, 0, b * 128 );
-
-					}
-
-					teapot.geometry.setAttribute( 'color', new THREE.Uint8BufferAttribute( colors, 3, true ) );
-					teapot.material.vertexColors = true;
-					teapot.material.needsUpdate = true;
-
-				} else {
-
-					teapot.geometry.deleteAttribute( 'color' );
-					teapot.material.vertexColors = false;
-					teapot.material.needsUpdate = true;
-
-				}
-
-				scene.add( teapot );
-
-			}
-
-			const exporter = new ColladaExporter();
-
-			function exportCollada() {
-
-				const result = exporter.parse( teapot, undefined, { upAxis: 'Y_UP', unitName: 'millimeter', unitMeter: 0.001 } );
-				let materialType = 'Phong';
-
-				if ( shading === 'wireframe' ) {
-
-					materialType = 'Constant';
-
-				}
-
-				if ( shading === 'smooth' ) {
-
-					materialType = 'Lambert';
-
-				}
-
-				saveString( result.data, 'teapot_' + shading + '_' + materialType + '.dae' );
-
-				result.textures.forEach( tex => {
-
-					saveArrayBuffer( tex.data, `${ tex.name }.${ tex.ext }` );
-
-				} );
-
-			}
-
-			function save( blob, filename ) {
-
-				link.href = URL.createObjectURL( blob );
-				link.download = filename;
-				link.click();
-
-			}
-
-			function saveString( text, filename ) {
-
-				save( new Blob( [ text ], { type: 'text/plain' } ), filename );
-
-			}
-
-			function saveArrayBuffer( buffer, filename ) {
-
-				save( new Blob( [ buffer ], { type: 'application/octet-stream' } ), filename );
-
-			}
-
-			const link = document.createElement( 'a' );
-			link.style.display = 'none';
-			document.body.appendChild( link );
-
-		</script>
-
-	</body>
-</html>

BIN
examples/screenshots/misc_exporter_collada.jpg