BufferGeometry.js 23.8 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
				var directgeometry = geometry.__directGeometry;
178

M
Mr.doob 已提交
179
				// morphs
180

M
Mr.doob 已提交
181
				if ( object.morphTargetInfluences !== undefined ) {
182

M
Mr.doob 已提交
183
					var morphTargets = directgeometry.morphTargets;
184 185 186 187 188

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

						var morphTarget = morphTargets[ i ];

M
Mr.doob 已提交
189
						var attribute = new THREE.Float32Attribute( morphTarget.length * 3, 3 );
190

M
Mr.doob 已提交
191
						this.morphAttributes.push( attribute.copyVector3sArray( morphTarget ) );
192 193 194

					}

M
Mr.doob 已提交
195
					// TODO normals, colors
196

M
Mr.doob 已提交
197
				}
M
Mr.doob 已提交
198

M
Mr.doob 已提交
199 200 201 202 203 204 205 206 207 208 209 210
				// skinning

				if ( object instanceof THREE.SkinnedMesh ) {

					var skinIndices = new THREE.Float32Attribute( directgeometry.skinIndices.length * 4, 4 );
					var skinWeights = new THREE.Float32Attribute( directgeometry.skinWeights.length * 4, 4 );

					this.addAttribute( 'skinIndex', skinIndices.copyVector4sArray( directgeometry.skinIndices ) );
					this.addAttribute( 'skinWeight', skinWeights.copyVector4sArray( directgeometry.skinWeights ) );

				}

M
Mr.doob 已提交
211
			}
212 213 214 215 216 217 218

		}

		return this;

	},

219 220
	updateFromObject: function ( object ) {

M
Mr.doob 已提交
221
		var geometry = object.geometry;
222

M
Mr.doob 已提交
223
		if ( object instanceof THREE.Mesh ) {
224

M
Mr.doob 已提交
225
			var direct = geometry.__directGeometry;
226

M
Mr.doob 已提交
227 228 229 230 231 232 233 234 235
			direct.verticesNeedUpdate = geometry.verticesNeedUpdate;
			direct.normalsNeedUpdate = geometry.normalsNeedUpdate;
			direct.colorsNeedUpdate = geometry.colorsNeedUpdate;
			direct.uvsNeedUpdate = geometry.uvsNeedUpdate;

			geometry.verticesNeedUpdate = false;
			geometry.normalsNeedUpdate = false;
			geometry.colorsNeedUpdate = false;
			geometry.uvsNeedUpdate = false;
236

M
Mr.doob 已提交
237
			geometry = direct;
238 239

		}
240

M
Mr.doob 已提交
241
		if ( geometry.verticesNeedUpdate === true ) {
242

M
Mr.doob 已提交
243
			var attribute = this.attributes.position;
244

M
Mr.doob 已提交
245
			if ( attribute !== undefined ) {
246

M
Mr.doob 已提交
247 248
				attribute.copyVector3sArray( geometry.vertices );
				attribute.needsUpdate = true;
249 250 251

			}

M
Mr.doob 已提交
252
			geometry.verticesNeedUpdate = false;
253

M
Mr.doob 已提交
254
		}
255

256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
		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 已提交
271
		if ( geometry.colorsNeedUpdate === true ) {
272

M
Mr.doob 已提交
273
			var attribute = this.attributes.color;
274

M
Mr.doob 已提交
275
			if ( attribute !== undefined ) {
276

M
Mr.doob 已提交
277 278
				attribute.copyColorsArray( geometry.colors );
				attribute.needsUpdate = true;
279 280 281

			}

M
Mr.doob 已提交
282 283
			geometry.colorsNeedUpdate = false;

284
		}
285 286

		return this;
287 288 289

	},

290
	fromGeometry: function ( geometry, material ) {
291

292 293 294
		geometry.__directGeometry = new THREE.DirectGeometry().fromGeometry( geometry, material );

		return this.fromDirectGeometry( geometry.__directGeometry );
295

296
	},
297

298
	fromDirectGeometry: function ( geometry ) {
299

M
Mr.doob 已提交
300 301 302 303 304 305 306
		if ( geometry.indices.length > 0 ) {

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

		}

307
		if ( geometry.vertices.length > 0 ) {
308

309 310
			var positions = new Float32Array( geometry.vertices.length * 3 );
			this.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ).copyVector3sArray( geometry.vertices ) );
311

312 313
		}

314 315 316 317 318 319 320 321
		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 已提交
322

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

326 327 328 329 330 331 332 333
		}

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

335 336 337 338 339 340 341 342 343 344 345
		if ( geometry.boundingSphere !== null ) {

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

		}

		if ( geometry.boundingBox !== null ) {

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

		}
M
Mr.doob 已提交
346 347 348 349 350

		return this;

	},

351 352
	computeBoundingBox: function () {

353
		var vector = new THREE.Vector3();
354

355
		return function () {
356

357
			if ( this.boundingBox === null ) {
358

359
				this.boundingBox = new THREE.Box3();
360

361 362
			}

363
			var positions = this.attributes.position.array;
364

365
			if ( positions ) {
366

367 368
				var bb = this.boundingBox;
				bb.makeEmpty();
369

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

372
					vector.fromArray( positions, i );
373
					bb.expandByPoint( vector );
374 375 376 377 378

				}

			}

379
			if ( positions === undefined || positions.length === 0 ) {
380

381 382
				this.boundingBox.min.set( 0, 0, 0 );
				this.boundingBox.max.set( 0, 0, 0 );
383

384
			}
385

386
			if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) {
387

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

390
			}
391

G
Greg French 已提交
392
		};
393

394
	}(),
395 396 397

	computeBoundingSphere: function () {

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

401
		return function () {
402

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

405
				this.boundingSphere = new THREE.Sphere();
406

407
			}
408

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

411
			if ( positions ) {
412

413 414
				box.makeEmpty();

415
				var center = this.boundingSphere.center;
416

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

419
					vector.fromArray( positions, i );
J
Jan Wrobel 已提交
420
					box.expandByPoint( vector );
421 422 423 424 425

				}

				box.center( center );

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

429 430
				var maxRadiusSq = 0;

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

433
					vector.fromArray( positions, i );
434
					maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) );
435

436 437 438 439
				}

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

440 441
				if ( isNaN( this.boundingSphere.radius ) ) {

442
					console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this );
443 444 445

				}

446
			}
447

G
Greg French 已提交
448
		};
449

450
	}(),
451

452 453 454 455 456 457
	computeFaceNormals: function () {

		// backwards compatibility

	},

458 459
	computeVertexNormals: function () {

460
		var attributes = this.attributes;
461

462
		if ( attributes.position ) {
463

464
			var positions = attributes.position.array;
465

466
			if ( attributes.normal === undefined ) {
467

468
				this.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( positions.length ), 3 ) );
469 470 471 472 473

			} else {

				// reset existing normals to zero

474 475 476
				var normals = attributes.normal.array;

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

478
					normals[ i ] = 0;
479 480 481 482 483

				}

			}

484
			var normals = attributes.normal.array;
485

M
Mr.doob 已提交
486
			var vA, vB, vC,
487 488 489 490 491 492 493 494

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

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

495 496
			// indexed elements

497
			if ( attributes.index ) {
498

499
				var indices = attributes.index.array;
500

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

503
				for ( var j = 0, jl = offsets.length; j < jl; ++ j ) {
504 505 506 507 508

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

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

M
Mr.doob 已提交
511 512 513
						vA = ( index + indices[ i     ] ) * 3;
						vB = ( index + indices[ i + 1 ] ) * 3;
						vC = ( index + indices[ i + 2 ] ) * 3;
514

M
Mr.doob 已提交
515 516 517
						pA.fromArray( positions, vA );
						pB.fromArray( positions, vB );
						pC.fromArray( positions, vC );
518

519 520 521
						cb.subVectors( pC, pB );
						ab.subVectors( pA, pB );
						cb.cross( ab );
522

M
Mr.doob 已提交
523 524 525
						normals[ vA     ] += cb.x;
						normals[ vA + 1 ] += cb.y;
						normals[ vA + 2 ] += cb.z;
526

M
Mr.doob 已提交
527 528 529
						normals[ vB     ] += cb.x;
						normals[ vB + 1 ] += cb.y;
						normals[ vB + 2 ] += cb.z;
530

M
Mr.doob 已提交
531 532 533
						normals[ vC     ] += cb.x;
						normals[ vC + 1 ] += cb.y;
						normals[ vC + 2 ] += cb.z;
534 535 536 537 538 539

					}

				}

			} else {
540

541 542 543
				// non-indexed elements (unconnected triangle soup)

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

M
Mr.doob 已提交
545 546 547
					pA.fromArray( positions, i );
					pB.fromArray( positions, i + 3 );
					pC.fromArray( positions, i + 6 );
548

549 550 551
					cb.subVectors( pC, pB );
					ab.subVectors( pA, pB );
					cb.cross( ab );
552

M
Mr.doob 已提交
553
					normals[ i     ] = cb.x;
554 555
					normals[ i + 1 ] = cb.y;
					normals[ i + 2 ] = cb.z;
556

557 558 559
					normals[ i + 3 ] = cb.x;
					normals[ i + 4 ] = cb.y;
					normals[ i + 5 ] = cb.z;
560

561 562 563
					normals[ i + 6 ] = cb.x;
					normals[ i + 7 ] = cb.y;
					normals[ i + 8 ] = cb.z;
564 565 566 567 568

				}

			}

569
			this.normalizeNormals();
570

571
			attributes.normal.needsUpdate = true;
572

573
		}
574

575
	},
576

577 578 579 580 581
	computeTangents: function () {

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

582 583 584 585
		if ( this.attributes.index === undefined ||
			 this.attributes.position === undefined ||
			 this.attributes.normal === undefined ||
			 this.attributes.uv === undefined ) {
586

587
			console.warn( 'THREE.BufferGeometry: Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()' );
588 589 590 591
			return;

		}

592 593 594 595
		var indices = this.attributes.index.array;
		var positions = this.attributes.position.array;
		var normals = this.attributes.normal.array;
		var uvs = this.attributes.uv.array;
596 597 598

		var nVertices = positions.length / 3;

599
		if ( this.attributes.tangent === undefined ) {
600

601
			this.addAttribute( 'tangent', new THREE.BufferAttribute( new Float32Array( 4 * nVertices ), 4 ) );
602 603 604

		}

605
		var tangents = this.attributes.tangent.array;
606 607 608 609 610 611 612 613 614 615

		var tan1 = [], tan2 = [];

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

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

		}

M
Mr.doob 已提交
616 617 618
		var vA = new THREE.Vector3(),
			vB = new THREE.Vector3(),
			vC = new THREE.Vector3(),
619

M
Mr.doob 已提交
620 621 622
			uvA = new THREE.Vector2(),
			uvB = new THREE.Vector2(),
			uvC = new THREE.Vector2(),
623 624 625 626 627 628 629 630

			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 已提交
631 632 633
			vA.fromArray( positions, a * 3 );
			vB.fromArray( positions, b * 3 );
			vC.fromArray( positions, c * 3 );
634

M
Mr.doob 已提交
635 636 637
			uvA.fromArray( uvs, a * 2 );
			uvB.fromArray( uvs, b * 2 );
			uvC.fromArray( uvs, c * 2 );
638

M
Mr.doob 已提交
639 640
			x1 = vB.x - vA.x;
			x2 = vC.x - vA.x;
641

M
Mr.doob 已提交
642 643
			y1 = vB.y - vA.y;
			y2 = vC.y - vA.y;
644

M
Mr.doob 已提交
645 646
			z1 = vB.z - vA.z;
			z2 = vC.z - vA.z;
647

M
Mr.doob 已提交
648 649
			s1 = uvB.x - uvA.x;
			s2 = uvC.x - uvA.x;
650

M
Mr.doob 已提交
651 652
			t1 = uvB.y - uvA.y;
			t2 = uvC.y - uvA.y;
653 654 655

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

656 657 658 659 660 661 662 663 664 665 666
			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
			);
667

668 669 670
			tan1[ a ].add( sdir );
			tan1[ b ].add( sdir );
			tan1[ c ].add( sdir );
671

672 673 674
			tan2[ a ].add( tdir );
			tan2[ b ].add( tdir );
			tan2[ c ].add( tdir );
675 676 677 678 679 680 681

		}

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

682
		if ( this.drawcalls.length === 0 ) {
683

684
			this.addDrawCall( 0, indices.length, 0 );
685

686 687 688 689 690 691 692 693 694
		}

		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;
695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713

			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 已提交
714
			n.fromArray( normals, v * 3 );
715 716 717 718 719 720 721
			n2.copy( n );

			t = tan1[ v ];

			// Gram-Schmidt orthogonalize

			tmp.copy( t );
722
			tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize();
723 724 725

			// Calculate handedness

726
			tmp2.crossVectors( n2, t );
727
			test = tmp2.dot( tan2[ v ] );
728
			w = ( test < 0.0 ) ? - 1.0 : 1.0;
729

M
Mr.doob 已提交
730
			tangents[ v * 4     ] = tmp.x;
731 732 733 734 735 736
			tangents[ v * 4 + 1 ] = tmp.y;
			tangents[ v * 4 + 2 ] = tmp.z;
			tangents[ v * 4 + 3 ] = w;

		}

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

739 740 741
			var start = drawcalls[ j ].start;
			var count = drawcalls[ j ].count;
			var index = drawcalls[ j ].index;
742 743 744 745 746 747 748 749 750 751 752 753 754 755 756

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

			}

		}

757 758
	},

759
	/*
M
Mr.doob 已提交
760 761 762
	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.
763
	size - Defaults to 65535 or 4294967296 if extension OES_element_index_uint supported, but allows for larger or smaller chunks.
764
	*/
M
Mr.doob 已提交
765
	computeOffsets: function ( size ) {
766

767
		if ( size === undefined ) size = THREE.BufferGeometry.MaxIndex;
768

769 770
		var indices = this.attributes.index.array;
		var vertices = this.attributes.position.array;
771

772
		var facesCount = ( indices.length / 3 );
773

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

776
		/*
777 778 779
		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.");
780 781
		*/

782 783
		var sortedIndices = new UintArray( indices.length );

784 785 786 787
		var indexPtr = 0;
		var vertexPtr = 0;

		var offsets = [ { start:0, count:0, index:0 } ];
788
		var offset = offsets[ 0 ];
789 790 791

		var duplicatedVertices = 0;
		var newVerticeMaps = 0;
792
		var faceVertices = new Int32Array( 6 );
793 794
		var vertexMap = new Int32Array( vertices.length );
		var revVertexMap = new Int32Array( vertices.length );
795
		for ( var j = 0; j < vertices.length; j ++ ) { vertexMap[ j ] = - 1; revVertexMap[ j ] = - 1; }
796 797 798

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

804 805
			for ( var vo = 0; vo < 3; vo ++ ) {
				var vid = indices[ findex * 3 + vo ];
F
Fabian Lange 已提交
806
				if ( vertexMap[ vid ] === - 1 ) {
807
					//Unmapped vertice
808 809 810 811
					faceVertices[ vo * 2 ] = vid;
					faceVertices[ vo * 2 + 1 ] = - 1;
					newVerticeMaps ++;
				} else if ( vertexMap[ vid ] < offset.index ) {
812
					//Reused vertices from previous block (duplicate)
813 814 815
					faceVertices[ vo * 2 ] = vid;
					faceVertices[ vo * 2 + 1 ] = - 1;
					duplicatedVertices ++;
816 817
				} else {
					//Reused vertice in the current block
818 819
					faceVertices[ vo * 2 ] = vid;
					faceVertices[ vo * 2 + 1 ] = vertexMap[ vid ];
820 821 822 823
				}
			}

			var faceMax = vertexPtr + newVerticeMaps;
824
			if ( faceMax > ( offset.index + size ) ) {
825
				var new_offset = { start:indexPtr, count:0, index:vertexPtr };
826
				offsets.push( new_offset );
827 828 829
				offset = new_offset;

				//Re-evaluate reused vertices in light of new offset.
830 831 832 833
				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;
834 835 836 837
				}
			}

			//Reindex the face.
838 839 840
			for ( var v = 0; v < 6; v += 2 ) {
				var vid = faceVertices[ v ];
				var new_vid = faceVertices[ v + 1 ];
841

842 843
				if ( new_vid === - 1 )
					new_vid = vertexPtr ++;
844

845 846 847 848
				vertexMap[ vid ] = new_vid;
				revVertexMap[ new_vid ] = vid;
				sortedIndices[ indexPtr ++ ] = new_vid - offset.index; //XXX overflows at 16bit
				offset.count ++;
849 850 851 852
			}
		}

		/* Move all attribute values to map to the new computed indices , also expand the vertice stack to match our new vertexPtr. */
853
		this.reorderBuffers( sortedIndices, revVertexMap, vertexPtr );
854 855
		this.offsets = offsets; // TODO: Deprecate
		this.drawcalls = offsets;
856 857 858

		/*
		var orderTime = Date.now();
859 860 861 862
		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);
863 864 865
		*/

		return offsets;
866

867 868
	},

869 870 871 872
	merge: function ( geometry, offset ) {

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

873
			console.error( 'THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry );
874 875 876 877 878 879 880 881 882 883 884
			return;

		}

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

		var attributes = this.attributes;

		for ( var key in attributes ) {

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

886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902
			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;
903 904 905 906 907

	},

	normalizeNormals: function () {

908
		var normals = this.attributes.normal.array;
909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927

		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;

		}

	},

928 929 930 931 932 933 934
	/*
		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).
	*/
935
	reorderBuffers: function ( indexBuffer, indexMap, vertexCount ) {
936 937 938

		/* Create a copy of all attributes for reordering. */
		var sortedAttributes = {};
939
		for ( var attr in this.attributes ) {
F
Fabian Lange 已提交
940
			if ( attr === 'index' )
941
				continue;
942
			var sourceArray = this.attributes[ attr ].array;
943
			sortedAttributes[ attr ] = new sourceArray.constructor( this.attributes[ attr ].itemSize * vertexCount );
944 945 946
		}

		/* Move attribute positions based on the new index map */
947 948
		for ( var new_vid = 0; new_vid < vertexCount; new_vid ++ ) {
			var vid = indexMap[ new_vid ];
949
			for ( var attr in this.attributes ) {
F
Fabian Lange 已提交
950
				if ( attr === 'index' )
951
					continue;
952 953 954 955
				var attrArray = this.attributes[ attr ].array;
				var attrSize = this.attributes[ attr ].itemSize;
				var sortedAttr = sortedAttributes[ attr ];
				for ( var k = 0; k < attrSize; k ++ )
956 957 958 959 960
					sortedAttr[ new_vid * attrSize + k ] = attrArray[ vid * attrSize + k ];
			}
		}

		/* Carry the new sorted buffers locally */
961
		this.attributes[ 'index' ].array = indexBuffer;
962
		for ( var attr in this.attributes ) {
F
Fabian Lange 已提交
963
			if ( attr === 'index' )
964
				continue;
965 966
			this.attributes[ attr ].array = sortedAttributes[ attr ];
			this.attributes[ attr ].numItems = this.attributes[ attr ].itemSize * vertexCount;
967 968 969
		}
	},

970
	toJSON: function () {
971

972 973 974 975 976 977
		var data = {
			metadata: {
				version: 4.4,
				type: 'BufferGeometry',
				generator: 'BufferGeometry.toJSON'
			}
B
brason 已提交
978
		};
979

980
		// standard BufferGeometry serialization
981

982
		data.uuid = this.uuid;
M
Mr.doob 已提交
983
		data.type = this.type;
984
		if ( this.name !== '' ) data.name = this.name;
985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000

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

1002
		var attributes = this.attributes;
1003 1004 1005 1006 1007 1008 1009
		var offsets = this.offsets;
		var boundingSphere = this.boundingSphere;

		for ( var key in attributes ) {

			var attribute = attributes[ key ];

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

1012
			data.data.attributes[ key ] = {
1013 1014 1015 1016 1017 1018 1019 1020 1021
				itemSize: attribute.itemSize,
				type: attribute.array.constructor.name,
				array: array
			}

		}

		if ( offsets.length > 0 ) {

1022
			data.data.offsets = JSON.parse( JSON.stringify( offsets ) );
1023 1024 1025 1026 1027

		}

		if ( boundingSphere !== null ) {

1028
			data.data.boundingSphere = {
1029 1030 1031 1032 1033 1034
				center: boundingSphere.center.toArray(),
				radius: boundingSphere.radius
			}

		}

1035
		return data;
1036 1037 1038

	},

M
Mr.doob 已提交
1039
	clone: function () {
O
ohmed 已提交
1040 1041 1042 1043 1044

		var geometry = new THREE.BufferGeometry();

		for ( var attr in this.attributes ) {

M
Mr.doob 已提交
1045
			var sourceAttr = this.attributes[ attr ];
D
dubejf 已提交
1046
			geometry.addAttribute( attr, sourceAttr.clone() );
O
ohmed 已提交
1047 1048 1049

		}

O
ohmed 已提交
1050
		for ( var i = 0, il = this.offsets.length; i < il; i ++ ) {
O
ohmed 已提交
1051 1052 1053

			var offset = this.offsets[ i ];

M
Mr.doob 已提交
1054
			geometry.offsets.push( {
O
ohmed 已提交
1055

O
ohmed 已提交
1056 1057 1058
				start: offset.start,
				index: offset.index,
				count: offset.count
O
ohmed 已提交
1059

M
Mr.doob 已提交
1060
			} );
O
ohmed 已提交
1061

O
ohmed 已提交
1062
		}
O
ohmed 已提交
1063 1064 1065 1066 1067

		return geometry;

	},

1068
	dispose: function () {
1069

1070
		this.dispatchEvent( { type: 'dispose' } );
1071

1072
	}
1073 1074

};
M
Mr.doob 已提交
1075 1076

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

1078
THREE.BufferGeometry.MaxIndex = 65535;