BufferGeometry.js 24.5 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 20
	this.drawcalls = [];
	this.offsets = this.drawcalls; // backwards compatibility
21

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

};

THREE.BufferGeometry.prototype = {

29
	constructor: THREE.BufferGeometry,
30

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

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

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

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

			return;

		}

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

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

	getAttribute: function ( name ) {

49 50
		return this.attributes[ name ];

51 52
	},

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

55
		this.drawcalls.push( {
M
Mr.doob 已提交
56 57 58

			start: start,
			count: count,
M
Mr.doob 已提交
59
			index: indexOffset !== undefined ? indexOffset : 0
M
Mr.doob 已提交
60 61 62 63 64

		} );

	},

65 66
	applyMatrix: function ( matrix ) {

M
Mr.doob 已提交
67
		var position = this.attributes.position;
68

M
Mr.doob 已提交
69
		if ( position !== undefined ) {
70

71
			matrix.applyToVector3Array( position.array );
M
Mr.doob 已提交
72
			position.needsUpdate = true;
73 74 75

		}

M
Mr.doob 已提交
76
		var normal = this.attributes.normal;
77

M
Mr.doob 已提交
78
		if ( normal !== undefined ) {
79

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

82
			normalMatrix.applyToVector3Array( normal.array );
M
Mr.doob 已提交
83
			normal.needsUpdate = true;
84 85 86

		}

M
Mr.doob 已提交
87
		if ( this.boundingBox !== null ) {
88 89 90 91 92

			this.computeBoundingBox();

		}

M
Mr.doob 已提交
93
		if ( this.boundingSphere !== null ) {
94 95 96 97 98

			this.computeBoundingSphere();

		}

99 100
	},

M
Mr.doob 已提交
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
	copy: function ( geometry ) {

		var attributes = geometry.attributes;
		var offsets = geometry.offsets;

		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 ];

			this.offsets.push( {

				start: offset.start,
				index: offset.index,
				count: offset.count

			} );

		}

		return this;

	},

132 133
	center: function () {

M
Mr.doob 已提交
134 135 136 137 138 139 140
		this.computeBoundingBox();

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

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

		return offset;
141 142 143

	},

144
	setFromObject: function ( object ) {
145

146
		console.log( 'THREE.BufferGeometry.setFromObject(). Converting', object, this );
147

148 149 150 151 152
		var geometry = object.geometry;
		var material = object.material;

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

153 154
			var positions = new THREE.Float32Attribute( geometry.vertices.length * 3, 3 );
			var colors = new THREE.Float32Attribute( geometry.colors.length * 3, 3 );
155

156 157
			this.addAttribute( 'position', positions.copyVector3sArray( geometry.vertices ) );
			this.addAttribute( 'color', colors.copyColorsArray( geometry.colors ) );
158 159 160 161 162 163 164 165 166 167 168 169

			if ( geometry.boundingSphere !== null ) {

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

			}

			if ( geometry.boundingBox !== null ) {

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

			}
170 171 172

		} else if ( object instanceof THREE.Mesh ) {

M
Mr.doob 已提交
173
			if ( geometry instanceof THREE.Geometry ) {
174 175

				this.fromGeometry( geometry );
176

M
Mr.doob 已提交
177
			}
178 179 180 181 182 183 184

		}

		return this;

	},

185 186
	updateFromObject: function ( object ) {

M
Mr.doob 已提交
187
		var geometry = object.geometry;
188

M
Mr.doob 已提交
189
		if ( object instanceof THREE.Mesh ) {
190

M
Mr.doob 已提交
191
			var direct = geometry.__directGeometry;
192

M
Mr.doob 已提交
193 194 195 196
			direct.verticesNeedUpdate = geometry.verticesNeedUpdate;
			direct.normalsNeedUpdate = geometry.normalsNeedUpdate;
			direct.colorsNeedUpdate = geometry.colorsNeedUpdate;
			direct.uvsNeedUpdate = geometry.uvsNeedUpdate;
197
			direct.tangentsNeedUpdate = geometry.tangentsNeedUpdate;
M
Mr.doob 已提交
198 199 200 201 202

			geometry.verticesNeedUpdate = false;
			geometry.normalsNeedUpdate = false;
			geometry.colorsNeedUpdate = false;
			geometry.uvsNeedUpdate = false;
203
			geometry.tangentsNeedUpdate = false;
204

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

		}
208

M
Mr.doob 已提交
209
		if ( geometry.verticesNeedUpdate === true ) {
210

M
Mr.doob 已提交
211
			var attribute = this.attributes.position;
212

M
Mr.doob 已提交
213
			if ( attribute !== undefined ) {
214

M
Mr.doob 已提交
215 216
				attribute.copyVector3sArray( geometry.vertices );
				attribute.needsUpdate = true;
217 218 219

			}

M
Mr.doob 已提交
220
			geometry.verticesNeedUpdate = false;
221

M
Mr.doob 已提交
222
		}
223

224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
		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 已提交
239
		if ( geometry.colorsNeedUpdate === true ) {
240

M
Mr.doob 已提交
241
			var attribute = this.attributes.color;
242

M
Mr.doob 已提交
243
			if ( attribute !== undefined ) {
244

M
Mr.doob 已提交
245 246
				attribute.copyColorsArray( geometry.colors );
				attribute.needsUpdate = true;
247 248 249

			}

M
Mr.doob 已提交
250 251
			geometry.colorsNeedUpdate = false;

252
		}
253

254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
		if ( geometry.tangentsNeedUpdate === true ) {

			var attribute = this.attributes.tangent;

			if ( attribute !== undefined ) {

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

			}

			geometry.tangentsNeedUpdate = false;

		}

269
		return this;
270 271 272

	},

273
	fromGeometry: function ( geometry ) {
274

275
		geometry.__directGeometry = new THREE.DirectGeometry().fromGeometry( geometry );
276 277

		return this.fromDirectGeometry( geometry.__directGeometry );
278

279
	},
280

281
	fromDirectGeometry: function ( geometry ) {
282

M
Mr.doob 已提交
283 284 285 286 287 288 289
		if ( geometry.indices.length > 0 ) {

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

		}

290
		if ( geometry.vertices.length > 0 ) {
291

292 293
			var positions = new Float32Array( geometry.vertices.length * 3 );
			this.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ).copyVector3sArray( geometry.vertices ) );
294

295 296
		}

297 298 299 300 301 302 303 304
		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 已提交
305

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

309 310 311 312 313 314 315 316
		}

		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 已提交
317

318 319 320 321 322 323 324 325 326 327 328 329 330 331
		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 ) );

		}

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
		// 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 ) );

		}

		//

370 371 372 373 374 375 376 377 378 379 380
		if ( geometry.boundingSphere !== null ) {

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

		}

		if ( geometry.boundingBox !== null ) {

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

		}
M
Mr.doob 已提交
381 382 383 384 385

		return this;

	},

386 387
	computeBoundingBox: function () {

388
		var vector = new THREE.Vector3();
389

390
		return function () {
391

392
			if ( this.boundingBox === null ) {
393

394
				this.boundingBox = new THREE.Box3();
395

396 397
			}

398
			var positions = this.attributes.position.array;
399

400
			if ( positions ) {
401

402 403
				var bb = this.boundingBox;
				bb.makeEmpty();
404

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

407
					vector.fromArray( positions, i );
408
					bb.expandByPoint( vector );
409 410 411 412 413

				}

			}

414
			if ( positions === undefined || positions.length === 0 ) {
415

416 417
				this.boundingBox.min.set( 0, 0, 0 );
				this.boundingBox.max.set( 0, 0, 0 );
418

419
			}
420

421
			if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) {
422

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

425
			}
426

G
Greg French 已提交
427
		};
428

429
	}(),
430 431 432

	computeBoundingSphere: function () {

433 434
		var box = new THREE.Box3();
		var vector = new THREE.Vector3();
435

436
		return function () {
437

438
			if ( this.boundingSphere === null ) {
439

440
				this.boundingSphere = new THREE.Sphere();
441

442
			}
443

444
			var positions = this.attributes.position.array;
445

446
			if ( positions ) {
447

448 449
				box.makeEmpty();

450
				var center = this.boundingSphere.center;
451

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

454
					vector.fromArray( positions, i );
J
Jan Wrobel 已提交
455
					box.expandByPoint( vector );
456 457 458 459 460

				}

				box.center( center );

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

464 465
				var maxRadiusSq = 0;

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

468
					vector.fromArray( positions, i );
469
					maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) );
470

471 472 473 474
				}

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

475 476
				if ( isNaN( this.boundingSphere.radius ) ) {

477
					console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this );
478 479 480

				}

481
			}
482

G
Greg French 已提交
483
		};
484

485
	}(),
486

487 488 489 490 491 492
	computeFaceNormals: function () {

		// backwards compatibility

	},

493 494
	computeVertexNormals: function () {

495
		var attributes = this.attributes;
496

497
		if ( attributes.position ) {
498

499
			var positions = attributes.position.array;
500

501
			if ( attributes.normal === undefined ) {
502

503
				this.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( positions.length ), 3 ) );
504 505 506 507 508

			} else {

				// reset existing normals to zero

509 510 511
				var normals = attributes.normal.array;

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

513
					normals[ i ] = 0;
514 515 516 517 518

				}

			}

519
			var normals = attributes.normal.array;
520

M
Mr.doob 已提交
521
			var vA, vB, vC,
522 523 524 525 526 527 528 529

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

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

530 531
			// indexed elements

532
			if ( attributes.index ) {
533

534
				var indices = attributes.index.array;
535

536
				var offsets = ( this.offsets.length > 0 ? this.offsets : [ { start: 0, count: indices.length, index: 0 } ] );
537

538
				for ( var j = 0, jl = offsets.length; j < jl; ++ j ) {
539 540 541 542 543

					var start = offsets[ j ].start;
					var count = offsets[ j ].count;
					var index = offsets[ j ].index;

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

M
Mr.doob 已提交
546 547 548
						vA = ( index + indices[ i     ] ) * 3;
						vB = ( index + indices[ i + 1 ] ) * 3;
						vC = ( index + indices[ i + 2 ] ) * 3;
549

M
Mr.doob 已提交
550 551 552
						pA.fromArray( positions, vA );
						pB.fromArray( positions, vB );
						pC.fromArray( positions, vC );
553

554 555 556
						cb.subVectors( pC, pB );
						ab.subVectors( pA, pB );
						cb.cross( ab );
557

M
Mr.doob 已提交
558 559 560
						normals[ vA     ] += cb.x;
						normals[ vA + 1 ] += cb.y;
						normals[ vA + 2 ] += cb.z;
561

M
Mr.doob 已提交
562 563 564
						normals[ vB     ] += cb.x;
						normals[ vB + 1 ] += cb.y;
						normals[ vB + 2 ] += cb.z;
565

M
Mr.doob 已提交
566 567 568
						normals[ vC     ] += cb.x;
						normals[ vC + 1 ] += cb.y;
						normals[ vC + 2 ] += cb.z;
569 570 571 572 573 574

					}

				}

			} else {
575

576 577 578
				// non-indexed elements (unconnected triangle soup)

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

M
Mr.doob 已提交
580 581 582
					pA.fromArray( positions, i );
					pB.fromArray( positions, i + 3 );
					pC.fromArray( positions, i + 6 );
583

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

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

592 593 594
					normals[ i + 3 ] = cb.x;
					normals[ i + 4 ] = cb.y;
					normals[ i + 5 ] = cb.z;
595

596 597 598
					normals[ i + 6 ] = cb.x;
					normals[ i + 7 ] = cb.y;
					normals[ i + 8 ] = cb.z;
599 600 601 602 603

				}

			}

604
			this.normalizeNormals();
605

606
			attributes.normal.needsUpdate = true;
607

608
		}
609

610
	},
611

612 613 614 615 616
	computeTangents: function () {

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

617 618 619 620
		if ( this.attributes.index === undefined ||
			 this.attributes.position === undefined ||
			 this.attributes.normal === undefined ||
			 this.attributes.uv === undefined ) {
621

622
			console.warn( 'THREE.BufferGeometry: Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()' );
623 624 625 626
			return;

		}

627 628 629 630
		var indices = this.attributes.index.array;
		var positions = this.attributes.position.array;
		var normals = this.attributes.normal.array;
		var uvs = this.attributes.uv.array;
631 632 633

		var nVertices = positions.length / 3;

634
		if ( this.attributes.tangent === undefined ) {
635

636
			this.addAttribute( 'tangent', new THREE.BufferAttribute( new Float32Array( 4 * nVertices ), 4 ) );
637 638 639

		}

640
		var tangents = this.attributes.tangent.array;
641 642 643 644 645 646 647 648 649 650

		var tan1 = [], tan2 = [];

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

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

		}

M
Mr.doob 已提交
651 652 653
		var vA = new THREE.Vector3(),
			vB = new THREE.Vector3(),
			vC = new THREE.Vector3(),
654

M
Mr.doob 已提交
655 656 657
			uvA = new THREE.Vector2(),
			uvB = new THREE.Vector2(),
			uvC = new THREE.Vector2(),
658 659 660 661 662 663 664 665

			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 已提交
666 667 668
			vA.fromArray( positions, a * 3 );
			vB.fromArray( positions, b * 3 );
			vC.fromArray( positions, c * 3 );
669

M
Mr.doob 已提交
670 671 672
			uvA.fromArray( uvs, a * 2 );
			uvB.fromArray( uvs, b * 2 );
			uvC.fromArray( uvs, c * 2 );
673

M
Mr.doob 已提交
674 675
			x1 = vB.x - vA.x;
			x2 = vC.x - vA.x;
676

M
Mr.doob 已提交
677 678
			y1 = vB.y - vA.y;
			y2 = vC.y - vA.y;
679

M
Mr.doob 已提交
680 681
			z1 = vB.z - vA.z;
			z2 = vC.z - vA.z;
682

M
Mr.doob 已提交
683 684
			s1 = uvB.x - uvA.x;
			s2 = uvC.x - uvA.x;
685

M
Mr.doob 已提交
686 687
			t1 = uvB.y - uvA.y;
			t2 = uvC.y - uvA.y;
688 689 690

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

691 692 693 694 695 696 697 698 699 700 701
			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
			);
702

703 704 705
			tan1[ a ].add( sdir );
			tan1[ b ].add( sdir );
			tan1[ c ].add( sdir );
706

707 708 709
			tan2[ a ].add( tdir );
			tan2[ b ].add( tdir );
			tan2[ c ].add( tdir );
710 711 712 713 714 715 716

		}

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

717
		if ( this.drawcalls.length === 0 ) {
718

719
			this.addDrawCall( 0, indices.length, 0 );
720

721 722 723 724 725 726 727 728 729
		}

		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;
730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748

			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 已提交
749
			n.fromArray( normals, v * 3 );
750 751 752 753 754 755 756
			n2.copy( n );

			t = tan1[ v ];

			// Gram-Schmidt orthogonalize

			tmp.copy( t );
757
			tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize();
758 759 760

			// Calculate handedness

761
			tmp2.crossVectors( n2, t );
762
			test = tmp2.dot( tan2[ v ] );
763
			w = ( test < 0.0 ) ? - 1.0 : 1.0;
764

M
Mr.doob 已提交
765
			tangents[ v * 4     ] = tmp.x;
766 767 768 769 770 771
			tangents[ v * 4 + 1 ] = tmp.y;
			tangents[ v * 4 + 2 ] = tmp.z;
			tangents[ v * 4 + 3 ] = w;

		}

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

774 775 776
			var start = drawcalls[ j ].start;
			var count = drawcalls[ j ].count;
			var index = drawcalls[ j ].index;
777 778 779 780 781 782 783 784 785 786 787 788 789 790 791

			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 );

			}

		}

792 793
	},

794
	/*
M
Mr.doob 已提交
795 796 797
	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.
798
	size - Defaults to 65535 or 4294967296 if extension OES_element_index_uint supported, but allows for larger or smaller chunks.
799
	*/
M
Mr.doob 已提交
800
	computeOffsets: function ( size ) {
801

802
		if ( size === undefined ) size = THREE.BufferGeometry.MaxIndex;
803

804 805
		var indices = this.attributes.index.array;
		var vertices = this.attributes.position.array;
806

807
		var facesCount = ( indices.length / 3 );
808

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

811
		/*
812 813 814
		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.");
815 816
		*/

817 818
		var sortedIndices = new UintArray( indices.length );

819 820 821 822
		var indexPtr = 0;
		var vertexPtr = 0;

		var offsets = [ { start:0, count:0, index:0 } ];
823
		var offset = offsets[ 0 ];
824 825 826

		var duplicatedVertices = 0;
		var newVerticeMaps = 0;
827
		var faceVertices = new Int32Array( 6 );
828 829
		var vertexMap = new Int32Array( vertices.length );
		var revVertexMap = new Int32Array( vertices.length );
830
		for ( var j = 0; j < vertices.length; j ++ ) { vertexMap[ j ] = - 1; revVertexMap[ j ] = - 1; }
831 832 833

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

839 840
			for ( var vo = 0; vo < 3; vo ++ ) {
				var vid = indices[ findex * 3 + vo ];
F
Fabian Lange 已提交
841
				if ( vertexMap[ vid ] === - 1 ) {
842
					//Unmapped vertice
843 844 845 846
					faceVertices[ vo * 2 ] = vid;
					faceVertices[ vo * 2 + 1 ] = - 1;
					newVerticeMaps ++;
				} else if ( vertexMap[ vid ] < offset.index ) {
847
					//Reused vertices from previous block (duplicate)
848 849 850
					faceVertices[ vo * 2 ] = vid;
					faceVertices[ vo * 2 + 1 ] = - 1;
					duplicatedVertices ++;
851 852
				} else {
					//Reused vertice in the current block
853 854
					faceVertices[ vo * 2 ] = vid;
					faceVertices[ vo * 2 + 1 ] = vertexMap[ vid ];
855 856 857 858
				}
			}

			var faceMax = vertexPtr + newVerticeMaps;
859
			if ( faceMax > ( offset.index + size ) ) {
860
				var new_offset = { start:indexPtr, count:0, index:vertexPtr };
861
				offsets.push( new_offset );
862 863 864
				offset = new_offset;

				//Re-evaluate reused vertices in light of new offset.
865 866 867 868
				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;
869 870 871 872
				}
			}

			//Reindex the face.
873 874 875
			for ( var v = 0; v < 6; v += 2 ) {
				var vid = faceVertices[ v ];
				var new_vid = faceVertices[ v + 1 ];
876

877 878
				if ( new_vid === - 1 )
					new_vid = vertexPtr ++;
879

880 881 882 883
				vertexMap[ vid ] = new_vid;
				revVertexMap[ new_vid ] = vid;
				sortedIndices[ indexPtr ++ ] = new_vid - offset.index; //XXX overflows at 16bit
				offset.count ++;
884 885 886 887
			}
		}

		/* Move all attribute values to map to the new computed indices , also expand the vertice stack to match our new vertexPtr. */
888
		this.reorderBuffers( sortedIndices, revVertexMap, vertexPtr );
889 890
		this.offsets = offsets; // TODO: Deprecate
		this.drawcalls = offsets;
891 892 893

		/*
		var orderTime = Date.now();
894 895 896 897
		console.log("Reorder time: "+(orderTime-s)+"ms");
		console.log("Duplicated "+duplicatedVertices+" vertices.");
		console.log("Compute Buffers time: "+(Date.now()-s)+"ms");
		console.log("Draw offsets: "+offsets.length);
898 899 900
		*/

		return offsets;
901

902 903
	},

904 905 906 907
	merge: function ( geometry, offset ) {

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

908
			console.error( 'THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry );
909 910 911 912 913 914 915 916 917 918 919
			return;

		}

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

		var attributes = this.attributes;

		for ( var key in attributes ) {

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

921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937
			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;
938 939 940 941 942

	},

	normalizeNormals: function () {

943
		var normals = this.attributes.normal.array;
944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962

		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;

		}

	},

963 964 965 966 967 968 969
	/*
		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.
		vertexCount - Amount of total vertices considered in this reordering (in case you want to grow the vertice stack).
	*/
970
	reorderBuffers: function ( indexBuffer, indexMap, vertexCount ) {
971 972 973

		/* Create a copy of all attributes for reordering. */
		var sortedAttributes = {};
974
		for ( var attr in this.attributes ) {
F
Fabian Lange 已提交
975
			if ( attr === 'index' )
976
				continue;
977
			var sourceArray = this.attributes[ attr ].array;
978
			sortedAttributes[ attr ] = new sourceArray.constructor( this.attributes[ attr ].itemSize * vertexCount );
979 980 981
		}

		/* Move attribute positions based on the new index map */
982 983
		for ( var new_vid = 0; new_vid < vertexCount; new_vid ++ ) {
			var vid = indexMap[ new_vid ];
984
			for ( var attr in this.attributes ) {
F
Fabian Lange 已提交
985
				if ( attr === 'index' )
986
					continue;
987 988 989 990
				var attrArray = this.attributes[ attr ].array;
				var attrSize = this.attributes[ attr ].itemSize;
				var sortedAttr = sortedAttributes[ attr ];
				for ( var k = 0; k < attrSize; k ++ )
991 992 993 994 995
					sortedAttr[ new_vid * attrSize + k ] = attrArray[ vid * attrSize + k ];
			}
		}

		/* Carry the new sorted buffers locally */
996
		this.attributes[ 'index' ].array = indexBuffer;
997
		for ( var attr in this.attributes ) {
F
Fabian Lange 已提交
998
			if ( attr === 'index' )
999
				continue;
1000 1001
			this.attributes[ attr ].array = sortedAttributes[ attr ];
			this.attributes[ attr ].numItems = this.attributes[ attr ].itemSize * vertexCount;
1002 1003 1004
		}
	},

1005
	toJSON: function () {
1006

1007 1008 1009 1010 1011 1012
		var data = {
			metadata: {
				version: 4.4,
				type: 'BufferGeometry',
				generator: 'BufferGeometry.toJSON'
			}
B
brason 已提交
1013
		};
1014

1015
		// standard BufferGeometry serialization
1016

1017
		data.uuid = this.uuid;
M
Mr.doob 已提交
1018
		data.type = this.type;
1019
		if ( this.name !== '' ) data.name = this.name;
1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035

		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: {} };
1036

1037
		var attributes = this.attributes;
1038 1039 1040 1041 1042 1043 1044
		var offsets = this.offsets;
		var boundingSphere = this.boundingSphere;

		for ( var key in attributes ) {

			var attribute = attributes[ key ];

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

1047
			data.data.attributes[ key ] = {
1048 1049 1050 1051 1052 1053 1054 1055 1056
				itemSize: attribute.itemSize,
				type: attribute.array.constructor.name,
				array: array
			}

		}

		if ( offsets.length > 0 ) {

1057
			data.data.offsets = JSON.parse( JSON.stringify( offsets ) );
1058 1059 1060 1061 1062

		}

		if ( boundingSphere !== null ) {

1063
			data.data.boundingSphere = {
1064 1065 1066 1067 1068 1069
				center: boundingSphere.center.toArray(),
				radius: boundingSphere.radius
			}

		}

1070
		return data;
1071 1072 1073

	},

M
Mr.doob 已提交
1074
	clone: function () {
O
ohmed 已提交
1075 1076 1077 1078 1079

		var geometry = new THREE.BufferGeometry();

		for ( var attr in this.attributes ) {

M
Mr.doob 已提交
1080
			var sourceAttr = this.attributes[ attr ];
D
dubejf 已提交
1081
			geometry.addAttribute( attr, sourceAttr.clone() );
O
ohmed 已提交
1082 1083 1084

		}

O
ohmed 已提交
1085
		for ( var i = 0, il = this.offsets.length; i < il; i ++ ) {
O
ohmed 已提交
1086 1087 1088

			var offset = this.offsets[ i ];

M
Mr.doob 已提交
1089
			geometry.offsets.push( {
O
ohmed 已提交
1090

O
ohmed 已提交
1091 1092 1093
				start: offset.start,
				index: offset.index,
				count: offset.count
O
ohmed 已提交
1094

M
Mr.doob 已提交
1095
			} );
O
ohmed 已提交
1096

O
ohmed 已提交
1097
		}
O
ohmed 已提交
1098 1099 1100 1101 1102

		return geometry;

	},

1103
	dispose: function () {
1104

1105
		this.dispatchEvent( { type: 'dispose' } );
1106

1107
	}
1108 1109

};
M
Mr.doob 已提交
1110 1111

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

1113
THREE.BufferGeometry.MaxIndex = 65535;