Geometry.js 14.6 KB
Newer Older
M
Mr.doob 已提交
1
/**
M
Mr.doob 已提交
2
 * @author mrdoob / http://mrdoob.com/
M
Mr.doob 已提交
3
 * @author kile / http://kile.stravaganza.org/
M
Mr.doob 已提交
4
 * @author alteredq / http://alteredqualia.com/
5
 * @author mikael emtinger / http://gomo.se/
6
 * @author zz85 / http://www.lab4games.net/zz85/blog
M
Mr.doob 已提交
7 8
 */

M
Mr.doob 已提交
9
THREE.Geometry = function () {
10

M
Mr.doob 已提交
11
	THREE.GeometryLibrary.push( this );
M
Mr.doob 已提交
12

M
Mr.doob 已提交
13 14
	this.id = THREE.GeometryIdCount ++;

M
Mr.doob 已提交
15 16
	this.name = '';

M
Mr.doob 已提交
17
	this.vertices = [];
18 19
	this.colors = [];  // one-to-one vertex colors, used in ParticleSystem, Line and Ribbon
	this.normals = []; // one-to-one vertex normals, used in Ribbon
20

21 22
	this.materials = [];

M
Mr.doob 已提交
23
	this.faces = [];
24

25 26
	this.faceUvs = [[]];
	this.faceVertexUvs = [[]];
27

28
	this.morphTargets = [];
M
Mr.doob 已提交
29
	this.morphColors = [];
A
alteredq 已提交
30
	this.morphNormals = [];
M
Mr.doob 已提交
31

32 33
	this.skinWeights = [];
	this.skinIndices = [];
M
Mr.doob 已提交
34

35 36
	this.lineDistances = [];

37 38 39
	this.boundingBox = null;
	this.boundingSphere = null;

40
	this.hasTangents = false;
41

A
alteredq 已提交
42
	this.dynamic = true; // the intermediate typed arrays will be deleted when set to false
43

44 45 46 47 48 49 50 51
	// update flags

	this.verticesNeedUpdate = false;
	this.elementsNeedUpdate = false;
	this.uvsNeedUpdate = false;
	this.normalsNeedUpdate = false;
	this.tangentsNeedUpdate = false;
	this.colorsNeedUpdate = false;
52
	this.lineDistancesNeedUpdate = false;
53

A
alteredq 已提交
54 55
	this.buffersNeedUpdate = false;

M
Mr.doob 已提交
56 57 58 59
};

THREE.Geometry.prototype = {

60 61
	constructor : THREE.Geometry,

62 63 64
	applyMatrix: function ( matrix ) {

		var matrixRotation = new THREE.Matrix4();
A
alteredq 已提交
65
		matrixRotation.extractRotation( matrix );
66 67 68 69 70

		for ( var i = 0, il = this.vertices.length; i < il; i ++ ) {

			var vertex = this.vertices[ i ];

71
			matrix.multiplyVector3( vertex );
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92

		}

		for ( var i = 0, il = this.faces.length; i < il; i ++ ) {

			var face = this.faces[ i ];

			matrixRotation.multiplyVector3( face.normal );

			for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) {

				matrixRotation.multiplyVector3( face.vertexNormals[ j ] );

			}

			matrix.multiplyVector3( face.centroid );

		}

	},

M
Mr.doob 已提交
93 94 95 96
	computeCentroids: function () {

		var f, fl, face;

M
Mr.doob 已提交
97
		for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
M
Mr.doob 已提交
98 99 100 101 102 103

			face = this.faces[ f ];
			face.centroid.set( 0, 0, 0 );

			if ( face instanceof THREE.Face3 ) {

104 105 106
				face.centroid.addSelf( this.vertices[ face.a ] );
				face.centroid.addSelf( this.vertices[ face.b ] );
				face.centroid.addSelf( this.vertices[ face.c ] );
M
Mr.doob 已提交
107 108 109 110
				face.centroid.divideScalar( 3 );

			} else if ( face instanceof THREE.Face4 ) {

111 112 113 114
				face.centroid.addSelf( this.vertices[ face.a ] );
				face.centroid.addSelf( this.vertices[ face.b ] );
				face.centroid.addSelf( this.vertices[ face.c ] );
				face.centroid.addSelf( this.vertices[ face.d ] );
M
Mr.doob 已提交
115 116 117 118 119 120 121 122
				face.centroid.divideScalar( 4 );

			}

		}

	},

123
	computeFaceNormals: function () {
124

125 126
		var n, nl, v, vl, vertex, f, fl, face, vA, vB, vC,
		cb = new THREE.Vector3(), ab = new THREE.Vector3();
127

M
Mr.doob 已提交
128
		for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
129

M
Mr.doob 已提交
130
			face = this.faces[ f ];
131

132 133 134
			vA = this.vertices[ face.a ];
			vB = this.vertices[ face.b ];
			vC = this.vertices[ face.c ];
U
unknown 已提交
135

136 137
			cb.sub( vC, vB );
			ab.sub( vA, vB );
138
			cb.crossSelf( ab );
U
unknown 已提交
139

140
			if ( !cb.isZero() ) {
U
unknown 已提交
141

142
				cb.normalize();
143 144 145

			}

146 147
			face.normal.copy( cb );

148 149 150 151
		}

	},

152 153
	computeVertexNormals: function () {

154
		var v, vl, f, fl, face, vertices;
155

156 157
		// create internal buffers for reuse when calling this method repeatedly
		// (otherwise memory allocation / deallocation every frame is big resource hog)
M
Mr.doob 已提交
158

159
		if ( this.__tmpVertices === undefined ) {
M
Mr.doob 已提交
160

161 162
			this.__tmpVertices = new Array( this.vertices.length );
			vertices = this.__tmpVertices;
M
Mr.doob 已提交
163

164 165 166 167 168
			for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {

				vertices[ v ] = new THREE.Vector3();

			}
M
Mr.doob 已提交
169

170 171 172 173 174 175 176
			for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {

				face = this.faces[ f ];

				if ( face instanceof THREE.Face3 ) {

					face.vertexNormals = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ];
M
Mr.doob 已提交
177

178
				} else if ( face instanceof THREE.Face4 ) {
M
Mr.doob 已提交
179

180 181 182 183 184
					face.vertexNormals = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ];

				}

			}
M
Mr.doob 已提交
185

186
		} else {
M
Mr.doob 已提交
187

188
			vertices = this.__tmpVertices;
M
Mr.doob 已提交
189

190 191 192 193 194
			for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {

				vertices[ v ].set( 0, 0, 0 );

			}
M
Mr.doob 已提交
195

M
Mr.doob 已提交
196 197 198 199 200 201 202
		}

		for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {

			face = this.faces[ f ];

			if ( face instanceof THREE.Face3 ) {
203

M
Mr.doob 已提交
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
				vertices[ face.a ].addSelf( face.normal );
				vertices[ face.b ].addSelf( face.normal );
				vertices[ face.c ].addSelf( face.normal );

			} else if ( face instanceof THREE.Face4 ) {

				vertices[ face.a ].addSelf( face.normal );
				vertices[ face.b ].addSelf( face.normal );
				vertices[ face.c ].addSelf( face.normal );
				vertices[ face.d ].addSelf( face.normal );

			}

		}

		for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {

			vertices[ v ].normalize();

		}

		for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {

			face = this.faces[ f ];

			if ( face instanceof THREE.Face3 ) {

231 232 233
				face.vertexNormals[ 0 ].copy( vertices[ face.a ] );
				face.vertexNormals[ 1 ].copy( vertices[ face.b ] );
				face.vertexNormals[ 2 ].copy( vertices[ face.c ] );
M
Mr.doob 已提交
234 235 236

			} else if ( face instanceof THREE.Face4 ) {

237 238 239 240
				face.vertexNormals[ 0 ].copy( vertices[ face.a ] );
				face.vertexNormals[ 1 ].copy( vertices[ face.b ] );
				face.vertexNormals[ 2 ].copy( vertices[ face.c ] );
				face.vertexNormals[ 3 ].copy( vertices[ face.d ] );
M
Mr.doob 已提交
241 242

			}
243 244 245 246 247

		}

	},

248 249 250 251
	computeMorphNormals: function () {

		var i, il, f, fl, face;

252 253 254
		// save original normals
		// - create temp variables on first access
		//   otherwise just copy (for faster repeated calls)
255 256 257 258

		for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {

			face = this.faces[ f ];
259 260 261 262 263 264 265 266 267 268 269 270

			if ( ! face.__originalFaceNormal ) {

				face.__originalFaceNormal = face.normal.clone();

			} else {

				face.__originalFaceNormal.copy( face.normal );

			}

			if ( ! face.__originalVertexNormals ) face.__originalVertexNormals = [];
271 272 273

			for ( i = 0, il = face.vertexNormals.length; i < il; i ++ ) {

274 275 276 277 278 279 280 281 282
				if ( ! face.__originalVertexNormals[ i ] ) {

					face.__originalVertexNormals[ i ] = face.vertexNormals[ i ].clone();

				} else {

					face.__originalVertexNormals[ i ].copy( face.vertexNormals[ i ] );

				}
283 284 285 286 287 288 289 290 291 292 293 294

			}

		}

		// use temp geometry to compute face and vertex normals for each morph

		var tmpGeo = new THREE.Geometry();
		tmpGeo.faces = this.faces;

		for ( i = 0, il = this.morphTargets.length; i < il; i ++ ) {

295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
			// create on first access

			if ( ! this.morphNormals[ i ] ) {

				this.morphNormals[ i ] = {};
				this.morphNormals[ i ].faceNormals = [];
				this.morphNormals[ i ].vertexNormals = [];

				var dstNormalsFace = this.morphNormals[ i ].faceNormals;
				var dstNormalsVertex = this.morphNormals[ i ].vertexNormals;

				var faceNormal, vertexNormals;

				for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {

					face = this.faces[ f ];

					faceNormal = new THREE.Vector3();

					if ( face instanceof THREE.Face3 ) {

						vertexNormals = { a: new THREE.Vector3(), b: new THREE.Vector3(), c: new THREE.Vector3() };

					} else {

						vertexNormals = { a: new THREE.Vector3(), b: new THREE.Vector3(), c: new THREE.Vector3(), d: new THREE.Vector3() };

					}

					dstNormalsFace.push( faceNormal );
					dstNormalsVertex.push( vertexNormals );

				}

			}

331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
			var morphNormals = this.morphNormals[ i ];

			// set vertices to morph target

			tmpGeo.vertices = this.morphTargets[ i ].vertices;

			// compute morph normals

			tmpGeo.computeFaceNormals();
			tmpGeo.computeVertexNormals();

			// store morph normals

			var faceNormal, vertexNormals;

			for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {

				face = this.faces[ f ];

				faceNormal = morphNormals.faceNormals[ f ];
				vertexNormals = morphNormals.vertexNormals[ f ];

				faceNormal.copy( face.normal );

				if ( face instanceof THREE.Face3 ) {

					vertexNormals.a.copy( face.vertexNormals[ 0 ] );
					vertexNormals.b.copy( face.vertexNormals[ 1 ] );
					vertexNormals.c.copy( face.vertexNormals[ 2 ] );

				} else {

					vertexNormals.a.copy( face.vertexNormals[ 0 ] );
					vertexNormals.b.copy( face.vertexNormals[ 1 ] );
					vertexNormals.c.copy( face.vertexNormals[ 2 ] );
					vertexNormals.d.copy( face.vertexNormals[ 3 ] );

				}

			}

		}

374
		// restore original normals
375 376 377 378

		for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {

			face = this.faces[ f ];
379 380

			face.normal = face.__originalFaceNormal;
381 382 383 384 385 386
			face.vertexNormals = face.__originalVertexNormals;

		}

	},

387
	computeTangents: function () {
388

389 390
		// based on http://www.terathon.com/code/tangent.html
		// tangents go to vertices
391

392 393
		var f, fl, v, vl, i, il, vertexIndex,
			face, uv, vA, vB, vC, uvA, uvB, uvC,
394
			x1, x2, y1, y2, z1, z2,
395
			s1, s2, t1, t2, r, t, test,
396 397
			tan1 = [], tan2 = [],
			sdir = new THREE.Vector3(), tdir = new THREE.Vector3(),
398
			tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3(),
399
			n = new THREE.Vector3(), w;
400

401 402 403 404 405 406
		for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {

			tan1[ v ] = new THREE.Vector3();
			tan2[ v ] = new THREE.Vector3();

		}
407

M
Mr.doob 已提交
408
		function handleTriangle( context, a, b, c, ua, ub, uc ) {
409

410 411 412
			vA = context.vertices[ a ];
			vB = context.vertices[ b ];
			vC = context.vertices[ c ];
413

M
Mr.doob 已提交
414 415 416
			uvA = uv[ ua ];
			uvB = uv[ ub ];
			uvC = uv[ uc ];
417

418 419 420 421 422 423 424 425 426 427 428 429 430
			x1 = vB.x - vA.x;
			x2 = vC.x - vA.x;
			y1 = vB.y - vA.y;
			y2 = vC.y - vA.y;
			z1 = vB.z - vA.z;
			z2 = vC.z - vA.z;

			s1 = uvB.u - uvA.u;
			s2 = uvC.u - uvA.u;
			t1 = uvB.v - uvA.v;
			t2 = uvC.v - uvA.v;

			r = 1.0 / ( s1 * t2 - s2 * t1 );
431
			sdir.set( ( t2 * x1 - t1 * x2 ) * r,
432 433
					  ( t2 * y1 - t1 * y2 ) * r,
					  ( t2 * z1 - t1 * z2 ) * r );
434
			tdir.set( ( s1 * x2 - s2 * x1 ) * r,
435 436
					  ( s1 * y2 - s2 * y1 ) * r,
					  ( s1 * z2 - s2 * z1 ) * r );
437

438 439 440
			tan1[ a ].addSelf( sdir );
			tan1[ b ].addSelf( sdir );
			tan1[ c ].addSelf( sdir );
441

442 443 444
			tan2[ a ].addSelf( tdir );
			tan2[ b ].addSelf( tdir );
			tan2[ c ].addSelf( tdir );
445

446
		}
447

448
		for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
449

450
			face = this.faces[ f ];
451
			uv = this.faceVertexUvs[ 0 ][ f ]; // use UV layer 0 for tangents
452

453
			if ( face instanceof THREE.Face3 ) {
454

M
Mr.doob 已提交
455
				handleTriangle( this, face.a, face.b, face.c, 0, 1, 2 );
456

457
			} else if ( face instanceof THREE.Face4 ) {
458

M
Mr.doob 已提交
459
				handleTriangle( this, face.a, face.b, face.d, 0, 1, 3 );
460
				handleTriangle( this, face.b, face.c, face.d, 1, 2, 3 );
461 462

			}
463

464
		}
465

466
		var faceIndex = [ 'a', 'b', 'c', 'd' ];
467

468
		for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
469

470
			face = this.faces[ f ];
471

472
			for ( i = 0; i < face.vertexNormals.length; i++ ) {
473

474
				n.copy( face.vertexNormals[ i ] );
475

476
				vertexIndex = face[ faceIndex[ i ] ];
477

478
				t = tan1[ vertexIndex ];
479

480
				// Gram-Schmidt orthogonalize
481

482 483
				tmp.copy( t );
				tmp.subSelf( n.multiplyScalar( n.dot( t ) ) ).normalize();
484

485
				// Calculate handedness
486

487 488 489
				tmp2.cross( face.vertexNormals[ i ], t );
				test = tmp2.dot( tan2[ vertexIndex ] );
				w = (test < 0.0) ? -1.0 : 1.0;
490

491
				face.vertexTangents[ i ] = new THREE.Vector4( tmp.x, tmp.y, tmp.z, w );
492

493
			}
494

495
		}
496

497
		this.hasTangents = true;
498

499
	},
500

501
	computeBoundingBox: function () {
502

503
		if ( ! this.boundingBox ) {
504

505
			this.boundingBox = { min: new THREE.Vector3(), max: new THREE.Vector3() };
506

507
		}
508

509
		if ( this.vertices.length > 0 ) {
510

511
			var position, firstPosition = this.vertices[ 0 ];
512

513 514
			this.boundingBox.min.copy( firstPosition );
			this.boundingBox.max.copy( firstPosition );
515 516 517

			var min = this.boundingBox.min,
				max = this.boundingBox.max;
518

M
Mr.doob 已提交
519
			for ( var v = 1, vl = this.vertices.length; v < vl; v ++ ) {
520

521
				position = this.vertices[ v ];
522

523
				if ( position.x < min.x ) {
524

525
					min.x = position.x;
526

527
				} else if ( position.x > max.x ) {
528

529
					max.x = position.x;
530 531 532

				}

533
				if ( position.y < min.y ) {
534

535
					min.y = position.y;
536

537
				} else if ( position.y > max.y ) {
538

539
					max.y = position.y;
540 541 542

				}

543
				if ( position.z < min.z ) {
544

545
					min.z = position.z;
546

547
				} else if ( position.z > max.z ) {
548

549
					max.z = position.z;
550 551 552 553

				}

			}
554

555 556 557 558 559
		} else {

			this.boundingBox.min.set( 0, 0, 0 );
			this.boundingBox.max.set( 0, 0, 0 );

560 561
		}

M
Mr.doob 已提交
562 563
	},

564
	computeBoundingSphere: function () {
565

566
		var maxRadiusSq = 0;
567

568 569 570
		if ( this.boundingSphere === null ) this.boundingSphere = { radius: 0 };

		for ( var i = 0, l = this.vertices.length; i < l; i ++ ) {
571 572

			var radiusSq = this.vertices[ i ].lengthSq();
573
			if ( radiusSq > maxRadiusSq ) maxRadiusSq = radiusSq;
574 575 576

		}

577
		this.boundingSphere.radius = Math.sqrt( maxRadiusSq );
578

579
	},
580 581 582

	/*
	 * Checks for duplicate vertices with hashmap.
583
	 * Duplicated vertices are removed
584
	 * and faces' vertices are updated.
585
	 */
586

587
	mergeVertices: function () {
588

589
		var verticesMap = {}; // Hashmap for looking up vertice by position coordinates (and making sure they are unique)
590
		var unique = [], changes = [];
591

592
		var v, key;
593 594
		var precisionPoints = 4; // number of decimal points, eg. 4 for epsilon of 0.0001
		var precision = Math.pow( 10, precisionPoints );
595
		var i,il, face;
Z
zz85 已提交
596
		var abcd = 'abcd', o, k, j, jl, u;
597 598 599

		for ( i = 0, il = this.vertices.length; i < il; i ++ ) {

600
			v = this.vertices[ i ];
601 602 603 604 605 606 607 608
			key = [ Math.round( v.x * precision ), Math.round( v.y * precision ), Math.round( v.z * precision ) ].join( '_' );

			if ( verticesMap[ key ] === undefined ) {

				verticesMap[ key ] = i;
				unique.push( this.vertices[ i ] );
				changes[ i ] = unique.length - 1;

609
			} else {
610

611
				//console.log('Duplicate vertex found. ', i, ' could be using ', verticesMap[key]);
612 613
				changes[ i ] = changes[ verticesMap[ key ] ];

614
			}
615

616
		};
617 618 619 620


		// Start to patch face indices

621 622 623 624 625
		for( i = 0, il = this.faces.length; i < il; i ++ ) {

			face = this.faces[ i ];

			if ( face instanceof THREE.Face3 ) {
626 627 628 629 630 631 632 633 634 635 636 637

				face.a = changes[ face.a ];
				face.b = changes[ face.b ];
				face.c = changes[ face.c ];

			} else if ( face instanceof THREE.Face4 ) {

				face.a = changes[ face.a ];
				face.b = changes[ face.b ];
				face.c = changes[ face.c ];
				face.d = changes[ face.d ];

638
				// check dups in (a, b, c, d) and convert to -> face3
639 640 641 642 643 644 645

				o = [ face.a, face.b, face.c, face.d ];

				for ( k = 3; k > 0; k -- ) {

					if ( o.indexOf( face[ abcd[ k ] ] ) !== k ) {

646
						// console.log('faces', face.a, face.b, face.c, face.d, 'dup at', k);
647 648 649 650 651 652 653 654 655 656

						o.splice( k, 1 );

						this.faces[ i ] = new THREE.Face3( o[0], o[1], o[2], face.normal, face.color, face.materialIndex );

						for ( j = 0, jl = this.faceVertexUvs.length; j < jl; j ++ ) {

							u = this.faceVertexUvs[ j ][ i ];
							if ( u ) u.splice( k, 1 );

Z
zz85 已提交
657
						}
658

Z
zz85 已提交
659
						this.faces[ i ].vertexColors = face.vertexColors;
660

Z
zz85 已提交
661
						break;
662 663
					}

664
				}
665

666
			}
667

668
		}
669

670
		// Use unique set of vertices
671

Z
zz85 已提交
672
		var diff = this.vertices.length - unique.length;
673
		this.vertices = unique;
Z
zz85 已提交
674
		return diff;
675

676 677 678 679 680 681
	},

	clone: function () {

		// TODO

682 683 684 685
	},

	deallocate: function () {

M
Mr.doob 已提交
686 687
		var index = THREE.GeometryLibrary.indexOf( this );
		if ( index !== -1 ) THREE.GeometryLibrary.splice( index, 1 );
688

689
	}
690

M
Mr.doob 已提交
691
};
692

M
Mr.doob 已提交
693
THREE.GeometryIdCount = 0;
M
Mr.doob 已提交
694
THREE.GeometryLibrary = [];