VRMLLoader.js 18.9 KB
Newer Older
M
r59  
Mr.doob 已提交
1 2 3 4 5 6 7 8
/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.VRMLLoader = function () {};

THREE.VRMLLoader.prototype = {

M
r62  
Mr.doob 已提交
9
	constructor: THREE.VRMLLoader,
M
r59  
Mr.doob 已提交
10

M
r66  
Mr.doob 已提交
11 12 13 14 15
	// for IndexedFaceSet support
	isRecordingPoints: false,
	isRecordingFaces: false,
	points: [],
	indexes : [],
M
r63  
Mr.doob 已提交
16

M
r66  
Mr.doob 已提交
17 18 19 20 21
	// for Background support
	isRecordingAngles: false,
	isRecordingColors: false,
	angles: [],
	colors: [],
M
r63  
Mr.doob 已提交
22

M
r66  
Mr.doob 已提交
23
	recordingFieldname: null,
M
r63  
Mr.doob 已提交
24

M
r59  
Mr.doob 已提交
25 26 27 28 29 30 31 32 33 34 35
	load: function ( url, callback ) {

		var scope = this;
		var request = new XMLHttpRequest();

		request.addEventListener( 'load', function ( event ) {

			var object = scope.parse( event.target.responseText );

			scope.dispatchEvent( { type: 'load', content: object } );

M
r66  
Mr.doob 已提交
36 37
			if ( callback ) callback( object );

M
r59  
Mr.doob 已提交
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
		}, false );

		request.addEventListener( 'progress', function ( event ) {

			scope.dispatchEvent( { type: 'progress', loaded: event.loaded, total: event.total } );

		}, false );

		request.addEventListener( 'error', function () {

			scope.dispatchEvent( { type: 'error', message: 'Couldn\'t load URL [' + url + ']' } );

		}, false );

		request.open( 'GET', url, true );
		request.send( null );

	},

	parse: function ( data ) {

		var parseV1 = function ( lines, scene ) {

			console.warn( 'VRML V1.0 not supported yet' );

		};

		var parseV2 = function ( lines, scene ) {
M
r69  
Mr.doob 已提交
66

M
r66  
Mr.doob 已提交
67 68
			var defines = {};
			var float_pattern = /(\b|\-|\+)([\d\.e]+)/;
M
r69  
Mr.doob 已提交
69
			var float3_pattern = /([\d\.\+\-e]+)\s+([\d\.\+\-e]+)\s+([\d\.\+\-e]+)/g;
M
r66  
Mr.doob 已提交
70 71 72 73 74 75 76 77 78 79 80

			/**
			* Interpolates colors a and b following their relative distance
			* expressed by t.
			*
			* @param float a
			* @param float b
			* @param float t
			* @returns {Color}
			*/
			var interpolateColors = function(a, b, t) {
M
r69  
Mr.doob 已提交
81 82 83
				var deltaR = a.r - b.r;
				var deltaG = a.g - b.g;
				var deltaB = a.b - b.b;
M
r66  
Mr.doob 已提交
84

M
r69  
Mr.doob 已提交
85
				var c = new THREE.Color();
M
r66  
Mr.doob 已提交
86

M
r69  
Mr.doob 已提交
87 88 89
				c.r = a.r - t * deltaR;
				c.g = a.g - t * deltaG;
				c.b = a.b - t * deltaB;
M
r66  
Mr.doob 已提交
90

M
r69  
Mr.doob 已提交
91
				return c;
M
r66  
Mr.doob 已提交
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
			};

			/**
			 * Vertically paints the faces interpolating between the
			 * specified colors at the specified angels. This is used for the Background
			 * node, but could be applied to other nodes with multiple faces as well.
			 *
			 * When used with the Background node, default is directionIsDown is true if
			 * interpolating the skyColor down from the Zenith. When interpolationg up from
			 * the Nadir i.e. interpolating the groundColor, the directionIsDown is false.
			 *
			 * The first angle is never specified, it is the Zenith (0 rad). Angles are specified
			 * in radians. The geometry is thought a sphere, but could be anything. The color interpolation
			 * is linear along the Y axis in any case.
			 *
			 * You must specify one more color than you have angles at the beginning of the colors array.
			 * This is the color of the Zenith (the top of the shape).
			 *
			 * @param geometry
			 * @param radius
			 * @param angles
			 * @param colors
			 * @param boolean directionIsDown Whether to work bottom up or top down.
			 */
			var paintFaces = function (geometry, radius, angles, colors, directionIsDown) {

				var f, n, p, vertexIndex, color;

				var direction = directionIsDown ? 1 : -1;

				var faceIndices = [ 'a', 'b', 'c', 'd' ];

				var coord = [ ], aColor, bColor, t = 1, A = {}, B = {}, applyColor = false, colorIndex;

				for ( var k = 0; k < angles.length; k++ ) {

					var vec = { };

					// push the vector at which the color changes
					vec.y = direction * ( Math.cos( angles[k] ) * radius);

					vec.x = direction * ( Math.sin( angles[k] ) * radius);

					coord.push( vec );

				}

				// painting the colors on the faces
				for ( var i = 0; i < geometry.faces.length ; i++ ) {

					f  = geometry.faces[ i ];

					n = ( f instanceof THREE.Face3 ) ? 3 : 4;

					for ( var j = 0; j < n; j++ ) {

						vertexIndex = f[ faceIndices[ j ] ];

						p = geometry.vertices[ vertexIndex ];

						for ( var index = 0; index < colors.length; index++ ) {

							// linear interpolation between aColor and bColor, calculate proportion
							// A is previous point (angle)
							if ( index === 0 ) {

								A.x = 0;
								A.y = directionIsDown ? radius : -1 * radius;

							} else {

								A.x = coord[ index-1 ].x;
								A.y = coord[ index-1 ].y;

							}
M
r63  
Mr.doob 已提交
167

M
r66  
Mr.doob 已提交
168 169
							// B is current point (angle)
							B = coord[index];
M
r63  
Mr.doob 已提交
170

M
r66  
Mr.doob 已提交
171 172 173
							if ( undefined !== B ) {
								// p has to be between the points A and B which we interpolate
								applyColor = directionIsDown ? p.y <= A.y && p.y > B.y : p.y >= A.y && p.y < B.y;
M
r63  
Mr.doob 已提交
174

M
r66  
Mr.doob 已提交
175
								if (applyColor) {
M
r63  
Mr.doob 已提交
176

M
r66  
Mr.doob 已提交
177
									bColor = colors[ index + 1 ];
M
r63  
Mr.doob 已提交
178

M
r66  
Mr.doob 已提交
179
									aColor = colors[ index ];
M
r63  
Mr.doob 已提交
180

M
r66  
Mr.doob 已提交
181 182
									// below is simple linear interpolation
									t = Math.abs( p.y - A.y ) / ( A.y - B.y );
M
r63  
Mr.doob 已提交
183

M
r66  
Mr.doob 已提交
184 185
									// to make it faster, you can only calculate this if the y coord changes, the color is the same for points with the same y
									color = interpolateColors( aColor, bColor, t );
M
r63  
Mr.doob 已提交
186

M
r66  
Mr.doob 已提交
187 188
									f.vertexColors[ j ] = color;
								}
M
r63  
Mr.doob 已提交
189

M
r66  
Mr.doob 已提交
190 191 192
							} else if ( undefined === f.vertexColors[ j ] ) {
								colorIndex = directionIsDown ? colors.length -1 : 0;
								f.vertexColors[ j ] = colors[ colorIndex ];
M
r63  
Mr.doob 已提交
193

M
r66  
Mr.doob 已提交
194 195 196 197
							}
						}

					}
M
r63  
Mr.doob 已提交
198

M
r66  
Mr.doob 已提交
199 200 201 202
				}
			};

			var parseProperty = function (node, line) {
M
r63  
Mr.doob 已提交
203

M
r66  
Mr.doob 已提交
204
				var parts = [], part, property = {}, fieldName;
M
r63  
Mr.doob 已提交
205

M
r66  
Mr.doob 已提交
206 207 208 209 210
				/**
				 * Expression for matching relevant information, such as a name or value, but not the separators
				 * @type {RegExp}
				 */
				var regex = /[^\s,\[\]]+/g;
M
r63  
Mr.doob 已提交
211

M
r66  
Mr.doob 已提交
212
				var point, index, angles, colors;
M
r63  
Mr.doob 已提交
213

M
r66  
Mr.doob 已提交
214 215 216
				while (null != ( part = regex.exec(line) ) ) {
					parts.push(part[0]);
				}
M
r63  
Mr.doob 已提交
217

M
r66  
Mr.doob 已提交
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
				fieldName = parts[0];


				// trigger several recorders
				switch (fieldName) {
					case 'skyAngle':
					case 'groundAngle':
						this.recordingFieldname = fieldName;
						this.isRecordingAngles = true;
						this.angles = [];
						break;
					case 'skyColor':
					case 'groundColor':
						this.recordingFieldname = fieldName;
						this.isRecordingColors = true;
						this.colors = [];
						break;
					case 'point':
						this.recordingFieldname = fieldName;
						this.isRecordingPoints = true;
						this.points = [];
						break;
					case 'coordIndex':
						this.recordingFieldname = fieldName;
						this.isRecordingFaces = true;
						this.indexes = [];
						break;
				}
M
r63  
Mr.doob 已提交
246

M
r66  
Mr.doob 已提交
247
				if (this.isRecordingFaces) {
M
r63  
Mr.doob 已提交
248

M
r66  
Mr.doob 已提交
249 250 251
					// the parts hold the indexes as strings
					if (parts.length > 0) {
						index = [];
M
r63  
Mr.doob 已提交
252

M
r66  
Mr.doob 已提交
253
						for (var ind = 0;ind < parts.length; ind++) {
M
r63  
Mr.doob 已提交
254

M
r66  
Mr.doob 已提交
255 256 257 258
							// the part should either be positive integer or -1
							if (!/(-?\d+)/.test( parts[ind]) ) {
								continue;
							}
M
r63  
Mr.doob 已提交
259

M
r66  
Mr.doob 已提交
260 261 262 263 264
							// end of current face
							if (parts[ind] === "-1") {
								if (index.length > 0) {
								   this.indexes.push(index);
								}
M
r63  
Mr.doob 已提交
265

M
r66  
Mr.doob 已提交
266 267 268 269 270 271
								// start new one
								index = [];
							} else {
								index.push(parseInt( parts[ind]) );
							}
						}
M
r63  
Mr.doob 已提交
272

M
r66  
Mr.doob 已提交
273
					}
M
r63  
Mr.doob 已提交
274

M
r66  
Mr.doob 已提交
275 276 277 278 279
					// end
					if (/]/.exec(line)) {
						this.isRecordingFaces = false;
						node.coordIndex = this.indexes;
					}
M
r63  
Mr.doob 已提交
280

M
r66  
Mr.doob 已提交
281
				} else if (this.isRecordingPoints) {
M
r63  
Mr.doob 已提交
282

M
r69  
Mr.doob 已提交
283
					while ( null !== ( parts = float3_pattern.exec(line) ) ) {
M
r66  
Mr.doob 已提交
284 285 286 287 288
						point = {
							x: parseFloat(parts[1]),
							y: parseFloat(parts[2]),
							z: parseFloat(parts[3])
						};
M
r63  
Mr.doob 已提交
289

M
r66  
Mr.doob 已提交
290 291
						this.points.push(point);
					}
M
r63  
Mr.doob 已提交
292

M
r66  
Mr.doob 已提交
293 294 295 296 297
					// end
					if ( /]/.exec(line) ) {
						this.isRecordingPoints = false;
						node.points = this.points;
					}
M
r63  
Mr.doob 已提交
298

M
r66  
Mr.doob 已提交
299
				} else if ( this.isRecordingAngles ) {
M
r63  
Mr.doob 已提交
300

M
r66  
Mr.doob 已提交
301 302
					// the parts hold the angles as strings
					if ( parts.length > 0 ) {
M
r63  
Mr.doob 已提交
303

M
r66  
Mr.doob 已提交
304
						for ( var ind = 0;ind < parts.length; ind++ ) {
M
r63  
Mr.doob 已提交
305

M
r66  
Mr.doob 已提交
306 307 308 309
							// the part should be a float
							if ( ! float_pattern.test( parts[ind] ) ) {
								continue;
							}
M
r63  
Mr.doob 已提交
310

M
r66  
Mr.doob 已提交
311 312
							this.angles.push( parseFloat( parts[ind] ) );
						}
M
r63  
Mr.doob 已提交
313

M
r66  
Mr.doob 已提交
314
					}
M
r63  
Mr.doob 已提交
315

M
r66  
Mr.doob 已提交
316 317 318 319 320
					// end
					if ( /]/.exec(line) ) {
						this.isRecordingAngles = false;
						node[this.recordingFieldname] = this.angles;
					}
M
r63  
Mr.doob 已提交
321

M
r66  
Mr.doob 已提交
322
				} else if (this.isRecordingColors) {
M
r63  
Mr.doob 已提交
323

M
r69  
Mr.doob 已提交
324
					while( null !== ( parts = float3_pattern.exec(line) ) ) {
M
r63  
Mr.doob 已提交
325

M
r66  
Mr.doob 已提交
326 327 328 329 330
						color = {
							r: parseFloat(parts[1]),
							g: parseFloat(parts[2]),
							b: parseFloat(parts[3])
						};
M
r63  
Mr.doob 已提交
331

M
r66  
Mr.doob 已提交
332
						this.colors.push(color);
M
r63  
Mr.doob 已提交
333

M
r66  
Mr.doob 已提交
334
					}
M
r63  
Mr.doob 已提交
335

M
r66  
Mr.doob 已提交
336 337 338 339 340
					// end
					if (/]/.exec(line)) {
						this.isRecordingColors = false;
						node[this.recordingFieldname] = this.colors;
					}
M
r63  
Mr.doob 已提交
341

M
r66  
Mr.doob 已提交
342
				} else if ( parts[parts.length -1] !== 'NULL' && fieldName !== 'children') {
M
r63  
Mr.doob 已提交
343

M
r66  
Mr.doob 已提交
344
					switch (fieldName) {
M
r63  
Mr.doob 已提交
345

M
r66  
Mr.doob 已提交
346 347 348 349
						case 'diffuseColor':
						case 'emissiveColor':
						case 'specularColor':
						case 'color':
M
r63  
Mr.doob 已提交
350

M
r66  
Mr.doob 已提交
351 352 353 354
							if (parts.length != 4) {
								console.warn('Invalid color format detected for ' + fieldName );
								break;
							}
M
r63  
Mr.doob 已提交
355

M
r66  
Mr.doob 已提交
356
							property = {
M
r69  
Mr.doob 已提交
357 358 359
								r: parseFloat(parts[1]),
								g: parseFloat(parts[2]),
								b: parseFloat(parts[3])
M
r66  
Mr.doob 已提交
360
							}
M
r63  
Mr.doob 已提交
361

M
r66  
Mr.doob 已提交
362
							break;
M
r63  
Mr.doob 已提交
363

M
r66  
Mr.doob 已提交
364 365 366 367 368 369 370
						case 'translation':
						case 'scale':
						case 'size':
							if (parts.length != 4) {
								console.warn('Invalid vector format detected for ' + fieldName);
								break;
							}
M
r63  
Mr.doob 已提交
371

M
r66  
Mr.doob 已提交
372
							property = {
M
r69  
Mr.doob 已提交
373 374 375
								x: parseFloat(parts[1]),
								y: parseFloat(parts[2]),
								z: parseFloat(parts[3])
M
r66  
Mr.doob 已提交
376
							}
M
r63  
Mr.doob 已提交
377

M
r66  
Mr.doob 已提交
378 379 380 381 382 383 384 385 386 387 388 389 390
							break;

						case 'radius':
						case 'topRadius':
						case 'bottomRadius':
						case 'height':
						case 'transparency':
						case 'shininess':
						case 'ambientIntensity':
							if (parts.length != 2) {
								console.warn('Invalid single float value specification detected for ' + fieldName);
								break;
							}
M
r63  
Mr.doob 已提交
391

M
r66  
Mr.doob 已提交
392
							property = parseFloat(parts[1]);
M
r63  
Mr.doob 已提交
393

M
r66  
Mr.doob 已提交
394
							break;
M
r63  
Mr.doob 已提交
395

M
r66  
Mr.doob 已提交
396 397 398 399 400
						case 'rotation':
							if (parts.length != 5) {
								console.warn('Invalid quaternion format detected for ' + fieldName);
								break;
							}
M
r63  
Mr.doob 已提交
401

M
r66  
Mr.doob 已提交
402
							property = {
M
r69  
Mr.doob 已提交
403 404 405 406
								x: parseFloat(parts[1]),
								y: parseFloat(parts[2]),
								z: parseFloat(parts[3]),
								w: parseFloat(parts[4])
M
r66  
Mr.doob 已提交
407
							}
M
r63  
Mr.doob 已提交
408

M
r66  
Mr.doob 已提交
409
							break;
M
r63  
Mr.doob 已提交
410

M
r66  
Mr.doob 已提交
411 412 413 414 415 416 417 418
						case 'ccw':
						case 'solid':
						case 'colorPerVertex':
						case 'convex':
							if (parts.length != 2) {
								console.warn('Invalid format detected for ' + fieldName);
								break;
							}
M
r63  
Mr.doob 已提交
419

M
r66  
Mr.doob 已提交
420
							property = parts[1] === 'TRUE' ? true : false;
M
r63  
Mr.doob 已提交
421

M
r66  
Mr.doob 已提交
422 423
							break;
					}
M
r63  
Mr.doob 已提交
424

M
r66  
Mr.doob 已提交
425 426
					node[fieldName] = property;
				}
M
r63  
Mr.doob 已提交
427

M
r66  
Mr.doob 已提交
428 429
				return property;
			};
M
r59  
Mr.doob 已提交
430 431 432 433 434

			var getTree = function ( lines ) {

				var tree = { 'string': 'Scene', children: [] };
				var current = tree;
M
r66  
Mr.doob 已提交
435 436
				var matches;
				var specification;
M
r59  
Mr.doob 已提交
437 438 439

				for ( var i = 0; i < lines.length; i ++ ) {

M
r66  
Mr.doob 已提交
440
					var comment = '';
M
r62  
Mr.doob 已提交
441

M
r59  
Mr.doob 已提交
442 443
					var line = lines[ i ];

M
r66  
Mr.doob 已提交
444 445 446 447
					// omit whitespace only lines
					if ( null !== ( result = /^\s+?$/g.exec( line ) ) ) {
						continue;
					}
M
r62  
Mr.doob 已提交
448

M
r66  
Mr.doob 已提交
449
					line = line.trim();
M
r63  
Mr.doob 已提交
450

M
r66  
Mr.doob 已提交
451 452 453 454
					// skip empty lines
					if (line === '') {
						continue;
					}
M
r63  
Mr.doob 已提交
455

M
r62  
Mr.doob 已提交
456 457
					if ( /#/.exec( line ) ) {

M
r66  
Mr.doob 已提交
458
						var parts = line.split('#');
M
r59  
Mr.doob 已提交
459

M
r66  
Mr.doob 已提交
460 461
						// discard everything after the #, it is a comment
						line = parts[0];
M
r59  
Mr.doob 已提交
462

M
r66  
Mr.doob 已提交
463 464
						// well, let's also keep the comment
						comment = parts[1];
M
r62  
Mr.doob 已提交
465
					}
M
r63  
Mr.doob 已提交
466

M
r66  
Mr.doob 已提交
467
					if ( matches = /([^\s]*){1}\s?{/.exec( line ) ) { // first subpattern should match the Node name
M
r59  
Mr.doob 已提交
468

M
r63  
Mr.doob 已提交
469
						var block = { 'nodeType' : matches[1], 'string': line, 'parent': current, 'children': [],'comment' : comment};
M
r59  
Mr.doob 已提交
470 471 472 473
						current.children.push( block );
						current = block;

						if ( /}/.exec( line ) ) {
M
r66  
Mr.doob 已提交
474 475
							// example: geometry Box { size 1 1 1 } # all on the same line
							specification = /{(.*)}/.exec( line )[ 1 ];
M
r63  
Mr.doob 已提交
476

M
r66  
Mr.doob 已提交
477
							// todo: remove once new parsing is complete?
M
r63  
Mr.doob 已提交
478 479
							block.children.push( specification );

M
r66  
Mr.doob 已提交
480
							parseProperty(current, specification);
M
r59  
Mr.doob 已提交
481 482 483 484 485 486 487 488 489 490 491

							current = current.parent;

						}

					} else if ( /}/.exec( line ) ) {

						current = current.parent;

					} else if ( line !== '' ) {

M
r66  
Mr.doob 已提交
492 493 494
						parseProperty(current, line);
						// todo: remove once new parsing is complete? we still do not parse geometry and appearance the new way
						current.children.push( line );
M
r59  
Mr.doob 已提交
495 496 497 498 499

					}

				}

M
r66  
Mr.doob 已提交
500
				return tree;
M
r59  
Mr.doob 已提交
501 502 503 504 505 506 507 508 509 510
			}

			var parseNode = function ( data, parent ) {

				// console.log( data );

				if ( typeof data === 'string' ) {

					if ( /USE/.exec( data ) ) {

M
r66  
Mr.doob 已提交
511
						var defineKey = /USE\s+?(\w+)/.exec( data )[ 1 ];
M
r59  
Mr.doob 已提交
512

M
r66  
Mr.doob 已提交
513 514 515
						if (undefined == defines[defineKey]) {
							console.warn(defineKey + ' is not defined.');
						} else {
M
r59  
Mr.doob 已提交
516

M
r66  
Mr.doob 已提交
517
							if ( /appearance/.exec( data ) && defineKey ) {
M
r59  
Mr.doob 已提交
518

M
r66  
Mr.doob 已提交
519
								parent.material = defines[ defineKey ].clone();
M
r62  
Mr.doob 已提交
520

M
r66  
Mr.doob 已提交
521
							} else if ( /geometry/.exec( data ) && defineKey ) {
M
r62  
Mr.doob 已提交
522

M
r66  
Mr.doob 已提交
523
								parent.geometry = defines[ defineKey ].clone();
M
r63  
Mr.doob 已提交
524

M
r66  
Mr.doob 已提交
525 526 527 528 529
								// the solid property is not cloned with clone(), is only needed for VRML loading, so we need to transfer it
								if (undefined !== defines[ defineKey ].solid && defines[ defineKey ].solid === false) {
									parent.geometry.solid = false;
									parent.material.side = THREE.DoubleSide;
								}
M
r62  
Mr.doob 已提交
530

M
r66  
Mr.doob 已提交
531
							} else if (defineKey){
M
r63  
Mr.doob 已提交
532

M
r66  
Mr.doob 已提交
533 534
								var object = defines[ defineKey ].clone();
								parent.add( object );
M
r62  
Mr.doob 已提交
535

M
r66  
Mr.doob 已提交
536
							}
M
r62  
Mr.doob 已提交
537

M
r66  
Mr.doob 已提交
538
						}
M
r59  
Mr.doob 已提交
539 540 541 542 543 544 545 546 547

					}

					return;

				}

				var object = parent;

M
r63  
Mr.doob 已提交
548 549
				if ( 'Transform' === data.nodeType || 'Group' === data.nodeType ) {

M
r59  
Mr.doob 已提交
550 551 552
					object = new THREE.Object3D();

					if ( /DEF/.exec( data.string ) ) {
M
r62  
Mr.doob 已提交
553
						object.name = /DEF\s+(\w+)/.exec( data.string )[ 1 ];
M
r59  
Mr.doob 已提交
554 555 556
						defines[ object.name ] = object;
					}

M
r66  
Mr.doob 已提交
557
					if ( undefined !== data['translation'] ) {
M
r59  
Mr.doob 已提交
558

M
r66  
Mr.doob 已提交
559
						var t = data.translation;
M
r59  
Mr.doob 已提交
560

M
r66  
Mr.doob 已提交
561
						object.position.set(t.x, t.y, t.z);
M
r59  
Mr.doob 已提交
562

M
r66  
Mr.doob 已提交
563
					}
M
r59  
Mr.doob 已提交
564

M
r66  
Mr.doob 已提交
565
					if ( undefined !== data.rotation ) {
M
r59  
Mr.doob 已提交
566

M
r66  
Mr.doob 已提交
567
						var r = data.rotation;
M
r59  
Mr.doob 已提交
568

M
r66  
Mr.doob 已提交
569
						object.quaternion.setFromAxisAngle( new THREE.Vector3( r.x, r.y, r.z ), r.w );
M
r62  
Mr.doob 已提交
570

M
r66  
Mr.doob 已提交
571
					}
M
r59  
Mr.doob 已提交
572

M
r66  
Mr.doob 已提交
573
					if ( undefined !== data.scale ) {
M
r59  
Mr.doob 已提交
574

M
r66  
Mr.doob 已提交
575
						var s = data.scale;
M
r59  
Mr.doob 已提交
576

M
r66  
Mr.doob 已提交
577
						object.scale.set( s.x, s.y, s.z );
M
r59  
Mr.doob 已提交
578

M
r66  
Mr.doob 已提交
579
					}
M
r59  
Mr.doob 已提交
580 581 582

					parent.add( object );

M
r63  
Mr.doob 已提交
583
				} else if ( 'Shape' === data.nodeType ) {
M
r59  
Mr.doob 已提交
584 585 586 587

					object = new THREE.Mesh();

					if ( /DEF/.exec( data.string ) ) {
M
r63  
Mr.doob 已提交
588

M
r59  
Mr.doob 已提交
589
						object.name = /DEF (\w+)/.exec( data.string )[ 1 ];
M
r63  
Mr.doob 已提交
590

M
r59  
Mr.doob 已提交
591 592 593 594 595
						defines[ object.name ] = object;
					}

					parent.add( object );

M
r63  
Mr.doob 已提交
596
				} else if ( 'Background' === data.nodeType ) {
M
r59  
Mr.doob 已提交
597

M
r66  
Mr.doob 已提交
598
					var segments = 20;
M
r59  
Mr.doob 已提交
599

M
r66  
Mr.doob 已提交
600
					// sky (full sphere):
M
r69  
Mr.doob 已提交
601

M
r66  
Mr.doob 已提交
602
					var radius = 2e4;
M
r59  
Mr.doob 已提交
603

M
r66  
Mr.doob 已提交
604
					var skyGeometry = new THREE.SphereGeometry( radius, segments, segments );
M
r69  
Mr.doob 已提交
605
					var skyMaterial = new THREE.MeshBasicMaterial( { fog: false, side: THREE.BackSide } );
M
r59  
Mr.doob 已提交
606

M
r69  
Mr.doob 已提交
607
					if ( data.skyColor.length > 1 ) {
M
r59  
Mr.doob 已提交
608

M
r69  
Mr.doob 已提交
609
						paintFaces( skyGeometry, radius, data.skyAngle, data.skyColor, true );
M
r59  
Mr.doob 已提交
610

M
r69  
Mr.doob 已提交
611
						skyMaterial.vertexColors = THREE.VertexColors
M
r59  
Mr.doob 已提交
612

M
r69  
Mr.doob 已提交
613
					} else {
M
r59  
Mr.doob 已提交
614

M
r69  
Mr.doob 已提交
615 616
						var color = data.skyColor[ 0 ];
						skyMaterial.color.setRGB( color.r, color.b, color.g );
M
r59  
Mr.doob 已提交
617

M
r69  
Mr.doob 已提交
618
					}
M
r59  
Mr.doob 已提交
619

M
r69  
Mr.doob 已提交
620
					scene.add( new THREE.Mesh( skyGeometry, skyMaterial ) );
M
r59  
Mr.doob 已提交
621

M
r66  
Mr.doob 已提交
622
					// ground (half sphere):
M
r59  
Mr.doob 已提交
623

M
r69  
Mr.doob 已提交
624
					if ( data.groundColor !== undefined ) {
M
r59  
Mr.doob 已提交
625

M
r69  
Mr.doob 已提交
626
						radius = 1.2e4;
M
r59  
Mr.doob 已提交
627

M
r69  
Mr.doob 已提交
628 629
						var groundGeometry = new THREE.SphereGeometry( radius, segments, segments, 0, 2 * Math.PI, 0.5 * Math.PI, 1.5 * Math.PI );
						var groundMaterial = new THREE.MeshBasicMaterial( { fog: false, side: THREE.BackSide, vertexColors: THREE.VertexColors } );
M
r59  
Mr.doob 已提交
630

M
r69  
Mr.doob 已提交
631
						paintFaces( groundGeometry, radius, data.groundAngle, data.groundColor, false );
M
r59  
Mr.doob 已提交
632

M
r69  
Mr.doob 已提交
633
						scene.add( new THREE.Mesh( groundGeometry, groundMaterial ) );
M
r59  
Mr.doob 已提交
634

M
r69  
Mr.doob 已提交
635
					}
M
r59  
Mr.doob 已提交
636

M
r63  
Mr.doob 已提交
637
				} else if ( /geometry/.exec( data.string ) ) {
M
r59  
Mr.doob 已提交
638

M
r63  
Mr.doob 已提交
639
					if ( 'Box' === data.nodeType ) {
M
r59  
Mr.doob 已提交
640

M
r66  
Mr.doob 已提交
641
						var s = data.size;
M
r59  
Mr.doob 已提交
642

M
r66  
Mr.doob 已提交
643
						parent.geometry = new THREE.BoxGeometry( s.x, s.y, s.z );
M
r59  
Mr.doob 已提交
644

M
r63  
Mr.doob 已提交
645
					} else if ( 'Cylinder' === data.nodeType ) {
M
r59  
Mr.doob 已提交
646

M
r63  
Mr.doob 已提交
647
						parent.geometry = new THREE.CylinderGeometry( data.radius, data.radius, data.height );
M
r59  
Mr.doob 已提交
648

M
r63  
Mr.doob 已提交
649
					} else if ( 'Cone' === data.nodeType ) {
M
r59  
Mr.doob 已提交
650

M
r63  
Mr.doob 已提交
651
						parent.geometry = new THREE.CylinderGeometry( data.topRadius, data.bottomRadius, data.height );
M
r59  
Mr.doob 已提交
652

M
r63  
Mr.doob 已提交
653
					} else if ( 'Sphere' === data.nodeType ) {
M
r59  
Mr.doob 已提交
654

M
r63  
Mr.doob 已提交
655
						parent.geometry = new THREE.SphereGeometry( data.radius );
M
r59  
Mr.doob 已提交
656

M
r63  
Mr.doob 已提交
657
					} else if ( 'IndexedFaceSet' === data.nodeType ) {
M
r62  
Mr.doob 已提交
658

M
r66  
Mr.doob 已提交
659
						var geometry = new THREE.Geometry();
M
r62  
Mr.doob 已提交
660

M
r66  
Mr.doob 已提交
661
						var indexes;
M
r62  
Mr.doob 已提交
662

M
r66  
Mr.doob 已提交
663
						for ( var i = 0, j = data.children.length; i < j; i++ ) {
M
r62  
Mr.doob 已提交
664

M
r66  
Mr.doob 已提交
665
							var child = data.children[ i ];
M
r62  
Mr.doob 已提交
666

M
r66  
Mr.doob 已提交
667
							var vec;
M
r62  
Mr.doob 已提交
668

M
r66  
Mr.doob 已提交
669
							if ( 'Coordinate' === child.nodeType ) {
M
r62  
Mr.doob 已提交
670

M
r66  
Mr.doob 已提交
671
								for ( var k = 0, l = child.points.length; k < l; k++ ) {
M
r62  
Mr.doob 已提交
672

M
r66  
Mr.doob 已提交
673
									var point = child.points[ k ];
M
r62  
Mr.doob 已提交
674

M
r66  
Mr.doob 已提交
675
									vec = new THREE.Vector3( point.x, point.y, point.z );
M
r62  
Mr.doob 已提交
676

M
r66  
Mr.doob 已提交
677 678
									geometry.vertices.push( vec );
								}
M
r62  
Mr.doob 已提交
679

M
r66  
Mr.doob 已提交
680 681 682
								break;
							}
						}
M
r62  
Mr.doob 已提交
683

M
r66  
Mr.doob 已提交
684
						var skip = 0;
M
r63  
Mr.doob 已提交
685

M
r66  
Mr.doob 已提交
686 687
						// read this: http://math.hws.edu/eck/cs424/notes2013/16_Threejs_Advanced.html
						for ( var i = 0, j = data.coordIndex.length; i < j; i++ ) {
M
r62  
Mr.doob 已提交
688

M
r66  
Mr.doob 已提交
689
							indexes = data.coordIndex[i];
M
r62  
Mr.doob 已提交
690

M
r66  
Mr.doob 已提交
691 692
							// vrml support multipoint indexed face sets (more then 3 vertices). You must calculate the composing triangles here
							skip = 0;
M
r62  
Mr.doob 已提交
693

M
r66  
Mr.doob 已提交
694
							// todo: this is the time to check if the faces are ordered ccw or not (cw)
M
r62  
Mr.doob 已提交
695

M
r66  
Mr.doob 已提交
696 697
							// Face3 only works with triangles, but IndexedFaceSet allows shapes with more then three vertices, build them of triangles
							while ( indexes.length >= 3 && skip < ( indexes.length -2 ) ) {
M
r62  
Mr.doob 已提交
698

M
r66  
Mr.doob 已提交
699 700 701 702 703 704 705
								var face = new THREE.Face3(
									indexes[0],
									indexes[skip + 1],
									indexes[skip + 2],
									null // normal, will be added later
									// todo: pass in the color, if a color index is present
								);
M
r63  
Mr.doob 已提交
706

M
r66  
Mr.doob 已提交
707
								skip++;
M
r63  
Mr.doob 已提交
708

M
r66  
Mr.doob 已提交
709
								geometry.faces.push( face );
M
r62  
Mr.doob 已提交
710

M
r66  
Mr.doob 已提交
711
							}
M
r62  
Mr.doob 已提交
712 713


M
r66  
Mr.doob 已提交
714
						}
M
r62  
Mr.doob 已提交
715

M
r66  
Mr.doob 已提交
716 717 718
						if ( false === data.solid ) {
							parent.material.side = THREE.DoubleSide;
						}
M
r63  
Mr.doob 已提交
719

M
r66  
Mr.doob 已提交
720 721
						// we need to store it on the geometry for use with defines
						geometry.solid = data.solid;
M
r63  
Mr.doob 已提交
722

M
r66  
Mr.doob 已提交
723 724 725
						geometry.computeFaceNormals();
						//geometry.computeVertexNormals(); // does not show
						geometry.computeBoundingSphere();
M
r62  
Mr.doob 已提交
726

M
r66  
Mr.doob 已提交
727 728 729 730 731
						// see if it's a define
						if ( /DEF/.exec( data.string ) ) {
							geometry.name = /DEF (\w+)/.exec( data.string )[ 1 ];
							defines[ geometry.name ] = geometry;
						}
M
r62  
Mr.doob 已提交
732

M
r66  
Mr.doob 已提交
733
						parent.geometry = geometry;
M
r59  
Mr.doob 已提交
734 735 736 737 738 739 740 741 742 743
					}

					return;

				} else if ( /appearance/.exec( data.string ) ) {

					for ( var i = 0; i < data.children.length; i ++ ) {

						var child = data.children[ i ];

M
r63  
Mr.doob 已提交
744
						if ( 'Material' === child.nodeType ) {
M
r59  
Mr.doob 已提交
745 746
							var material = new THREE.MeshPhongMaterial();

M
r66  
Mr.doob 已提交
747
							if ( undefined !== child.diffuseColor ) {
M
r59  
Mr.doob 已提交
748

M
r66  
Mr.doob 已提交
749
								var d = child.diffuseColor;
M
r59  
Mr.doob 已提交
750

M
r66  
Mr.doob 已提交
751
								material.color.setRGB( d.r, d.g, d.b );
M
r59  
Mr.doob 已提交
752

M
r66  
Mr.doob 已提交
753
							}
M
r59  
Mr.doob 已提交
754

M
r66  
Mr.doob 已提交
755
							if ( undefined !== child.emissiveColor ) {
M
r59  
Mr.doob 已提交
756

M
r66  
Mr.doob 已提交
757
								var e = child.emissiveColor;
M
r59  
Mr.doob 已提交
758

M
r66  
Mr.doob 已提交
759
								material.emissive.setRGB( e.r, e.g, e.b );
M
r59  
Mr.doob 已提交
760

M
r66  
Mr.doob 已提交
761
							}
M
r59  
Mr.doob 已提交
762

M
r66  
Mr.doob 已提交
763
							if ( undefined !== child.specularColor ) {
M
r59  
Mr.doob 已提交
764

M
r66  
Mr.doob 已提交
765
								var s = child.specularColor;
M
r59  
Mr.doob 已提交
766

M
r66  
Mr.doob 已提交
767
								material.specular.setRGB( s.r, s.g, s.b );
M
r59  
Mr.doob 已提交
768

M
r66  
Mr.doob 已提交
769
							}
M
r59  
Mr.doob 已提交
770

M
r66  
Mr.doob 已提交
771
							if ( undefined !== child.transparency ) {
M
r59  
Mr.doob 已提交
772

M
r66  
Mr.doob 已提交
773
								var t = child.transparency;
M
r59  
Mr.doob 已提交
774

M
r66  
Mr.doob 已提交
775 776
								// transparency is opposite of opacity
								material.opacity = Math.abs( 1 - t );
M
r63  
Mr.doob 已提交
777

M
r66  
Mr.doob 已提交
778
								material.transparent = true;
M
r63  
Mr.doob 已提交
779

M
r66  
Mr.doob 已提交
780
							}
M
r59  
Mr.doob 已提交
781 782 783 784

							if ( /DEF/.exec( data.string ) ) {

								material.name = /DEF (\w+)/.exec( data.string )[ 1 ];
M
r62  
Mr.doob 已提交
785

M
r59  
Mr.doob 已提交
786 787 788 789 790 791
								defines[ material.name ] = material;

							}

							parent.material = material;

M
r66  
Mr.doob 已提交
792 793
							// material found, stop looping
							break;
M
r59  
Mr.doob 已提交
794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818
						}

					}

					return;

				}

				for ( var i = 0, l = data.children.length; i < l; i ++ ) {

					var child = data.children[ i ];

					parseNode( data.children[ i ], object );

				}

			}

			parseNode( getTree( lines ), scene );

		};

		var scene = new THREE.Scene();

		var lines = data.split( '\n' );
M
r63  
Mr.doob 已提交
819

M
r59  
Mr.doob 已提交
820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838
		var header = lines.shift();

		if ( /V1.0/.exec( header ) ) {

			parseV1( lines, scene );

		} else if ( /V2.0/.exec( header ) ) {

			parseV2( lines, scene );

		}

		return scene;

	}

};

THREE.EventDispatcher.prototype.apply( THREE.VRMLLoader.prototype );
M
r63  
Mr.doob 已提交
839