BufferGeometry.js 25.2 KB
Newer Older
1 2
/**
 * @author alteredq / http://alteredqualia.com/
3
 * @author mrdoob / http://mrdoob.com/
4 5 6 7
 */

THREE.BufferGeometry = function () {

M
Mr.doob 已提交
8 9
	Object.defineProperty( this, 'id', { value: THREE.GeometryIdCount ++ } );

10
	this.uuid = THREE.Math.generateUUID();
11

M
Mr.doob 已提交
12
	this.name = '';
13
	this.type = 'BufferGeometry';
M
Mr.doob 已提交
14

15
	this.attributes = {};
16

17 18
	this.morphAttributes = [];

19
	this.drawcalls = [];
20

21 22 23 24 25 26 27
	this.boundingBox = null;
	this.boundingSphere = null;

};

THREE.BufferGeometry.prototype = {

28
	constructor: THREE.BufferGeometry,
29

M
Mr.doob 已提交
30
	addAttribute: function ( name, attribute ) {
31

M
Mr.doob 已提交
32
		if ( attribute instanceof THREE.BufferAttribute === false && attribute instanceof THREE.InterleavedBufferAttribute === false ) {
33

34
			console.warn( 'THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).' );
35 36 37 38 39 40 41

			this.attributes[ name ] = { array: arguments[ 1 ], itemSize: arguments[ 2 ] };

			return;

		}

M
Mr.doob 已提交
42
		this.attributes[ name ] = attribute;
43

M
Mr.doob 已提交
44 45 46 47
	},

	getAttribute: function ( name ) {

48 49
		return this.attributes[ name ];

50 51
	},

52 53 54
	offsets: function () {

		console.warn( 'THREE.BufferGeometry: .offsets has been renamed to .drawcalls.' );
55
		return this.drawcalls;
56 57 58

	},

M
Mr.doob 已提交
59 60
	addDrawCall: function ( start, count, indexOffset ) {

61
		this.drawcalls.push( {
M
Mr.doob 已提交
62 63 64

			start: start,
			count: count,
M
Mr.doob 已提交
65
			index: indexOffset !== undefined ? indexOffset : 0
M
Mr.doob 已提交
66 67 68 69 70

		} );

	},

D
dubejf 已提交
71 72 73 74 75 76
	clearDrawCalls: function () {

		this.drawcalls = [];

	},

77 78
	applyMatrix: function ( matrix ) {

M
Mr.doob 已提交
79
		var position = this.attributes.position;
80

M
Mr.doob 已提交
81
		if ( position !== undefined ) {
82

83
			matrix.applyToVector3Array( position.array );
M
Mr.doob 已提交
84
			position.needsUpdate = true;
85 86 87

		}

M
Mr.doob 已提交
88
		var normal = this.attributes.normal;
89

M
Mr.doob 已提交
90
		if ( normal !== undefined ) {
91

M
Mr.doob 已提交
92
			var normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix );
93

94
			normalMatrix.applyToVector3Array( normal.array );
M
Mr.doob 已提交
95
			normal.needsUpdate = true;
96 97 98

		}

M
Mr.doob 已提交
99
		if ( this.boundingBox !== null ) {
100 101 102 103 104

			this.computeBoundingBox();

		}

M
Mr.doob 已提交
105
		if ( this.boundingSphere !== null ) {
106 107 108 109 110

			this.computeBoundingSphere();

		}

111 112
	},

M
Mr.doob 已提交
113 114
	copy: function ( geometry ) {

D
dubejf 已提交
115 116
		// TODO Clear attributes? Clear drawcalls? Copy morphTargets?

M
Mr.doob 已提交
117
		var attributes = geometry.attributes;
D
dubejf 已提交
118
		var offsets = geometry.drawcalls;
M
Mr.doob 已提交
119 120 121 122 123 124 125 126 127 128 129 130

		for ( var name in attributes ) {

			var attribute = attributes[ name ];

			this.addAttribute( name, attribute.clone() );

		}

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

			var offset = offsets[ i ];
D
dubejf 已提交
131
			this.addDrawCall( offset.start, offset.count, offset.index );
M
Mr.doob 已提交
132 133 134 135 136 137 138

		}

		return this;

	},

139 140
	center: function () {

M
Mr.doob 已提交
141 142 143 144 145 146 147
		this.computeBoundingBox();

		var offset = this.boundingBox.center().negate();

		this.applyMatrix( new THREE.Matrix4().setPosition( offset ) );

		return offset;
148 149 150

	},

151
	setFromObject: function ( object ) {
152

153
		console.log( 'THREE.BufferGeometry.setFromObject(). Converting', object, this );
154

155 156 157 158 159
		var geometry = object.geometry;
		var material = object.material;

		if ( object instanceof THREE.PointCloud || object instanceof THREE.Line ) {

160 161
			var positions = new THREE.Float32Attribute( geometry.vertices.length * 3, 3 );
			var colors = new THREE.Float32Attribute( geometry.colors.length * 3, 3 );
162

163 164
			this.addAttribute( 'position', positions.copyVector3sArray( geometry.vertices ) );
			this.addAttribute( 'color', colors.copyColorsArray( geometry.colors ) );
165

C
Chen Pang 已提交
166 167 168 169 170 171 172 173
			if ( geometry.lineDistances && geometry.lineDistances.length === geometry.vertices.length ) {

				var lineDistances = new THREE.Float32Attribute( geometry.lineDistances.length, 1 );

				this.addAttribute( 'lineDistance',  lineDistances.copyArray( geometry.lineDistances ) );

			}

174 175 176 177 178 179 180 181 182 183 184
			if ( geometry.boundingSphere !== null ) {

				this.boundingSphere = geometry.boundingSphere.clone();

			}

			if ( geometry.boundingBox !== null ) {

				this.boundingBox = geometry.boundingBox.clone();

			}
185 186 187

		} else if ( object instanceof THREE.Mesh ) {

M
Mr.doob 已提交
188
			if ( geometry instanceof THREE.Geometry ) {
189 190

				this.fromGeometry( geometry );
191

M
Mr.doob 已提交
192
			}
193 194 195 196 197 198 199

		}

		return this;

	},

200 201
	updateFromObject: function ( object ) {

M
Mr.doob 已提交
202
		var geometry = object.geometry;
203

M
Mr.doob 已提交
204
		if ( object instanceof THREE.Mesh ) {
205

M
Mr.doob 已提交
206
			var direct = geometry.__directGeometry;
207

M
Mr.doob 已提交
208 209 210 211
			direct.verticesNeedUpdate = geometry.verticesNeedUpdate;
			direct.normalsNeedUpdate = geometry.normalsNeedUpdate;
			direct.colorsNeedUpdate = geometry.colorsNeedUpdate;
			direct.uvsNeedUpdate = geometry.uvsNeedUpdate;
212
			direct.tangentsNeedUpdate = geometry.tangentsNeedUpdate;
M
Mr.doob 已提交
213 214 215 216 217

			geometry.verticesNeedUpdate = false;
			geometry.normalsNeedUpdate = false;
			geometry.colorsNeedUpdate = false;
			geometry.uvsNeedUpdate = false;
218
			geometry.tangentsNeedUpdate = false;
219

M
Mr.doob 已提交
220
			geometry = direct;
221 222

		}
223

M
Mr.doob 已提交
224
		if ( geometry.verticesNeedUpdate === true ) {
225

M
Mr.doob 已提交
226
			var attribute = this.attributes.position;
227

M
Mr.doob 已提交
228
			if ( attribute !== undefined ) {
229

M
Mr.doob 已提交
230 231
				attribute.copyVector3sArray( geometry.vertices );
				attribute.needsUpdate = true;
232 233 234

			}

M
Mr.doob 已提交
235
			geometry.verticesNeedUpdate = false;
236

M
Mr.doob 已提交
237
		}
238

239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
		if ( geometry.normalsNeedUpdate === true ) {

			var attribute = this.attributes.normal;

			if ( attribute !== undefined ) {

				attribute.copyVector3sArray( geometry.normals );
				attribute.needsUpdate = true;

			}

			geometry.normalsNeedUpdate = false;

		}

M
Mr.doob 已提交
254
		if ( geometry.colorsNeedUpdate === true ) {
255

M
Mr.doob 已提交
256
			var attribute = this.attributes.color;
257

M
Mr.doob 已提交
258
			if ( attribute !== undefined ) {
259

M
Mr.doob 已提交
260 261
				attribute.copyColorsArray( geometry.colors );
				attribute.needsUpdate = true;
262 263 264

			}

M
Mr.doob 已提交
265 266
			geometry.colorsNeedUpdate = false;

267
		}
268

269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
		if ( geometry.tangentsNeedUpdate === true ) {

			var attribute = this.attributes.tangent;

			if ( attribute !== undefined ) {

				attribute.copyVector4sArray( geometry.tangents );
				attribute.needsUpdate = true;

			}

			geometry.tangentsNeedUpdate = false;

		}

C
Chen Pang 已提交
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
		if ( geometry.lineDistancesNeedUpdate ) {

			var attribute = this.attributes.lineDistance;

			if ( attribute !== undefined ) {

				attribute.copyArray( geometry.lineDistances );
				attribute.needsUpdate = true;

			}

			geometry.lineDistancesNeedUpdate = false;

		}

299
		return this;
300 301 302

	},

303
	fromGeometry: function ( geometry ) {
304

305
		geometry.__directGeometry = new THREE.DirectGeometry().fromGeometry( geometry );
306 307

		return this.fromDirectGeometry( geometry.__directGeometry );
308

309
	},
310

311
	fromDirectGeometry: function ( geometry ) {
312

313 314
		var positions = new Float32Array( geometry.vertices.length * 3 );
		this.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ).copyVector3sArray( geometry.vertices ) );
315

316 317 318 319 320 321 322 323
		if ( geometry.normals.length > 0 ) {

			var normals = new Float32Array( geometry.normals.length * 3 );
			this.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ).copyVector3sArray( geometry.normals ) );

		}

		if ( geometry.colors.length > 0 ) {
M
Mr.doob 已提交
324

325
			var colors = new Float32Array( geometry.colors.length * 3 );
326
			this.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ).copyColorsArray( geometry.colors ) );
M
Mr.doob 已提交
327

328 329 330 331 332 333 334 335
		}

		if ( geometry.uvs.length > 0 ) {

			var uvs = new Float32Array( geometry.uvs.length * 2 );
			this.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ).copyVector2sArray( geometry.uvs ) );

		}
M
Mr.doob 已提交
336

337 338 339 340 341 342 343 344 345 346 347 348 349 350
		if ( geometry.uvs2.length > 0 ) {

			var uvs2 = new Float32Array( geometry.uvs2.length * 2 );
			this.addAttribute( 'uv2', new THREE.BufferAttribute( uvs2, 2 ).copyVector2sArray( geometry.uvs2 ) );

		}

		if ( geometry.tangents.length > 0 ) {

			var tangents = new Float32Array( geometry.tangents.length * 4 );
			this.addAttribute( 'tangent', new THREE.BufferAttribute( tangents, 4 ).copyVector4sArray( geometry.tangents ) );

		}

351 352 353 354 355 356 357
		if ( geometry.indices.length > 0 ) {

			var indices = new Uint16Array( geometry.indices.length * 3 );
			this.addAttribute( 'index', new THREE.BufferAttribute( indices, 1 ).copyIndicesArray( geometry.indices ) );

		}

358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395
		// morphs

		if ( geometry.morphTargets.length > 0 ) {

			var morphTargets = geometry.morphTargets;

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

				var morphTarget = morphTargets[ i ];

				var attribute = new THREE.Float32Attribute( morphTarget.length * 3, 3 );

				this.morphAttributes.push( attribute.copyVector3sArray( morphTarget ) );

			}

			// TODO normals, colors

		}

		// skinning

		if ( geometry.skinIndices.length > 0 ) {

			var skinIndices = new THREE.Float32Attribute( geometry.skinIndices.length * 4, 4 );
			this.addAttribute( 'skinIndex', skinIndices.copyVector4sArray( geometry.skinIndices ) );

		}

		if ( geometry.skinWeights.length > 0 ) {

			var skinWeights = new THREE.Float32Attribute( geometry.skinWeights.length * 4, 4 );
			this.addAttribute( 'skinWeight', skinWeights.copyVector4sArray( geometry.skinWeights ) );

		}

		//

396 397 398 399 400 401 402 403 404 405 406
		if ( geometry.boundingSphere !== null ) {

			this.boundingSphere = geometry.boundingSphere.clone();

		}

		if ( geometry.boundingBox !== null ) {

			this.boundingBox = geometry.boundingBox.clone();

		}
M
Mr.doob 已提交
407 408 409 410 411

		return this;

	},

412 413
	computeBoundingBox: function () {

414
		var vector = new THREE.Vector3();
415

416
		return function () {
417

418
			if ( this.boundingBox === null ) {
419

420
				this.boundingBox = new THREE.Box3();
421

422 423
			}

424
			var positions = this.attributes.position.array;
425

426
			if ( positions ) {
427

428 429
				var bb = this.boundingBox;
				bb.makeEmpty();
430

431
				for ( var i = 0, il = positions.length; i < il; i += 3 ) {
432

433
					vector.fromArray( positions, i );
434
					bb.expandByPoint( vector );
435 436 437 438 439

				}

			}

440
			if ( positions === undefined || positions.length === 0 ) {
441

442 443
				this.boundingBox.min.set( 0, 0, 0 );
				this.boundingBox.max.set( 0, 0, 0 );
444

445
			}
446

447
			if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) {
448

449
				console.error( 'THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this );
450

451
			}
452

G
Greg French 已提交
453
		};
454

455
	}(),
456 457 458

	computeBoundingSphere: function () {

459 460
		var box = new THREE.Box3();
		var vector = new THREE.Vector3();
461

462
		return function () {
463

464
			if ( this.boundingSphere === null ) {
465

466
				this.boundingSphere = new THREE.Sphere();
467

468
			}
469

470
			var positions = this.attributes.position.array;
471

472
			if ( positions ) {
473

474 475
				box.makeEmpty();

476
				var center = this.boundingSphere.center;
477

478
				for ( var i = 0, il = positions.length; i < il; i += 3 ) {
479

480
					vector.fromArray( positions, i );
J
Jan Wrobel 已提交
481
					box.expandByPoint( vector );
482 483 484 485 486

				}

				box.center( center );

487
				// hoping to find a boundingSphere with a radius smaller than the
M
Mr.doob 已提交
488
				// boundingSphere of the boundingBox: sqrt(3) smaller in the best case
489

490 491
				var maxRadiusSq = 0;

492
				for ( var i = 0, il = positions.length; i < il; i += 3 ) {
493

494
					vector.fromArray( positions, i );
495
					maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) );
496

497 498 499 500
				}

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

501 502
				if ( isNaN( this.boundingSphere.radius ) ) {

503
					console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this );
504 505 506

				}

507
			}
508

G
Greg French 已提交
509
		};
510

511
	}(),
512

513 514 515 516 517 518
	computeFaceNormals: function () {

		// backwards compatibility

	},

519 520
	computeVertexNormals: function () {

521
		var attributes = this.attributes;
522

523
		if ( attributes.position ) {
524

525
			var positions = attributes.position.array;
526

527
			if ( attributes.normal === undefined ) {
528

529
				this.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( positions.length ), 3 ) );
530 531 532 533 534

			} else {

				// reset existing normals to zero

535 536 537
				var normals = attributes.normal.array;

				for ( var i = 0, il = normals.length; i < il; i ++ ) {
538

539
					normals[ i ] = 0;
540 541 542 543 544

				}

			}

545
			var normals = attributes.normal.array;
546

M
Mr.doob 已提交
547
			var vA, vB, vC,
548 549 550 551 552 553 554 555

			pA = new THREE.Vector3(),
			pB = new THREE.Vector3(),
			pC = new THREE.Vector3(),

			cb = new THREE.Vector3(),
			ab = new THREE.Vector3();

556 557
			// indexed elements

558
			if ( attributes.index ) {
559

560
				var indices = attributes.index.array;
561

D
dubejf 已提交
562 563 564
				if ( this.drawcalls.length === 0 ) {

					this.addDrawCall( 0, indices.length, 0 );
565

D
dubejf 已提交
566 567 568
				}

				for ( var j = 0, jl = this.drawcalls.length; j < jl; ++ j ) {
569

D
dubejf 已提交
570 571 572
					var start = this.drawcalls[ j ].start;
					var count = this.drawcalls[ j ].count;
					var index = this.drawcalls[ j ].index;
573

574
					for ( var i = start, il = start + count; i < il; i += 3 ) {
575

M
Mr.doob 已提交
576 577 578
						vA = ( index + indices[ i     ] ) * 3;
						vB = ( index + indices[ i + 1 ] ) * 3;
						vC = ( index + indices[ i + 2 ] ) * 3;
579

M
Mr.doob 已提交
580 581 582
						pA.fromArray( positions, vA );
						pB.fromArray( positions, vB );
						pC.fromArray( positions, vC );
583

584 585 586
						cb.subVectors( pC, pB );
						ab.subVectors( pA, pB );
						cb.cross( ab );
587

M
Mr.doob 已提交
588 589 590
						normals[ vA     ] += cb.x;
						normals[ vA + 1 ] += cb.y;
						normals[ vA + 2 ] += cb.z;
591

M
Mr.doob 已提交
592 593 594
						normals[ vB     ] += cb.x;
						normals[ vB + 1 ] += cb.y;
						normals[ vB + 2 ] += cb.z;
595

M
Mr.doob 已提交
596 597 598
						normals[ vC     ] += cb.x;
						normals[ vC + 1 ] += cb.y;
						normals[ vC + 2 ] += cb.z;
599 600 601 602 603 604

					}

				}

			} else {
605

606 607 608
				// non-indexed elements (unconnected triangle soup)

				for ( var i = 0, il = positions.length; i < il; i += 9 ) {
609

M
Mr.doob 已提交
610 611 612
					pA.fromArray( positions, i );
					pB.fromArray( positions, i + 3 );
					pC.fromArray( positions, i + 6 );
613

614 615 616
					cb.subVectors( pC, pB );
					ab.subVectors( pA, pB );
					cb.cross( ab );
617

M
Mr.doob 已提交
618
					normals[ i     ] = cb.x;
619 620
					normals[ i + 1 ] = cb.y;
					normals[ i + 2 ] = cb.z;
621

622 623 624
					normals[ i + 3 ] = cb.x;
					normals[ i + 4 ] = cb.y;
					normals[ i + 5 ] = cb.z;
625

626 627 628
					normals[ i + 6 ] = cb.x;
					normals[ i + 7 ] = cb.y;
					normals[ i + 8 ] = cb.z;
629 630 631 632 633

				}

			}

634
			this.normalizeNormals();
635

636
			attributes.normal.needsUpdate = true;
637

638
		}
639

640
	},
641

642 643 644 645 646
	computeTangents: function () {

		// based on http://www.terathon.com/code/tangent.html
		// (per vertex tangents)

647 648 649 650
		if ( this.attributes.index === undefined ||
			 this.attributes.position === undefined ||
			 this.attributes.normal === undefined ||
			 this.attributes.uv === undefined ) {
651

652
			console.warn( 'THREE.BufferGeometry: Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()' );
653 654 655 656
			return;

		}

657 658 659 660
		var indices = this.attributes.index.array;
		var positions = this.attributes.position.array;
		var normals = this.attributes.normal.array;
		var uvs = this.attributes.uv.array;
661 662 663

		var nVertices = positions.length / 3;

664
		if ( this.attributes.tangent === undefined ) {
665

666
			this.addAttribute( 'tangent', new THREE.BufferAttribute( new Float32Array( 4 * nVertices ), 4 ) );
667 668 669

		}

670
		var tangents = this.attributes.tangent.array;
671 672 673 674 675 676 677 678 679 680

		var tan1 = [], tan2 = [];

		for ( var k = 0; k < nVertices; k ++ ) {

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

		}

M
Mr.doob 已提交
681 682 683
		var vA = new THREE.Vector3(),
			vB = new THREE.Vector3(),
			vC = new THREE.Vector3(),
684

M
Mr.doob 已提交
685 686 687
			uvA = new THREE.Vector2(),
			uvB = new THREE.Vector2(),
			uvC = new THREE.Vector2(),
688 689 690 691 692 693 694 695

			x1, x2, y1, y2, z1, z2,
			s1, s2, t1, t2, r;

		var sdir = new THREE.Vector3(), tdir = new THREE.Vector3();

		function handleTriangle( a, b, c ) {

M
Mr.doob 已提交
696 697 698
			vA.fromArray( positions, a * 3 );
			vB.fromArray( positions, b * 3 );
			vC.fromArray( positions, c * 3 );
699

M
Mr.doob 已提交
700 701 702
			uvA.fromArray( uvs, a * 2 );
			uvB.fromArray( uvs, b * 2 );
			uvC.fromArray( uvs, c * 2 );
703

M
Mr.doob 已提交
704 705
			x1 = vB.x - vA.x;
			x2 = vC.x - vA.x;
706

M
Mr.doob 已提交
707 708
			y1 = vB.y - vA.y;
			y2 = vC.y - vA.y;
709

M
Mr.doob 已提交
710 711
			z1 = vB.z - vA.z;
			z2 = vC.z - vA.z;
712

M
Mr.doob 已提交
713 714
			s1 = uvB.x - uvA.x;
			s2 = uvC.x - uvA.x;
715

M
Mr.doob 已提交
716 717
			t1 = uvB.y - uvA.y;
			t2 = uvC.y - uvA.y;
718 719 720

			r = 1.0 / ( s1 * t2 - s2 * t1 );

721 722 723 724 725 726 727 728 729 730 731
			sdir.set(
				( t2 * x1 - t1 * x2 ) * r,
				( t2 * y1 - t1 * y2 ) * r,
				( t2 * z1 - t1 * z2 ) * r
			);

			tdir.set(
				( s1 * x2 - s2 * x1 ) * r,
				( s1 * y2 - s2 * y1 ) * r,
				( s1 * z2 - s2 * z1 ) * r
			);
732

733 734 735
			tan1[ a ].add( sdir );
			tan1[ b ].add( sdir );
			tan1[ c ].add( sdir );
736

737 738 739
			tan2[ a ].add( tdir );
			tan2[ b ].add( tdir );
			tan2[ c ].add( tdir );
740 741 742 743 744 745 746

		}

		var i, il;
		var j, jl;
		var iA, iB, iC;

747
		if ( this.drawcalls.length === 0 ) {
748

749
			this.addDrawCall( 0, indices.length, 0 );
750

751 752 753 754 755 756 757 758 759
		}

		var drawcalls = this.drawcalls;

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

			var start = drawcalls[ j ].start;
			var count = drawcalls[ j ].count;
			var index = drawcalls[ j ].index;
760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778

			for ( i = start, il = start + count; i < il; i += 3 ) {

				iA = index + indices[ i ];
				iB = index + indices[ i + 1 ];
				iC = index + indices[ i + 2 ];

				handleTriangle( iA, iB, iC );

			}

		}

		var tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3();
		var n = new THREE.Vector3(), n2 = new THREE.Vector3();
		var w, t, test;

		function handleVertex( v ) {

M
Mr.doob 已提交
779
			n.fromArray( normals, v * 3 );
780 781 782 783 784 785 786
			n2.copy( n );

			t = tan1[ v ];

			// Gram-Schmidt orthogonalize

			tmp.copy( t );
787
			tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize();
788 789 790

			// Calculate handedness

791
			tmp2.crossVectors( n2, t );
792
			test = tmp2.dot( tan2[ v ] );
793
			w = ( test < 0.0 ) ? - 1.0 : 1.0;
794

M
Mr.doob 已提交
795
			tangents[ v * 4     ] = tmp.x;
796 797 798 799 800 801
			tangents[ v * 4 + 1 ] = tmp.y;
			tangents[ v * 4 + 2 ] = tmp.z;
			tangents[ v * 4 + 3 ] = w;

		}

802
		for ( j = 0, jl = drawcalls.length; j < jl; ++ j ) {
803

804 805 806
			var start = drawcalls[ j ].start;
			var count = drawcalls[ j ].count;
			var index = drawcalls[ j ].index;
807 808 809 810 811 812 813 814 815 816 817 818 819 820 821

			for ( i = start, il = start + count; i < il; i += 3 ) {

				iA = index + indices[ i ];
				iB = index + indices[ i + 1 ];
				iC = index + indices[ i + 2 ];

				handleVertex( iA );
				handleVertex( iB );
				handleVertex( iC );

			}

		}

822 823
	},

824
	/*
M
Mr.doob 已提交
825 826 827
	Compute the draw offset for large models by chunking the index buffer into chunks of 65k addressable vertices.
	This method will effectively rewrite the index buffer and remap all attributes to match the new indices.
	WARNING: This method will also expand the vertex count to prevent sprawled triangles across draw offsets.
828
	size - Defaults to 65535 or 4294967296 if extension OES_element_index_uint supported, but allows for larger or smaller chunks.
829
	*/
M
Mr.doob 已提交
830
	computeOffsets: function ( size ) {
831

832
		if ( size === undefined ) size = THREE.BufferGeometry.MaxIndex;
833

834 835
		var indices = this.attributes.index.array;
		var vertices = this.attributes.position.array;
836

837
		var facesCount = ( indices.length / 3 );
838

839
		var UintArray = ( ( vertices.length / 3 ) > 65535 && THREE.BufferGeometry.MaxIndex > 65535 ) ? Uint32Array : Uint16Array;
840

841
		/*
842 843 844
		console.log("Computing buffers in offsets of "+size+" -> indices:"+indices.length+" vertices:"+vertices.length);
		console.log("Faces to process: "+(indices.length/3));
		console.log("Reordering "+verticesCount+" vertices.");
845 846
		*/

847 848
		var sortedIndices = new UintArray( indices.length );

849 850 851
		var indexPtr = 0;
		var vertexPtr = 0;

D
dubejf 已提交
852 853
		var tmpOffsets = [ { start:0, count:0, index:0 } ];
		var offset = tmpOffsets[ 0 ];
854 855 856

		var duplicatedVertices = 0;
		var newVerticeMaps = 0;
857
		var faceVertices = new Int32Array( 6 );
858 859
		var vertexMap = new Int32Array( vertices.length );
		var revVertexMap = new Int32Array( vertices.length );
860
		for ( var j = 0; j < vertices.length; j ++ ) { vertexMap[ j ] = - 1; revVertexMap[ j ] = - 1; }
861 862 863

		/*
			Traverse every face and reorder vertices in the proper offsets of 65k.
864
			We can have more than 'size' entries in the index buffer per offset, but only reference 'size' values.
865
		*/
866
		for ( var findex = 0; findex < facesCount; findex ++ ) {
867 868
			newVerticeMaps = 0;

869 870
			for ( var vo = 0; vo < 3; vo ++ ) {
				var vid = indices[ findex * 3 + vo ];
F
Fabian Lange 已提交
871
				if ( vertexMap[ vid ] === - 1 ) {
D
dubejf 已提交
872
					//Unmapped vertex
873 874 875 876
					faceVertices[ vo * 2 ] = vid;
					faceVertices[ vo * 2 + 1 ] = - 1;
					newVerticeMaps ++;
				} else if ( vertexMap[ vid ] < offset.index ) {
877
					//Reused vertices from previous block (duplicate)
878 879 880
					faceVertices[ vo * 2 ] = vid;
					faceVertices[ vo * 2 + 1 ] = - 1;
					duplicatedVertices ++;
881
				} else {
D
dubejf 已提交
882
					//Reused vertex in the current block
883 884
					faceVertices[ vo * 2 ] = vid;
					faceVertices[ vo * 2 + 1 ] = vertexMap[ vid ];
885 886 887 888
				}
			}

			var faceMax = vertexPtr + newVerticeMaps;
889
			if ( faceMax > ( offset.index + size ) ) {
890
				var new_offset = { start:indexPtr, count:0, index:vertexPtr };
D
dubejf 已提交
891
				tmpOffsets.push( new_offset );
892 893 894
				offset = new_offset;

				//Re-evaluate reused vertices in light of new offset.
895 896 897 898
				for ( var v = 0; v < 6; v += 2 ) {
					var new_vid = faceVertices[ v + 1 ];
					if ( new_vid > - 1 && new_vid < offset.index )
						faceVertices[ v + 1 ] = - 1;
899 900 901 902
				}
			}

			//Reindex the face.
903 904 905
			for ( var v = 0; v < 6; v += 2 ) {
				var vid = faceVertices[ v ];
				var new_vid = faceVertices[ v + 1 ];
906

907 908
				if ( new_vid === - 1 )
					new_vid = vertexPtr ++;
909

910 911 912 913
				vertexMap[ vid ] = new_vid;
				revVertexMap[ new_vid ] = vid;
				sortedIndices[ indexPtr ++ ] = new_vid - offset.index; //XXX overflows at 16bit
				offset.count ++;
914 915 916
			}
		}

D
dubejf 已提交
917
		/* Move all attribute values to map to the new computed indices , also expand the vertex stack to match our new vertexPtr. */
918
		this.reorderBuffers( sortedIndices, revVertexMap, vertexPtr );
D
dubejf 已提交
919 920 921 922 923 924 925 926

		this.clearDrawCalls();
		for ( var i = 0; i < tmpOffsets.length; i ++ ) {

			var offset = tmpOffsets[ i ];
			this.addDrawCall( offset.start, offset.count, offset.index );

		}
927 928 929

		/*
		var orderTime = Date.now();
930 931 932
		console.log("Reorder time: "+(orderTime-s)+"ms");
		console.log("Duplicated "+duplicatedVertices+" vertices.");
		console.log("Compute Buffers time: "+(Date.now()-s)+"ms");
D
dubejf 已提交
933
		console.log("Draw tmpOffsets: "+tmpOffsets.length);
934 935 936 937
		*/

	},

938 939 940 941
	merge: function ( geometry, offset ) {

		if ( geometry instanceof THREE.BufferGeometry === false ) {

942
			console.error( 'THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry );
943 944 945 946 947 948 949 950 951 952 953
			return;

		}

		if ( offset === undefined ) offset = 0;

		var attributes = this.attributes;

		for ( var key in attributes ) {

			if ( geometry.attributes[ key ] === undefined ) continue;
954

955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971
			var attribute1 = attributes[ key ];
			var attributeArray1 = attribute1.array;

			var attribute2 = geometry.attributes[ key ];
			var attributeArray2 = attribute2.array;

			var attributeSize = attribute2.itemSize;

			for ( var i = 0, j = attributeSize * offset; i < attributeArray2.length; i ++, j ++ ) {

				attributeArray1[ j ] = attributeArray2[ i ];

			}

		}

		return this;
972 973 974 975 976

	},

	normalizeNormals: function () {

977
		var normals = this.attributes.normal.array;
978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996

		var x, y, z, n;

		for ( var i = 0, il = normals.length; i < il; i += 3 ) {

			x = normals[ i ];
			y = normals[ i + 1 ];
			z = normals[ i + 2 ];

			n = 1.0 / Math.sqrt( x * x + y * y + z * z );

			normals[ i     ] *= n;
			normals[ i + 1 ] *= n;
			normals[ i + 2 ] *= n;

		}

	},

997 998 999 1000 1001
	/*
		reoderBuffers:
		Reorder attributes based on a new indexBuffer and indexMap.
		indexBuffer - Uint16Array of the new ordered indices.
		indexMap - Int32Array where the position is the new vertex ID and the value the old vertex ID for each vertex.
D
dubejf 已提交
1002
		vertexCount - Amount of total vertices considered in this reordering (in case you want to grow the vertex stack).
1003
	*/
1004
	reorderBuffers: function ( indexBuffer, indexMap, vertexCount ) {
1005 1006 1007

		/* Create a copy of all attributes for reordering. */
		var sortedAttributes = {};
1008
		for ( var attr in this.attributes ) {
F
Fabian Lange 已提交
1009
			if ( attr === 'index' )
1010
				continue;
1011
			var sourceArray = this.attributes[ attr ].array;
1012
			sortedAttributes[ attr ] = new sourceArray.constructor( this.attributes[ attr ].itemSize * vertexCount );
1013 1014 1015
		}

		/* Move attribute positions based on the new index map */
1016 1017
		for ( var new_vid = 0; new_vid < vertexCount; new_vid ++ ) {
			var vid = indexMap[ new_vid ];
1018
			for ( var attr in this.attributes ) {
F
Fabian Lange 已提交
1019
				if ( attr === 'index' )
1020
					continue;
1021 1022 1023 1024
				var attrArray = this.attributes[ attr ].array;
				var attrSize = this.attributes[ attr ].itemSize;
				var sortedAttr = sortedAttributes[ attr ];
				for ( var k = 0; k < attrSize; k ++ )
1025 1026 1027 1028 1029
					sortedAttr[ new_vid * attrSize + k ] = attrArray[ vid * attrSize + k ];
			}
		}

		/* Carry the new sorted buffers locally */
1030
		this.attributes[ 'index' ].array = indexBuffer;
1031
		for ( var attr in this.attributes ) {
F
Fabian Lange 已提交
1032
			if ( attr === 'index' )
1033
				continue;
1034 1035
			this.attributes[ attr ].array = sortedAttributes[ attr ];
			this.attributes[ attr ].numItems = this.attributes[ attr ].itemSize * vertexCount;
1036 1037 1038
		}
	},

1039
	toJSON: function () {
1040

1041 1042 1043 1044 1045 1046
		var data = {
			metadata: {
				version: 4.4,
				type: 'BufferGeometry',
				generator: 'BufferGeometry.toJSON'
			}
B
brason 已提交
1047
		};
1048

1049
		// standard BufferGeometry serialization
1050

1051
		data.uuid = this.uuid;
M
Mr.doob 已提交
1052
		data.type = this.type;
1053
		if ( this.name !== '' ) data.name = this.name;
1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069

		if ( this.parameters !== undefined ) {

			var parameters = this.parameters;

			for ( var key in parameters ) {

				if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ];

			}

			return data;

		}

		data.data = { attributes: {} };
1070

1071
		var attributes = this.attributes;
D
dubejf 已提交
1072
		var offsets = this.drawcalls;
1073 1074 1075 1076 1077 1078
		var boundingSphere = this.boundingSphere;

		for ( var key in attributes ) {

			var attribute = attributes[ key ];

M
makc 已提交
1079
			var array = Array.prototype.slice.call( attribute.array );
1080

1081
			data.data.attributes[ key ] = {
1082 1083 1084 1085 1086 1087 1088 1089 1090
				itemSize: attribute.itemSize,
				type: attribute.array.constructor.name,
				array: array
			}

		}

		if ( offsets.length > 0 ) {

1091
			data.data.offsets = JSON.parse( JSON.stringify( offsets ) );
1092 1093 1094 1095 1096

		}

		if ( boundingSphere !== null ) {

1097
			data.data.boundingSphere = {
1098 1099 1100 1101 1102 1103
				center: boundingSphere.center.toArray(),
				radius: boundingSphere.radius
			}

		}

1104
		return data;
1105 1106 1107

	},

M
Mr.doob 已提交
1108
	clone: function () {
O
ohmed 已提交
1109 1110 1111 1112 1113

		var geometry = new THREE.BufferGeometry();

		for ( var attr in this.attributes ) {

M
Mr.doob 已提交
1114
			var sourceAttr = this.attributes[ attr ];
D
dubejf 已提交
1115
			geometry.addAttribute( attr, sourceAttr.clone() );
O
ohmed 已提交
1116 1117 1118

		}

D
dubejf 已提交
1119
		for ( var i = 0, il = this.drawcalls.length; i < il; i ++ ) {
O
ohmed 已提交
1120

D
dubejf 已提交
1121
			var offset = this.drawcalls[ i ];
O
ohmed 已提交
1122

D
dubejf 已提交
1123
			geometry.addDrawCall( offset.start, offset.count, offset.index );
O
ohmed 已提交
1124

O
ohmed 已提交
1125
		}
O
ohmed 已提交
1126 1127 1128 1129 1130

		return geometry;

	},

1131
	dispose: function () {
1132

1133
		this.dispatchEvent( { type: 'dispose' } );
1134

1135
	}
1136 1137

};
M
Mr.doob 已提交
1138 1139

THREE.EventDispatcher.prototype.apply( THREE.BufferGeometry.prototype );
1140

1141
THREE.BufferGeometry.MaxIndex = 65535;