BufferGeometry.js 25.0 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 55 56 57
	removeAttribute: function ( name ) {

		delete this.attributes[ name ];

	},

58
	get offsets() {
59 60

		console.warn( 'THREE.BufferGeometry: .offsets has been renamed to .drawcalls.' );
61
		return this.drawcalls;
62 63 64

	},

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

67
		this.drawcalls.push( {
M
Mr.doob 已提交
68 69 70

			start: start,
			count: count,
M
Mr.doob 已提交
71
			index: indexOffset !== undefined ? indexOffset : 0
M
Mr.doob 已提交
72 73 74 75 76

		} );

	},

D
dubejf 已提交
77 78 79 80 81 82
	clearDrawCalls: function () {

		this.drawcalls = [];

	},

83 84
	applyMatrix: function ( matrix ) {

M
Mr.doob 已提交
85
		var position = this.attributes.position;
86

M
Mr.doob 已提交
87
		if ( position !== undefined ) {
88

89
			matrix.applyToVector3Array( position.array );
M
Mr.doob 已提交
90
			position.needsUpdate = true;
91 92 93

		}

M
Mr.doob 已提交
94
		var normal = this.attributes.normal;
95

M
Mr.doob 已提交
96
		if ( normal !== undefined ) {
97

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

100
			normalMatrix.applyToVector3Array( normal.array );
M
Mr.doob 已提交
101
			normal.needsUpdate = true;
102 103 104

		}

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

			this.computeBoundingBox();

		}

M
Mr.doob 已提交
111
		if ( this.boundingSphere !== null ) {
112 113 114 115 116

			this.computeBoundingSphere();

		}

117 118
	},

119 120
	center: function () {

M
Mr.doob 已提交
121 122 123 124 125 126 127
		this.computeBoundingBox();

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

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

		return offset;
128 129 130

	},

131
	setFromObject: function ( object ) {
132

133
		console.log( 'THREE.BufferGeometry.setFromObject(). Converting', object, this );
134

135 136 137 138
		var geometry = object.geometry;

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

139 140
			var positions = new THREE.Float32Attribute( geometry.vertices.length * 3, 3 );
			var colors = new THREE.Float32Attribute( geometry.colors.length * 3, 3 );
141

142 143
			this.addAttribute( 'position', positions.copyVector3sArray( geometry.vertices ) );
			this.addAttribute( 'color', colors.copyColorsArray( geometry.colors ) );
144

C
Chen Pang 已提交
145 146 147 148 149 150 151 152
			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 ) );

			}

153 154 155 156 157 158 159 160 161 162 163
			if ( geometry.boundingSphere !== null ) {

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

			}

			if ( geometry.boundingBox !== null ) {

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

			}
164 165 166

		} else if ( object instanceof THREE.Mesh ) {

M
Mr.doob 已提交
167
			if ( geometry instanceof THREE.Geometry ) {
168 169

				this.fromGeometry( geometry );
170

M
Mr.doob 已提交
171
			}
172 173 174 175 176 177 178

		}

		return this;

	},

179 180
	updateFromObject: function ( object ) {

M
Mr.doob 已提交
181
		var geometry = object.geometry;
182

M
Mr.doob 已提交
183
		if ( object instanceof THREE.Mesh ) {
184

M
Mr.doob 已提交
185
			var direct = geometry.__directGeometry;
186

187 188 189 190 191 192
			if ( direct === undefined ) {

				return this.fromGeometry( geometry );

			}

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;

		}

C
Chen Pang 已提交
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
		if ( geometry.lineDistancesNeedUpdate ) {

			var attribute = this.attributes.lineDistance;

			if ( attribute !== undefined ) {

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

			}

			geometry.lineDistancesNeedUpdate = false;

		}

284
		return this;
285 286 287

	},

288
	fromGeometry: function ( geometry ) {
289

290
		geometry.__directGeometry = new THREE.DirectGeometry().fromGeometry( geometry );
291 292

		return this.fromDirectGeometry( geometry.__directGeometry );
293

294
	},
295

296
	fromDirectGeometry: function ( geometry ) {
297

298 299
		var positions = new Float32Array( geometry.vertices.length * 3 );
		this.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ).copyVector3sArray( geometry.vertices ) );
300

301 302 303 304 305 306 307 308
		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 已提交
309

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

313 314 315 316 317 318 319 320
		}

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

322 323 324 325 326 327 328 329 330 331 332 333 334 335
		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 ) );

		}

336 337 338 339 340 341 342
		if ( geometry.indices.length > 0 ) {

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

		}

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 374 375 376 377 378 379 380
		// 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 ) );

		}

		//

381 382 383 384 385 386 387 388 389 390 391
		if ( geometry.boundingSphere !== null ) {

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

		}

		if ( geometry.boundingBox !== null ) {

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

		}
M
Mr.doob 已提交
392 393 394 395 396

		return this;

	},

397 398
	computeBoundingBox: function () {

399
		var vector = new THREE.Vector3();
400

401
		return function () {
402

403
			if ( this.boundingBox === null ) {
404

405
				this.boundingBox = new THREE.Box3();
406

407 408
			}

409
			var positions = this.attributes.position.array;
410

411
			if ( positions ) {
412

413 414
				var bb = this.boundingBox;
				bb.makeEmpty();
415

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

418
					vector.fromArray( positions, i );
419
					bb.expandByPoint( vector );
420 421 422 423 424

				}

			}

425
			if ( positions === undefined || positions.length === 0 ) {
426

427 428
				this.boundingBox.min.set( 0, 0, 0 );
				this.boundingBox.max.set( 0, 0, 0 );
429

430
			}
431

432
			if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) {
433

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

436
			}
437

G
Greg French 已提交
438
		};
439

440
	}(),
441 442 443

	computeBoundingSphere: function () {

444 445
		var box = new THREE.Box3();
		var vector = new THREE.Vector3();
446

447
		return function () {
448

449
			if ( this.boundingSphere === null ) {
450

451
				this.boundingSphere = new THREE.Sphere();
452

453
			}
454

455
			var positions = this.attributes.position.array;
456

457
			if ( positions ) {
458

459 460
				box.makeEmpty();

461
				var center = this.boundingSphere.center;
462

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

465
					vector.fromArray( positions, i );
J
Jan Wrobel 已提交
466
					box.expandByPoint( vector );
467 468 469 470 471

				}

				box.center( center );

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

475 476
				var maxRadiusSq = 0;

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

479
					vector.fromArray( positions, i );
480
					maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) );
481

482 483 484 485
				}

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

486 487
				if ( isNaN( this.boundingSphere.radius ) ) {

488
					console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this );
489 490 491

				}

492
			}
493

G
Greg French 已提交
494
		};
495

496
	}(),
497

498 499 500 501 502 503
	computeFaceNormals: function () {

		// backwards compatibility

	},

504 505
	computeVertexNormals: function () {

506
		var attributes = this.attributes;
507

508
		if ( attributes.position ) {
509

510
			var positions = attributes.position.array;
511

512
			if ( attributes.normal === undefined ) {
513

514
				this.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( positions.length ), 3 ) );
515 516 517 518 519

			} else {

				// reset existing normals to zero

520 521 522
				var normals = attributes.normal.array;

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

524
					normals[ i ] = 0;
525 526 527 528 529

				}

			}

530
			var normals = attributes.normal.array;
531

M
Mr.doob 已提交
532
			var vA, vB, vC,
533 534 535 536 537 538 539 540

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

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

541 542
			// indexed elements

543
			if ( attributes.index ) {
544

545
				var indices = attributes.index.array;
546

D
dubejf 已提交
547 548
				if ( this.drawcalls.length === 0 ) {

549
					this.addDrawCall( 0, indices.length );
550

D
dubejf 已提交
551 552 553
				}

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

D
dubejf 已提交
555 556 557
					var start = this.drawcalls[ j ].start;
					var count = this.drawcalls[ j ].count;
					var index = this.drawcalls[ j ].index;
558

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

G
gero3 已提交
561
						vA = ( index + indices[ i ] ) * 3;
M
Mr.doob 已提交
562 563
						vB = ( index + indices[ i + 1 ] ) * 3;
						vC = ( index + indices[ i + 2 ] ) * 3;
564

M
Mr.doob 已提交
565 566 567
						pA.fromArray( positions, vA );
						pB.fromArray( positions, vB );
						pC.fromArray( positions, vC );
568

569 570 571
						cb.subVectors( pC, pB );
						ab.subVectors( pA, pB );
						cb.cross( ab );
572

G
gero3 已提交
573
						normals[ vA ] += cb.x;
M
Mr.doob 已提交
574 575
						normals[ vA + 1 ] += cb.y;
						normals[ vA + 2 ] += cb.z;
576

G
gero3 已提交
577
						normals[ vB ] += cb.x;
M
Mr.doob 已提交
578 579
						normals[ vB + 1 ] += cb.y;
						normals[ vB + 2 ] += cb.z;
580

G
gero3 已提交
581
						normals[ vC ] += cb.x;
M
Mr.doob 已提交
582 583
						normals[ vC + 1 ] += cb.y;
						normals[ vC + 2 ] += cb.z;
584 585 586 587 588 589

					}

				}

			} else {
590

591 592 593
				// non-indexed elements (unconnected triangle soup)

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

M
Mr.doob 已提交
595 596 597
					pA.fromArray( positions, i );
					pB.fromArray( positions, i + 3 );
					pC.fromArray( positions, i + 6 );
598

599 600 601
					cb.subVectors( pC, pB );
					ab.subVectors( pA, pB );
					cb.cross( ab );
602

G
gero3 已提交
603
					normals[ i ] = cb.x;
604 605
					normals[ i + 1 ] = cb.y;
					normals[ i + 2 ] = cb.z;
606

607 608 609
					normals[ i + 3 ] = cb.x;
					normals[ i + 4 ] = cb.y;
					normals[ i + 5 ] = cb.z;
610

611 612 613
					normals[ i + 6 ] = cb.x;
					normals[ i + 7 ] = cb.y;
					normals[ i + 8 ] = cb.z;
614 615 616 617 618

				}

			}

619
			this.normalizeNormals();
620

621
			attributes.normal.needsUpdate = true;
622

623
		}
624

625
	},
626

627 628 629 630 631
	computeTangents: function () {

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

632 633 634 635
		if ( this.attributes.index === undefined ||
			 this.attributes.position === undefined ||
			 this.attributes.normal === undefined ||
			 this.attributes.uv === undefined ) {
636

637
			console.warn( 'THREE.BufferGeometry: Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()' );
638 639 640 641
			return;

		}

642 643 644 645
		var indices = this.attributes.index.array;
		var positions = this.attributes.position.array;
		var normals = this.attributes.normal.array;
		var uvs = this.attributes.uv.array;
646 647 648

		var nVertices = positions.length / 3;

649
		if ( this.attributes.tangent === undefined ) {
650

651
			this.addAttribute( 'tangent', new THREE.BufferAttribute( new Float32Array( 4 * nVertices ), 4 ) );
652 653 654

		}

655
		var tangents = this.attributes.tangent.array;
656 657 658 659 660 661 662 663 664 665

		var tan1 = [], tan2 = [];

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

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

		}

M
Mr.doob 已提交
666 667 668
		var vA = new THREE.Vector3(),
			vB = new THREE.Vector3(),
			vC = new THREE.Vector3(),
669

M
Mr.doob 已提交
670 671 672
			uvA = new THREE.Vector2(),
			uvB = new THREE.Vector2(),
			uvC = new THREE.Vector2(),
673 674 675 676 677 678 679 680

			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 已提交
681 682 683
			vA.fromArray( positions, a * 3 );
			vB.fromArray( positions, b * 3 );
			vC.fromArray( positions, c * 3 );
684

M
Mr.doob 已提交
685 686 687
			uvA.fromArray( uvs, a * 2 );
			uvB.fromArray( uvs, b * 2 );
			uvC.fromArray( uvs, c * 2 );
688

M
Mr.doob 已提交
689 690
			x1 = vB.x - vA.x;
			x2 = vC.x - vA.x;
691

M
Mr.doob 已提交
692 693
			y1 = vB.y - vA.y;
			y2 = vC.y - vA.y;
694

M
Mr.doob 已提交
695 696
			z1 = vB.z - vA.z;
			z2 = vC.z - vA.z;
697

M
Mr.doob 已提交
698 699
			s1 = uvB.x - uvA.x;
			s2 = uvC.x - uvA.x;
700

M
Mr.doob 已提交
701 702
			t1 = uvB.y - uvA.y;
			t2 = uvC.y - uvA.y;
703 704 705

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

706 707 708 709 710 711 712 713 714 715 716
			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
			);
717

718 719 720
			tan1[ a ].add( sdir );
			tan1[ b ].add( sdir );
			tan1[ c ].add( sdir );
721

722 723 724
			tan2[ a ].add( tdir );
			tan2[ b ].add( tdir );
			tan2[ c ].add( tdir );
725 726 727 728 729 730 731

		}

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

732
		if ( this.drawcalls.length === 0 ) {
733

734
			this.addDrawCall( 0, indices.length );
735

736 737 738 739 740 741 742 743 744
		}

		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;
745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763

			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 已提交
764
			n.fromArray( normals, v * 3 );
765 766 767 768 769 770 771
			n2.copy( n );

			t = tan1[ v ];

			// Gram-Schmidt orthogonalize

			tmp.copy( t );
772
			tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize();
773 774 775

			// Calculate handedness

776
			tmp2.crossVectors( n2, t );
777
			test = tmp2.dot( tan2[ v ] );
778
			w = ( test < 0.0 ) ? - 1.0 : 1.0;
779

G
gero3 已提交
780
			tangents[ v * 4 ] = tmp.x;
781 782 783 784 785 786
			tangents[ v * 4 + 1 ] = tmp.y;
			tangents[ v * 4 + 2 ] = tmp.z;
			tangents[ v * 4 + 3 ] = w;

		}

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

789 790 791
			var start = drawcalls[ j ].start;
			var count = drawcalls[ j ].count;
			var index = drawcalls[ j ].index;
792 793 794 795 796 797 798 799 800 801 802 803 804 805 806

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

			}

		}

807 808
	},

809
	/*
M
Mr.doob 已提交
810 811 812
	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.
813
	size - Defaults to 65535 or 4294967296 if extension OES_element_index_uint supported, but allows for larger or smaller chunks.
814
	*/
M
Mr.doob 已提交
815
	computeOffsets: function ( size ) {
816

817
		if ( size === undefined ) size = THREE.BufferGeometry.MaxIndex;
818

819 820
		var indices = this.attributes.index.array;
		var vertices = this.attributes.position.array;
821

822
		var facesCount = ( indices.length / 3 );
823

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

826
		/*
827 828 829
		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.");
830 831
		*/

832 833
		var sortedIndices = new UintArray( indices.length );

834 835 836
		var indexPtr = 0;
		var vertexPtr = 0;

G
gero3 已提交
837
		var tmpOffsets = [ { start: 0, count: 0, index: 0 } ];
D
dubejf 已提交
838
		var offset = tmpOffsets[ 0 ];
839 840 841

		var duplicatedVertices = 0;
		var newVerticeMaps = 0;
842
		var faceVertices = new Int32Array( 6 );
843 844
		var vertexMap = new Int32Array( vertices.length );
		var revVertexMap = new Int32Array( vertices.length );
G
gero3 已提交
845 846 847 848 849
		for ( var j = 0; j < vertices.length; j ++ ) {

			vertexMap[ j ] = - 1; revVertexMap[ j ] = - 1;

		}
850 851 852

		/*
			Traverse every face and reorder vertices in the proper offsets of 65k.
853
			We can have more than 'size' entries in the index buffer per offset, but only reference 'size' values.
854
		*/
855
		for ( var findex = 0; findex < facesCount; findex ++ ) {
G
gero3 已提交
856

857 858
			newVerticeMaps = 0;

859
			for ( var vo = 0; vo < 3; vo ++ ) {
G
gero3 已提交
860

861
				var vid = indices[ findex * 3 + vo ];
F
Fabian Lange 已提交
862
				if ( vertexMap[ vid ] === - 1 ) {
G
gero3 已提交
863

D
dubejf 已提交
864
					//Unmapped vertex
865 866 867
					faceVertices[ vo * 2 ] = vid;
					faceVertices[ vo * 2 + 1 ] = - 1;
					newVerticeMaps ++;
G
gero3 已提交
868

869
				} else if ( vertexMap[ vid ] < offset.index ) {
G
gero3 已提交
870

871
					//Reused vertices from previous block (duplicate)
872 873 874
					faceVertices[ vo * 2 ] = vid;
					faceVertices[ vo * 2 + 1 ] = - 1;
					duplicatedVertices ++;
G
gero3 已提交
875

876
				} else {
G
gero3 已提交
877

D
dubejf 已提交
878
					//Reused vertex in the current block
879 880
					faceVertices[ vo * 2 ] = vid;
					faceVertices[ vo * 2 + 1 ] = vertexMap[ vid ];
G
gero3 已提交
881

882
				}
G
gero3 已提交
883

884 885 886
			}

			var faceMax = vertexPtr + newVerticeMaps;
887
			if ( faceMax > ( offset.index + size ) ) {
G
gero3 已提交
888 889

				var new_offset = { start: indexPtr, count: 0, index: vertexPtr };
D
dubejf 已提交
890
				tmpOffsets.push( new_offset );
891 892 893
				offset = new_offset;

				//Re-evaluate reused vertices in light of new offset.
894
				for ( var v = 0; v < 6; v += 2 ) {
G
gero3 已提交
895

896 897 898
					var new_vid = faceVertices[ v + 1 ];
					if ( new_vid > - 1 && new_vid < offset.index )
						faceVertices[ v + 1 ] = - 1;
G
gero3 已提交
899

900
				}
G
gero3 已提交
901

902 903 904
			}

			//Reindex the face.
905
			for ( var v = 0; v < 6; v += 2 ) {
G
gero3 已提交
906

907 908
				var vid = faceVertices[ v ];
				var new_vid = faceVertices[ v + 1 ];
909

910 911
				if ( new_vid === - 1 )
					new_vid = vertexPtr ++;
912

913 914 915 916
				vertexMap[ vid ] = new_vid;
				revVertexMap[ new_vid ] = vid;
				sortedIndices[ indexPtr ++ ] = new_vid - offset.index; //XXX overflows at 16bit
				offset.count ++;
G
gero3 已提交
917

918
			}
G
gero3 已提交
919

920 921
		}

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

		this.clearDrawCalls();
926

D
dubejf 已提交
927 928
		for ( var i = 0; i < tmpOffsets.length; i ++ ) {

929 930
			var tmpOffset = tmpOffsets[ i ];
			this.addDrawCall( tmpOffset.start, tmpOffset.count, tmpOffset.index );
D
dubejf 已提交
931 932

		}
933 934 935

		/*
		var orderTime = Date.now();
936 937 938
		console.log("Reorder time: "+(orderTime-s)+"ms");
		console.log("Duplicated "+duplicatedVertices+" vertices.");
		console.log("Compute Buffers time: "+(Date.now()-s)+"ms");
D
dubejf 已提交
939
		console.log("Draw tmpOffsets: "+tmpOffsets.length);
940 941 942 943
		*/

	},

944 945 946 947
	merge: function ( geometry, offset ) {

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

948
			console.error( 'THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry );
949 950 951 952 953 954 955 956 957 958 959
			return;

		}

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

		var attributes = this.attributes;

		for ( var key in attributes ) {

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

961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977
			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;
978 979 980 981 982

	},

	normalizeNormals: function () {

983
		var normals = this.attributes.normal.array;
984 985 986 987 988 989 990 991 992 993 994

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

G
gero3 已提交
995
			normals[ i ] *= n;
996 997 998 999 1000 1001 1002
			normals[ i + 1 ] *= n;
			normals[ i + 2 ] *= n;

		}

	},

1003 1004 1005 1006 1007
	/*
		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 已提交
1008
		vertexCount - Amount of total vertices considered in this reordering (in case you want to grow the vertex stack).
1009
	*/
1010
	reorderBuffers: function ( indexBuffer, indexMap, vertexCount ) {
1011 1012 1013

		/* Create a copy of all attributes for reordering. */
		var sortedAttributes = {};
1014
		for ( var attr in this.attributes ) {
G
gero3 已提交
1015

F
Fabian Lange 已提交
1016
			if ( attr === 'index' )
1017
				continue;
1018
			var sourceArray = this.attributes[ attr ].array;
1019
			sortedAttributes[ attr ] = new sourceArray.constructor( this.attributes[ attr ].itemSize * vertexCount );
G
gero3 已提交
1020

1021 1022 1023
		}

		/* Move attribute positions based on the new index map */
1024
		for ( var new_vid = 0; new_vid < vertexCount; new_vid ++ ) {
G
gero3 已提交
1025

1026
			var vid = indexMap[ new_vid ];
1027
			for ( var attr in this.attributes ) {
G
gero3 已提交
1028

F
Fabian Lange 已提交
1029
				if ( attr === 'index' )
1030
					continue;
1031 1032 1033 1034
				var attrArray = this.attributes[ attr ].array;
				var attrSize = this.attributes[ attr ].itemSize;
				var sortedAttr = sortedAttributes[ attr ];
				for ( var k = 0; k < attrSize; k ++ )
1035
					sortedAttr[ new_vid * attrSize + k ] = attrArray[ vid * attrSize + k ];
G
gero3 已提交
1036

1037
			}
G
gero3 已提交
1038

1039 1040 1041
		}

		/* Carry the new sorted buffers locally */
1042
		this.attributes[ 'index' ].array = indexBuffer;
1043
		for ( var attr in this.attributes ) {
G
gero3 已提交
1044

F
Fabian Lange 已提交
1045
			if ( attr === 'index' )
1046
				continue;
1047 1048
			this.attributes[ attr ].array = sortedAttributes[ attr ];
			this.attributes[ attr ].numItems = this.attributes[ attr ].itemSize * vertexCount;
G
gero3 已提交
1049

1050
		}
G
gero3 已提交
1051

1052 1053
	},

1054
	toJSON: function () {
1055

1056 1057 1058 1059 1060 1061
		var data = {
			metadata: {
				version: 4.4,
				type: 'BufferGeometry',
				generator: 'BufferGeometry.toJSON'
			}
B
brason 已提交
1062
		};
1063

1064
		// standard BufferGeometry serialization
1065

1066
		data.uuid = this.uuid;
M
Mr.doob 已提交
1067
		data.type = this.type;
1068
		if ( this.name !== '' ) data.name = this.name;
1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084

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

1086
		var attributes = this.attributes;
1087
		var drawcalls = this.drawcalls;
1088 1089 1090 1091 1092 1093
		var boundingSphere = this.boundingSphere;

		for ( var key in attributes ) {

			var attribute = attributes[ key ];

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

1096
			data.data.attributes[ key ] = {
1097 1098 1099
				itemSize: attribute.itemSize,
				type: attribute.array.constructor.name,
				array: array
1100
			};
1101 1102 1103

		}

1104
		if ( drawcalls.length > 0 ) {
1105

1106
			data.data.drawcalls = JSON.parse( JSON.stringify( drawcalls ) );
1107 1108 1109 1110 1111

		}

		if ( boundingSphere !== null ) {

1112
			data.data.boundingSphere = {
1113 1114
				center: boundingSphere.center.toArray(),
				radius: boundingSphere.radius
1115
			};
1116 1117 1118

		}

1119
		return data;
1120 1121 1122

	},

M
Mr.doob 已提交
1123
	clone: function () {
O
ohmed 已提交
1124 1125

		var geometry = new THREE.BufferGeometry();
D
dubejf 已提交
1126
		return geometry.copy( this );
O
ohmed 已提交
1127

D
dubejf 已提交
1128 1129 1130
	},

	copy: function ( source ) {
O
ohmed 已提交
1131

1132
		for ( var attr in source.attributes ) {
O
ohmed 已提交
1133

1134 1135
			var sourceAttr = source.attributes[ attr ];
			this.addAttribute( attr, sourceAttr.clone() );
O
ohmed 已提交
1136 1137 1138

		}

1139
		for ( var i = 0, il = source.drawcalls.length; i < il; i ++ ) {
O
ohmed 已提交
1140

1141
			var offset = source.drawcalls[ i ];
O
ohmed 已提交
1142

1143
			this.addDrawCall( offset.start, offset.count, offset.index );
O
ohmed 已提交
1144

O
ohmed 已提交
1145
		}
O
ohmed 已提交
1146

1147
		return this;
O
ohmed 已提交
1148 1149 1150

	},

1151
	dispose: function () {
1152

1153
		this.dispatchEvent( { type: 'dispose' } );
1154

1155
	}
1156 1157

};
M
Mr.doob 已提交
1158 1159

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

1161
THREE.BufferGeometry.MaxIndex = 65535;