TransformControls.js 25.8 KB
Newer Older
A
Aleksandar Rodic 已提交
1 2 3 4
/**
 * @author arodic / https://github.com/arodic
 */

A
Aleksandar Rodic 已提交
5
 //"use strict";
A
Aleksandar Rodic 已提交
6

7
THREE.TransformControls = function ( camera, domElement ) {
A
Aleksandar Rodic 已提交
8

A
Aleksandar Rodic 已提交
9
	// TODO: Make non-uniform scale and rotate play nice in hierarchies
A
Aleksandar Rodic 已提交
10 11 12 13 14 15
	// TODO: ADD RXYZ contol

	this.camera = camera;
	this.domElement = ( domElement !== undefined ) ? domElement : document;

	this.active = false;
16
	this.mode = 'rotate';
A
Aleksandar Rodic 已提交
17 18
	this.space = 'world';
	this.scale = 1;
A
Aleksandar Rodic 已提交
19 20

	this.snapDist = null;
21 22 23
	this.modifierAxis = new THREE.Vector3( 1, 1, 1 );
	this.gizmo = new THREE.Object3D();

A
Aleksandar Rodic 已提交
24 25
	var scope = this;

26 27
	var changeEvent = { type: 'change' };

A
Aleksandar Rodic 已提交
28 29 30 31 32 33 34
	var showPickers = false; // debug

	var ray = new THREE.Raycaster();
	var projector = new THREE.Projector();
	var pointerVector = new THREE.Vector3();

	var point = new THREE.Vector3();
A
Aleksandar Rodic 已提交
35 36
	var offset = new THREE.Vector3();

A
Aleksandar Rodic 已提交
37 38
	var rotation = new THREE.Vector3();
	var offsetRotation = new THREE.Vector3();
A
Aleksandar Rodic 已提交
39 40
	var scale = 1;

A
Aleksandar Rodic 已提交
41
	var lookAtMatrix = new THREE.Matrix4();
A
Aleksandar Rodic 已提交
42
	var eye = new THREE.Vector3()
43

A
Aleksandar Rodic 已提交
44 45 46 47 48 49 50 51 52 53 54
	var tempMatrix = new THREE.Matrix4();
	var tempVector = new THREE.Vector3();
	var tempQuaternion = new THREE.Quaternion();
	var unitX = new THREE.Vector3( 1, 0, 0 );
	var unitY = new THREE.Vector3( 0, 1, 0 );
	var unitZ = new THREE.Vector3( 0, 0, 1 );

	var quaternionXYZ = new THREE.Quaternion();
	var quaternionX = new THREE.Quaternion();
	var quaternionY = new THREE.Quaternion();
	var quaternionZ = new THREE.Quaternion();
A
Aleksandar Rodic 已提交
55
	var quaternionE = new THREE.Quaternion();
A
Aleksandar Rodic 已提交
56 57 58

	var oldPosition = new THREE.Vector3();
	var oldScale = new THREE.Vector3();
A
Aleksandar Rodic 已提交
59 60 61 62
	var oldRotationMatrix = new THREE.Matrix4();

	var parentRotationMatrix  = new THREE.Matrix4();
	var parentScale = new THREE.Vector3();
A
Aleksandar Rodic 已提交
63

A
Aleksandar Rodic 已提交
64 65 66
	var worldPosition = new THREE.Vector3();
	var worldRotation = new THREE.Vector3();
	var worldRotationMatrix  = new THREE.Matrix4();
A
Aleksandar Rodic 已提交
67 68 69 70 71 72
	var camPosition = new THREE.Vector3();
	var camRotation = new THREE.Vector3();

	var displayAxes = {};
	var pickerAxes = {};
	var intersectionPlanes = {};
A
Aleksandar Rodic 已提交
73
	var intersectionPlaneList = ['XY','YZ','XZ','XYZE']; // E
A
Aleksandar Rodic 已提交
74
	var currentPlane = 'XY';
A
Aleksandar Rodic 已提交
75
	var intersect, planeIntersect;
A
Aleksandar Rodic 已提交
76 77 78

	var object, name;

79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
	// intersection planes
	{

		var planes = new THREE.Object3D();
		this.gizmo.add(planes);

		for ( var i in intersectionPlaneList ){

			intersectionPlanes[intersectionPlaneList[i]] = new THREE.Mesh( new THREE.PlaneGeometry( 500, 500 ) );
			intersectionPlanes[intersectionPlaneList[i]].material.side = THREE.DoubleSide;
			intersectionPlanes[intersectionPlaneList[i]].visible = false;
			planes.add(intersectionPlanes[intersectionPlaneList[i]]);

		}

		intersectionPlanes['YZ'].rotation.set( 0, Math.PI/2, 0 );
		intersectionPlanes['XZ'].rotation.set( -Math.PI/2, 0, 0 );
		bakeTransformations(intersectionPlanes['YZ']);
		bakeTransformations(intersectionPlanes['XZ']);

	}

A
Aleksandar Rodic 已提交
101 102 103 104 105 106 107 108 109
	// gizmo geometry
	{

		displayAxes["translate"] = new THREE.Object3D();
		displayAxes["rotate"] = new THREE.Object3D();
		displayAxes["scale"] = new THREE.Object3D();
		this.gizmo.add( displayAxes["translate"] );
		this.gizmo.add( displayAxes["rotate"] );
		this.gizmo.add( displayAxes["scale"] );
110

A
Aleksandar Rodic 已提交
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
		pickerAxes["translate"] = new THREE.Object3D();
		pickerAxes["rotate"] = new THREE.Object3D();
		pickerAxes["scale"] = new THREE.Object3D();
		this.gizmo.add( pickerAxes["translate"] );
		this.gizmo.add( pickerAxes["rotate"] );
		this.gizmo.add( pickerAxes["scale"] );

		var HandleMaterial = function ( color ) {
			var material = new THREE.MeshBasicMaterial();
			material.side = THREE.DoubleSide;
			material.transparent = true;
			material.depthTest = false;
			material.depthWrite = false;
			material.color.setRGB( color[0], color[1], color[2] );
			material.opacity = color[3];
			return material;
		}

		var LineMaterial = function ( color ) {
			var material = new THREE.LineBasicMaterial();
			material.transparent = true;
			material.depthTest = false;
			material.depthWrite = false;
			material.color.setRGB( color[0], color[1], color[2] );
			material.opacity = color[3];
			return material;
		}

		// materials by color
		var white = [1,1,1,0.2];
		var gray = [0.5,0.5,0.5,1];
		var red = [1,0,0,1];
		var green = [0,1,0,1];
		var blue = [0,0,1,1];
		var cyan = [0,1,1,0.2];
		var magenta = [1,0,1,0.2];
		var yellow = [1,1,0,0.2];

149
		var geometry, mesh;
A
Aleksandar Rodic 已提交
150

151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
		// Line axes

		var redColor = new THREE.Color( 0xff0000 );
		var greenColor = new THREE.Color( 0x00ff00 );
		var blueColor = new THREE.Color( 0x0000ff );

		geometry = new THREE.Geometry();
		geometry.vertices.push(
			new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 1, 0, 0 ),
			new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 1, 0 ),
			new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 0, 1 )
		);
		geometry.colors.push(
			redColor, redColor, greenColor, greenColor, blueColor, blueColor
		);
		material = new THREE.LineBasicMaterial( {
			vertexColors: THREE.VertexColors,
			depthTest: false,
			depthWrite: false,
			transparent: true
		} );
		mesh = new THREE.Line( geometry, material, THREE.LinePieces );
A
Aleksandar Rodic 已提交
173 174 175 176 177 178 179 180 181 182
		displayAxes['translate'].add( mesh );
		displayAxes['scale'].add( mesh.clone() );

		// Translate handles

		mesh = new THREE.Mesh( new THREE.OctahedronGeometry( 0.1, 0 ), HandleMaterial( white ) );
		mesh.name = 'TXYZ';
		displayAxes['translate'].add( mesh );
		pickerAxes['translate'].add( mesh.clone() );

183
		geometry = new THREE.PlaneGeometry( 0.3, 0.3 );
184 185

		mesh = new THREE.Mesh( geometry, HandleMaterial( yellow ) );
186
		mesh.position.set( 0.15, 0.15, 0 );
A
Aleksandar Rodic 已提交
187 188 189 190 191
		bakeTransformations( mesh );
		mesh.name = 'TXY';
		displayAxes['translate'].add( mesh );
		pickerAxes['translate'].add( mesh.clone() );

192
		mesh = new THREE.Mesh( geometry, HandleMaterial( cyan ) );
193
		mesh.position.set( 0, 0.15, 0.15 );
A
Aleksandar Rodic 已提交
194 195 196 197 198
		mesh.rotation.y = Math.PI/2;
		bakeTransformations( mesh );
		mesh.name = 'TYZ';
		displayAxes['translate'].add( mesh );
		pickerAxes['translate'].add( mesh.clone() );
199 200

		mesh = new THREE.Mesh( geometry, HandleMaterial( magenta ) );
201
		mesh.position.set( 0.15, 0, 0.15 );
A
Aleksandar Rodic 已提交
202 203 204 205 206 207
		mesh.rotation.x = Math.PI/2;
		bakeTransformations( mesh );
		mesh.name = 'TXZ';
		displayAxes['translate'].add( mesh );
		pickerAxes['translate'].add( mesh.clone() );

208 209 210
		geometry = new THREE.CylinderGeometry( 0, 0.05, 0.2, 4, 1, true );

		mesh = new THREE.Mesh( geometry, HandleMaterial( red ) );
211
		mesh.position.x = 1.1;
A
Aleksandar Rodic 已提交
212 213 214 215 216
		mesh.rotation.z = -Math.PI/2;
		bakeTransformations( mesh );
		mesh.name = 'TX';
		displayAxes['translate'].add( mesh );

217
		mesh = new THREE.Mesh( geometry, HandleMaterial( green ) );
218
		mesh.position.y = 1.1;
A
Aleksandar Rodic 已提交
219 220 221 222
		bakeTransformations( mesh );
		mesh.name = 'TY';
		displayAxes['translate'].add( mesh );

223
		mesh = new THREE.Mesh( geometry, HandleMaterial( blue ) );
224
		mesh.position.z = 1.1;
A
Aleksandar Rodic 已提交
225 226 227 228 229
		mesh.rotation.x = Math.PI/2;
		bakeTransformations( mesh );
		mesh.name = 'TZ';
		displayAxes['translate'].add( mesh );

230
		geometry = new THREE.CylinderGeometry( 0.2, 0.1, 0.8, 4, 1, false );
231 232

		mesh = new THREE.Mesh( geometry, HandleMaterial( red ) );
233
		mesh.position.x = 0.7;
A
Aleksandar Rodic 已提交
234 235 236 237 238
		mesh.rotation.z = -Math.PI/2;
		bakeTransformations( mesh );
		mesh.name = 'TX';
		pickerAxes['translate'].add( mesh );

239
		mesh = new THREE.Mesh( geometry, HandleMaterial( green ) );
240
		mesh.position.y = 0.7;
A
Aleksandar Rodic 已提交
241 242 243 244
		bakeTransformations( mesh );
		mesh.name = 'TY';
		pickerAxes['translate'].add( mesh );

245
		mesh = new THREE.Mesh( geometry, HandleMaterial( blue ) );
246
		mesh.position.z = 0.7;
A
Aleksandar Rodic 已提交
247 248 249 250 251 252 253
		mesh.rotation.x = Math.PI/2;
		bakeTransformations( mesh );
		mesh.name = 'TZ';
		pickerAxes['translate'].add( mesh );

		// scale manipulators

254
		geometry = new THREE.CubeGeometry( 0.125, 0.125, 0.125 );
255 256

		mesh = new THREE.Mesh( geometry, HandleMaterial( white ) );
A
Aleksandar Rodic 已提交
257 258 259 260
		mesh.name = 'SXYZ';
		displayAxes['scale'].add( mesh );
		pickerAxes['scale'].add( mesh.clone() );

261 262
		mesh = new THREE.Mesh( geometry, HandleMaterial( [1,0,0,0.25] ) );
		mesh.position.set( 1.05, 0, 0 );
A
Aleksandar Rodic 已提交
263 264 265 266 267
		bakeTransformations( mesh );
		mesh.name = 'SX';
		displayAxes['scale'].add( mesh );
		pickerAxes['scale'].add( mesh.clone() );

268 269
		mesh = new THREE.Mesh( geometry, HandleMaterial( [0,1,0,0.25] ) );
		mesh.position.set( 0, 1.05, 0 );
A
Aleksandar Rodic 已提交
270 271 272 273 274
		bakeTransformations( mesh );
		mesh.name = 'SY';
		displayAxes['scale'].add( mesh );
		pickerAxes['scale'].add( mesh.clone() );

275 276
		mesh = new THREE.Mesh( geometry, HandleMaterial( [0,0,1,0.25] ) );
		mesh.position.set( 0, 0, 1.05 );
A
Aleksandar Rodic 已提交
277 278 279 280 281 282 283
		bakeTransformations( mesh );
		mesh.name = 'SZ';
		displayAxes['scale'].add( mesh );
		pickerAxes['scale'].add( mesh.clone() );

		// rotate manipulators

284 285 286
		var Circle = function ( radius, facing, arc ) {

			geometry = new THREE.Geometry();
A
Aleksandar Rodic 已提交
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312
			arc = arc ? arc : 1;
			for ( var i = 0; i <= 64 * arc; ++i ) {
				if ( facing == 'x' ) geometry.vertices.push( new THREE.Vector3( 0, Math.cos( i / 32 * Math.PI ), Math.sin( i / 32 * Math.PI ) ).multiplyScalar(radius) );
				if ( facing == 'y' ) geometry.vertices.push( new THREE.Vector3( Math.cos( i / 32 * Math.PI ), 0, Math.sin( i / 32 * Math.PI ) ).multiplyScalar(radius) );
				if ( facing == 'z' ) geometry.vertices.push( new THREE.Vector3( Math.sin( i / 32 * Math.PI ), Math.cos( i / 32 * Math.PI ), 0 ).multiplyScalar(radius) );
			}

			return geometry;
		}

		mesh = new THREE.Line( Circle( 1, 'x', 0.5 ), LineMaterial( red ) );
		mesh.name = 'RX';
		displayAxes['rotate'].add( mesh );

		mesh = new THREE.Line( Circle( 1, 'y', 0.5 ), LineMaterial( green ) );
		mesh.name = 'RY';
		displayAxes['rotate'].add( mesh );

		mesh = new THREE.Line( Circle( 1, 'z', 0.5 ), LineMaterial( blue ) );
		mesh.name = 'RZ';
		displayAxes['rotate'].add( mesh );

		mesh = new THREE.Line( Circle( 1, 'z' ), LineMaterial( gray ) );
		mesh.name = 'RXYZE';
		displayAxes['rotate'].add( mesh );

313
		mesh = new THREE.Line( Circle( 1.25, 'z' ), LineMaterial( [1,1,0,0.25] ) );
A
Aleksandar Rodic 已提交
314 315 316
		mesh.name = 'RE';
		displayAxes['rotate'].add( mesh );

317
		geometry = new THREE.TorusGeometry( 1, 0.15, 4, 6, Math.PI );
318 319

		mesh = new THREE.Mesh( geometry, HandleMaterial( cyan ) );
A
Aleksandar Rodic 已提交
320
		mesh.rotation.z = -Math.PI/2;
A
Aleksandar Rodic 已提交
321 322 323 324 325
		mesh.rotation.y = -Math.PI/2;
		bakeTransformations( mesh );
		mesh.name = 'RX';
		pickerAxes['rotate'].add( mesh );

326 327
		mesh = new THREE.Mesh( geometry, HandleMaterial( magenta ) );
		mesh.rotation.z = Math.PI;
A
Aleksandar Rodic 已提交
328 329 330 331 332
		mesh.rotation.x = -Math.PI/2;
		bakeTransformations( mesh );
		mesh.name = 'RY';
		pickerAxes['rotate'].add( mesh );

333
		mesh = new THREE.Mesh( geometry, HandleMaterial( yellow ) );
A
Aleksandar Rodic 已提交
334 335
		mesh.rotation.z = -Math.PI/2;
		bakeTransformations( mesh );
A
Aleksandar Rodic 已提交
336 337 338 339
		mesh.name = 'RZ';
		pickerAxes['rotate'].add( mesh );

		mesh = new THREE.Mesh( new THREE.SphereGeometry( 0.95, 12, 12 ), HandleMaterial( white ) );
340
		mesh.name = 'RXYZE';
A
Aleksandar Rodic 已提交
341 342
		pickerAxes['rotate'].add( mesh );

343 344 345 346 347
		intersectionPlanes['SPHERE'] = new THREE.Mesh( new THREE.SphereGeometry( 0.95, 12, 12 ) );
		intersectionPlanes['SPHERE'].visible = false;
		planes.add(intersectionPlanes['SPHERE']);

		mesh = new THREE.Mesh( new THREE.TorusGeometry( 1.30, 0.15, 4, 12 ), HandleMaterial( yellow ) );
A
Aleksandar Rodic 已提交
348 349 350 351 352 353 354
		mesh.name = 'RE';
		pickerAxes['rotate'].add( mesh );

		mesh = null;

	}

355
	this.attatch = function ( object ) {
A
Aleksandar Rodic 已提交
356

357
		this.object = object;
358
	 	this.setMode( scope.mode );
359

A
Aleksandar Rodic 已提交
360
		this.domElement.addEventListener( 'mousedown', onMouseDown, false );
361
		this.domElement.addEventListener( 'mousemove', onMouseHover, false );
A
Aleksandar Rodic 已提交
362
		document.addEventListener( 'keydown', onKeyDown, false );
A
Aleksandar Rodic 已提交
363

364
	}
A
Aleksandar Rodic 已提交
365

366
	this.detatch = function ( object ) {
A
Aleksandar Rodic 已提交
367 368 369 370

	 	this.hide();

		this.domElement.removeEventListener( 'mousedown', onMouseDown, false );
371
		this.domElement.removeEventListener( 'mousemove', onMouseHover, false );
A
Aleksandar Rodic 已提交
372
		document.removeEventListener( 'keydown', onKeyDown, false );
A
Aleksandar Rodic 已提交
373

374
	}
A
Aleksandar Rodic 已提交
375

376
	this.update = function () {
A
Aleksandar Rodic 已提交
377

A
Aleksandar Rodic 已提交
378 379 380
		this.object.updateMatrixWorld();
		worldPosition.getPositionFromMatrix( this.object.matrixWorld );
		worldRotation.setEulerFromRotationMatrix( tempMatrix.extractRotation(this.object.matrixWorld ));
A
Aleksandar Rodic 已提交
381

A
Aleksandar Rodic 已提交
382 383 384
		this.camera.updateMatrixWorld();
		camPosition.getPositionFromMatrix( this.camera.matrixWorld );
		camRotation.setEulerFromRotationMatrix( tempMatrix.extractRotation( this.camera.matrixWorld ));
A
Aleksandar Rodic 已提交
385

386
		scale = worldPosition.distanceTo( camPosition ) / 6 * this.scale;
A
Aleksandar Rodic 已提交
387 388
		this.gizmo.position.copy( worldPosition )
		this.gizmo.scale.set( scale, scale, scale );
A
Aleksandar Rodic 已提交
389

A
Aleksandar Rodic 已提交
390
		for ( var i in this.gizmo.children ) {
391

A
Aleksandar Rodic 已提交
392
			for ( var j in this.gizmo.children[i].children ) {
A
Aleksandar Rodic 已提交
393 394 395 396 397

				object = this.gizmo.children[i].children[j];
				name = object.name;

				if ( name.search('E') != -1 ){
398

A
Aleksandar Rodic 已提交
399
					lookAtMatrix.lookAt( camPosition, worldPosition, tempVector.set( 0, 1, 0 ));
A
Aleksandar Rodic 已提交
400 401 402 403
					object.rotation.setEulerFromRotationMatrix( lookAtMatrix );

				} else {

A
Aleksandar Rodic 已提交
404
					eye.copy( camPosition ).sub( worldPosition ).normalize();
A
Aleksandar Rodic 已提交
405 406 407

					if ( this.space == 'local' ) {

A
Aleksandar Rodic 已提交
408
						tempQuaternion.setFromEuler( worldRotation );
A
Aleksandar Rodic 已提交
409

A
Aleksandar Rodic 已提交
410
						if ( name.search('R') != -1 ){
A
Aleksandar Rodic 已提交
411

A
Aleksandar Rodic 已提交
412 413
							tempMatrix.makeRotationFromQuaternion( tempQuaternion ).getInverse( tempMatrix );
							eye.applyProjection( tempMatrix );
A
Aleksandar Rodic 已提交
414

A
Aleksandar Rodic 已提交
415 416
							if ( name == 'RX' ) {
								quaternionX.setFromAxisAngle( unitX, Math.atan2( -eye.y, eye.z ) );
417
								tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionX );
A
Aleksandar Rodic 已提交
418
							}
A
Aleksandar Rodic 已提交
419

A
Aleksandar Rodic 已提交
420 421
							if ( name == 'RY' ) {
								quaternionY.setFromAxisAngle( unitY, Math.atan2( eye.x, eye.z ) );
422
								tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionY );
A
Aleksandar Rodic 已提交
423 424 425 426
							}

							if ( name == 'RZ' ) {
								quaternionZ.setFromAxisAngle( unitZ, Math.atan2( eye.y, eye.x ) );
427
								tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionZ );
A
Aleksandar Rodic 已提交
428
							}
429

A
Aleksandar Rodic 已提交
430
						}
431

A
Aleksandar Rodic 已提交
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454
						object.rotation.setEulerFromQuaternion( tempQuaternion );

					} else if ( this.space == 'world' ) {

						object.rotation.set( 0, 0, 0 );

						if ( name == 'RX' ) {
							object.rotation.setX( Math.atan2( -eye.y, eye.z ) );
						}

						if ( name == 'RY' ) {
							object.rotation.setY( Math.atan2( eye.x, eye.z ) );
						}

						if ( name == 'RZ' ) {
							object.rotation.setZ( Math.atan2( eye.y, eye.x ) );
						}

					}

				}

			}
A
Aleksandar Rodic 已提交
455

A
Aleksandar Rodic 已提交
456 457
		}

458 459 460
	}

	this.hide = function () {
A
Aleksandar Rodic 已提交
461

A
Aleksandar Rodic 已提交
462
	 	for ( var i in displayAxes ) {
A
Aleksandar Rodic 已提交
463

A
Aleksandar Rodic 已提交
464
		 	for ( var j in displayAxes[i].children ) {
A
Aleksandar Rodic 已提交
465 466 467 468 469 470 471

		 		displayAxes[i].children[j].visible = false;

		 	}

	 	}

A
Aleksandar Rodic 已提交
472
	 	for ( var i in pickerAxes ) {
A
Aleksandar Rodic 已提交
473

A
Aleksandar Rodic 已提交
474
		 	for ( var j in pickerAxes[i].children ) {
A
Aleksandar Rodic 已提交
475 476 477 478 479 480 481

		 		pickerAxes[i].children[j].visible = false;

		 	}

	 	}

482
	}
A
Aleksandar Rodic 已提交
483

484 485 486
	this.setMode = function ( value ) {

		scope.mode = value;
A
Aleksandar Rodic 已提交
487

488
		this.hide();
A
Aleksandar Rodic 已提交
489

490
		if ( scope.mode == 'scale' ) scope.space = 'local';
A
Aleksandar Rodic 已提交
491

A
Aleksandar Rodic 已提交
492
	 	for ( var i in displayAxes[this.mode].children ) {
A
Aleksandar Rodic 已提交
493 494

 			displayAxes[this.mode].children[i].visible = true;
495

A
Aleksandar Rodic 已提交
496 497
	 	}

A
Aleksandar Rodic 已提交
498
	 	for ( var i in pickerAxes[this.mode].children ) {
A
Aleksandar Rodic 已提交
499 500

 			pickerAxes[this.mode].children[i].visible = showPickers;
501

A
Aleksandar Rodic 已提交
502 503
	 	}

504
	 	scope.update();
A
Aleksandar Rodic 已提交
505

506
	}
A
Aleksandar Rodic 已提交
507

508
	this.setIntersectionPlane = function () {
A
Aleksandar Rodic 已提交
509

510
		eye.copy( camPosition ).sub( worldPosition ).normalize();
A
Aleksandar Rodic 已提交
511

512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528
		if ( this.space == 'local' ) {

			eye.applyMatrix4( tempMatrix.getInverse( scope.object.matrixWorld ) );
		
		}

		if ( isActive("X") ) {

			if ( eye.y > eye.z ) currentPlane = 'XZ';
			else currentPlane = 'XY';

		}

		if ( isActive("Y") ) {

			if ( eye.x > eye.z ) currentPlane = 'YZ';
			else currentPlane = 'XY';
A
Aleksandar Rodic 已提交
529

530
		}
A
Aleksandar Rodic 已提交
531

532
		if ( isActive("Z") ) {
A
Aleksandar Rodic 已提交
533

534 535 536 537 538 539 540 541 542 543 544 545 546
			if ( eye.x > eye.y ) currentPlane = 'YZ';
			else currentPlane = 'XZ';

		}

		if ( isActive("XY") ) {

			currentPlane = 'XY';

		}

		if ( isActive("YZ") ) {

547
			currentPlane = 'YZ';
A
Aleksandar Rodic 已提交
548

549
		}
A
Aleksandar Rodic 已提交
550

551
		if ( isActive("XZ") ) {
A
Aleksandar Rodic 已提交
552

553
			currentPlane = 'XZ';
A
Aleksandar Rodic 已提交
554

555
		}
A
Aleksandar Rodic 已提交
556

557
		if ( isActive("XYZ") || isActive("E") ) {
A
Aleksandar Rodic 已提交
558

559
			currentPlane = 'XYZE';
A
Aleksandar Rodic 已提交
560

561
		}
A
Aleksandar Rodic 已提交
562

563
	 	if ( isActive("RX") ) {
A
Aleksandar Rodic 已提交
564

565
			currentPlane = 'YZ';
A
Aleksandar Rodic 已提交
566

567
		}
A
Aleksandar Rodic 已提交
568

569
		if ( isActive("RY") ) {
A
Aleksandar Rodic 已提交
570

571
			currentPlane = 'XZ';
A
Aleksandar Rodic 已提交
572

573
		} 
A
Aleksandar Rodic 已提交
574

575
		if ( isActive("RZ") ) {
A
Aleksandar Rodic 已提交
576

577
			currentPlane = 'XY';
A
Aleksandar Rodic 已提交
578

579
		}
A
Aleksandar Rodic 已提交
580

581 582 583 584 585
		if ( isActive("RXYZ") ) {

			currentPlane = 'SPHERE';

		}
A
Aleksandar Rodic 已提交
586

587
	}
A
Aleksandar Rodic 已提交
588

589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628
	function onMouseHover( event ) {

		event.preventDefault();

		if ( event.button === 0 && !scope.active ) {

			intersect = intersectObjects( event, pickerAxes[scope.mode].children );

			for ( var i in displayAxes[scope.mode].children ) {

	 			var axis = displayAxes[scope.mode].children[i];
	 			
	 			if ( intersect && axis.name == intersect.object.name ) {

	 				axis.material.color.setRGB(1,1,0);
	 				axis.material.opacity = 1;
	 			
	 			} else if ( axis.material.origColor ) {

	 				axis.material.color.copy( axis.material.origColor );
	 				axis.material.opacity = axis.material.origOpacity;
	 					
	 			} else {

	 				axis.material.origColor = axis.material.color.clone();
	 				axis.material.origOpacity = axis.material.opacity;

	 			}

		 	}

		 	scope.dispatchEvent( changeEvent );

		}

		document.addEventListener( 'mousemove', onMouseMove, false );
		document.addEventListener( 'mouseup', onMouseUp, false );

	};

629
	function onMouseDown( event ) {
A
Aleksandar Rodic 已提交
630 631 632 633 634

		event.preventDefault();

		if ( event.button === 0 ) {

M
Mr.doob 已提交
635
			intersect = intersectObjects( event, pickerAxes[scope.mode].children );
A
Aleksandar Rodic 已提交
636

A
Aleksandar Rodic 已提交
637
			if ( intersect ) {
A
Aleksandar Rodic 已提交
638

A
Aleksandar Rodic 已提交
639
				scope.active = intersect.object.name;
A
Aleksandar Rodic 已提交
640

641
				scope.update();
A
Aleksandar Rodic 已提交
642 643
				scope.setIntersectionPlane();

M
Mr.doob 已提交
644
				planeIntersect = intersectObjects( event, [intersectionPlanes[currentPlane]] );
A
Aleksandar Rodic 已提交
645

A
Aleksandar Rodic 已提交
646 647
				if ( planeIntersect ) {

648 649
					oldPosition.copy( scope.object.position );
					oldScale.copy( scope.object.scale );
A
Aleksandar Rodic 已提交
650

651 652
					oldRotationMatrix.extractRotation( scope.object.matrix );
					worldRotationMatrix.extractRotation( scope.object.matrixWorld );
A
Aleksandar Rodic 已提交
653

654 655
					parentRotationMatrix.extractRotation( scope.object.parent.matrixWorld );
					parentScale.getScaleFromMatrix( tempMatrix.getInverse( scope.object.parent.matrixWorld ) );
A
Aleksandar Rodic 已提交
656

A
Aleksandar Rodic 已提交
657 658 659
					offset.copy( planeIntersect.point );

				}
A
Aleksandar Rodic 已提交
660 661 662 663 664 665 666 667 668 669 670 671 672 673

			}

		}

		document.addEventListener( 'mousemove', onMouseMove, false );
		document.addEventListener( 'mouseup', onMouseUp, false );

	};

	function onMouseMove( event ) {

		if ( scope.active ) {

M
Mr.doob 已提交
674
			planeIntersect = intersectObjects( event, [intersectionPlanes[currentPlane]] );
A
Aleksandar Rodic 已提交
675

A
Aleksandar Rodic 已提交
676
			if ( planeIntersect ) {
A
Aleksandar Rodic 已提交
677

A
Aleksandar Rodic 已提交
678
				point.copy( planeIntersect.point );
A
Aleksandar Rodic 已提交
679

A
Aleksandar Rodic 已提交
680
				if ( ( scope.mode == 'translate' ) && isActive("T") ) {
681

A
Aleksandar Rodic 已提交
682 683
					point.sub( offset );
					point.multiply(parentScale);
A
Aleksandar Rodic 已提交
684 685 686

					if ( scope.space == 'local' ) {

A
Aleksandar Rodic 已提交
687 688 689 690 691 692
						point.applyMatrix4( tempMatrix.getInverse( worldRotationMatrix ) );

						if ( !(isActive("X")) || scope.modifierAxis.x != 1 ) point.x = 0;
						if ( !(isActive("Y")) || scope.modifierAxis.y != 1 ) point.y = 0;
						if ( !(isActive("Z")) || scope.modifierAxis.z != 1 ) point.z = 0;
						if ( isActive("XYZ") ) point.set( 0, 0, 0 );
A
Aleksandar Rodic 已提交
693

A
Aleksandar Rodic 已提交
694
						point.applyMatrix4( oldRotationMatrix );
A
Aleksandar Rodic 已提交
695 696

						scope.object.position.copy( oldPosition );
A
Aleksandar Rodic 已提交
697
						scope.object.position.add( point );
A
Aleksandar Rodic 已提交
698 699 700

					} 

A
Aleksandar Rodic 已提交
701
					if ( scope.space == 'world' || isActive("XYZ") ) {
A
Aleksandar Rodic 已提交
702

A
Aleksandar Rodic 已提交
703 704 705
						if ( !(isActive("X")) || scope.modifierAxis.x != 1 ) point.x = 0;
						if ( !(isActive("Y")) || scope.modifierAxis.y != 1 ) point.y = 0;
						if ( !(isActive("Z")) || scope.modifierAxis.z != 1 ) point.z = 0;
A
Aleksandar Rodic 已提交
706

A
Aleksandar Rodic 已提交
707
						point.applyMatrix4( tempMatrix.getInverse( parentRotationMatrix ) );
A
Aleksandar Rodic 已提交
708 709 710

						scope.object.position.copy( oldPosition );
						scope.object.position.add( point );
711

A
Aleksandar Rodic 已提交
712
						if ( scope.snapDist ) {
A
Aleksandar Rodic 已提交
713
							if ( isActive("X") ) scope.object.position.x = Math.round( scope.object.position.x / scope.snapDist ) * scope.snapDist;
714 715
							if ( isActive("Y") ) scope.object.position.y = Math.round( scope.object.position.y / scope.snapDist ) * scope.snapDist;
							if ( isActive("Z") ) scope.object.position.z = Math.round( scope.object.position.z / scope.snapDist ) * scope.snapDist;
A
Aleksandar Rodic 已提交
716 717 718 719
						}

					}

A
Aleksandar Rodic 已提交
720
				} else if ( ( scope.mode == 'scale') && isActive("S") ) {
A
Aleksandar Rodic 已提交
721

A
Aleksandar Rodic 已提交
722 723
					point.sub( offset );
					point.multiply(parentScale);
A
Aleksandar Rodic 已提交
724 725 726

					if ( scope.space == 'local' ) {

A
Aleksandar Rodic 已提交
727
						if ( isActive("XYZ")) {
728

A
Aleksandar Rodic 已提交
729
							scale = 1 + ( ( point.y ) / 50 );
A
Aleksandar Rodic 已提交
730 731 732 733 734 735

							scope.object.scale.x = oldScale.x * scale;
							scope.object.scale.y = oldScale.y * scale;
							scope.object.scale.z = oldScale.z * scale;

						} else {
736

A
Aleksandar Rodic 已提交
737
							point.applyMatrix4( tempMatrix.getInverse( worldRotationMatrix ) );
A
Aleksandar Rodic 已提交
738

A
Aleksandar Rodic 已提交
739 740 741 742 743 744 745
							if ( !(isActive("X")) || scope.modifierAxis.x != 1 ) point.x = 0;
							if ( !(isActive("Y")) || scope.modifierAxis.y != 1 ) point.y = 0;
							if ( !(isActive("Z")) || scope.modifierAxis.z != 1 ) point.z = 0;

							if ( isActive("X") ) scope.object.scale.x = oldScale.x * ( 1 + point.x / 50 );
							if ( isActive("Y") ) scope.object.scale.y = oldScale.y * ( 1 + point.y / 50 );
							if ( isActive("Z") ) scope.object.scale.z = oldScale.z * ( 1 + point.z / 50 );
A
Aleksandar Rodic 已提交
746 747 748

						}

A
Aleksandar Rodic 已提交
749
					}
A
Aleksandar Rodic 已提交
750

A
Aleksandar Rodic 已提交
751
				} else if ( ( scope.mode == 'rotate' ) && isActive("R") ) {
A
Aleksandar Rodic 已提交
752

A
Aleksandar Rodic 已提交
753 754 755 756
					point.sub( worldPosition );
					point.multiply(parentScale);
					tempVector.copy(offset).sub( worldPosition );
					tempVector.multiply(parentScale);
A
Aleksandar Rodic 已提交
757

A
Aleksandar Rodic 已提交
758
					if ( scope.active == "RE" ) {
A
Aleksandar Rodic 已提交
759

A
Aleksandar Rodic 已提交
760 761
						point.applyMatrix4( tempMatrix.getInverse( lookAtMatrix ) );
						tempVector.applyMatrix4( tempMatrix.getInverse( lookAtMatrix ) );
A
Aleksandar Rodic 已提交
762

A
Aleksandar Rodic 已提交
763 764
						rotation.set( Math.atan2( point.z, point.y ), Math.atan2( point.x, point.z ), Math.atan2( point.y, point.x ) );
						offsetRotation.set( Math.atan2( tempVector.z, tempVector.y ), Math.atan2( tempVector.x, tempVector.z ), Math.atan2( tempVector.y, tempVector.x ) );
A
Aleksandar Rodic 已提交
765

A
Aleksandar Rodic 已提交
766
						tempQuaternion.setFromRotationMatrix( tempMatrix.getInverse( parentRotationMatrix ) );
A
Aleksandar Rodic 已提交
767

A
Aleksandar Rodic 已提交
768 769 770 771 772
						quaternionE.setFromAxisAngle( eye, rotation.z - offsetRotation.z );
						quaternionXYZ.setFromRotationMatrix( worldRotationMatrix );

						tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionE );
						tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionXYZ );
773

A
Aleksandar Rodic 已提交
774 775
						scope.object.rotation.setEulerFromQuaternion( tempQuaternion );

776 777 778
					} else if ( scope.active == "RXYZE" ) {

						quaternionE.setFromEuler( point.clone().cross(tempVector).normalize() ); // rotation axis
A
Aleksandar Rodic 已提交
779

780 781 782 783 784 785 786 787
						tempQuaternion.setFromRotationMatrix( tempMatrix.getInverse( parentRotationMatrix ) );
						quaternionX.setFromAxisAngle( quaternionE, - point.clone().angleTo(tempVector) );
						quaternionXYZ.setFromRotationMatrix( worldRotationMatrix );

						tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionX );
						tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionXYZ );

						scope.object.rotation.setEulerFromQuaternion( tempQuaternion );
A
Aleksandar Rodic 已提交
788 789 790 791 792 793 794 795 796 797 798

					} else if ( scope.space == 'local' ) {

						point.applyMatrix4( tempMatrix.getInverse( worldRotationMatrix ) );

						tempVector.applyMatrix4( tempMatrix.getInverse( worldRotationMatrix ) );

						rotation.set( Math.atan2( point.z, point.y ), Math.atan2( point.x, point.z ), Math.atan2( point.y, point.x ) );
						offsetRotation.set( Math.atan2( tempVector.z, tempVector.y ), Math.atan2( tempVector.x, tempVector.z ), Math.atan2( tempVector.y, tempVector.x ) );

						quaternionXYZ.setFromRotationMatrix( oldRotationMatrix );
A
Aleksandar Rodic 已提交
799 800 801 802
						quaternionX.setFromAxisAngle( unitX, rotation.x - offsetRotation.x );
						quaternionY.setFromAxisAngle( unitY, rotation.y - offsetRotation.y );
						quaternionZ.setFromAxisAngle( unitZ, rotation.z - offsetRotation.z );

A
Aleksandar Rodic 已提交
803 804 805
						if ( scope.active == "RX" ) quaternionXYZ.multiplyQuaternions( quaternionXYZ, quaternionX );
						if ( scope.active == "RY" ) quaternionXYZ.multiplyQuaternions( quaternionXYZ, quaternionY );
						if ( scope.active == "RZ" ) quaternionXYZ.multiplyQuaternions( quaternionXYZ, quaternionZ );
806

A
Aleksandar Rodic 已提交
807 808
						scope.object.rotation.setEulerFromQuaternion( quaternionXYZ );

A
Aleksandar Rodic 已提交
809
					} else if ( scope.space == 'world' ) {
A
Aleksandar Rodic 已提交
810 811

						rotation.set( Math.atan2( point.z, point.y ), Math.atan2( point.x, point.z ), Math.atan2( point.y, point.x ) );
A
Aleksandar Rodic 已提交
812 813 814
						offsetRotation.set( Math.atan2( tempVector.z, tempVector.y ), Math.atan2( tempVector.x, tempVector.z ), Math.atan2( tempVector.y, tempVector.x ) );

						tempQuaternion.setFromRotationMatrix( tempMatrix.getInverse( parentRotationMatrix ) );
A
Aleksandar Rodic 已提交
815 816 817 818

						quaternionX.setFromAxisAngle( unitX, rotation.x - offsetRotation.x );
						quaternionY.setFromAxisAngle( unitY, rotation.y - offsetRotation.y );
						quaternionZ.setFromAxisAngle( unitZ, rotation.z - offsetRotation.z );
A
Aleksandar Rodic 已提交
819
						quaternionXYZ.setFromRotationMatrix( worldRotationMatrix );
A
Aleksandar Rodic 已提交
820

A
Aleksandar Rodic 已提交
821 822 823
						if ( scope.active == "RX" ) tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionX );
						if ( scope.active == "RY" ) tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionY );
						if ( scope.active == "RZ" ) tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionZ );
A
Aleksandar Rodic 已提交
824

A
Aleksandar Rodic 已提交
825
						tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionXYZ );
826

A
Aleksandar Rodic 已提交
827
						scope.object.rotation.setEulerFromQuaternion( tempQuaternion );
A
Aleksandar Rodic 已提交
828 829 830 831 832 833 834

					}

				}

			}

835
			scope.update();
836
			scope.dispatchEvent( changeEvent );
A
Aleksandar Rodic 已提交
837

838
		}
A
Aleksandar Rodic 已提交
839 840 841 842 843 844 845 846 847 848 849 850 851 852

	}

	function onMouseUp( event ) {

		scope.active = false;

		document.removeEventListener( 'mousemove', onMouseMove, false );
		document.removeEventListener( 'mouseup', onMouseUp, false );

	}

	function onKeyDown( event ) {

853 854 855 856
		var currentMode = scope.mode;
		var currentSpace = scope.space;
		var currentScale = scope.scale;

A
Aleksandar Rodic 已提交
857 858 859 860 861 862 863 864 865
		if ( event.keyCode == 87 ) { // W

			if ( scope.mode == 'translate' ) scope.space = ( scope.space == 'world' ) ? 'local' : 'world';
			scope.mode = 'translate';

		}

		if ( event.keyCode == 69 ) { // E

866
			if ( scope.mode == 'rotate' ) scope.space = ( scope.space == 'world' ) ? 'local' : 'world';
A
Aleksandar Rodic 已提交
867 868 869 870 871
			scope.mode = 'rotate';

		}

		if ( event.keyCode == 82 ) { // R
872

A
Aleksandar Rodic 已提交
873 874 875 876 877
			scope.mode = 'scale';
			scope.space = 'local';

		}

A
Aleksandar Rodic 已提交
878
		if ( event.keyCode == 187 || event.keyCode == 107 ) { // +,=,num+
879

A
Aleksandar Rodic 已提交
880 881 882 883 884
			scope.scale += 0.1

		}

		if ( event.keyCode == 189 || event.keyCode == 109) { // -,_,num-
885

A
Aleksandar Rodic 已提交
886 887 888 889 890
			scope.scale -= 0.1
			scope.scale = Math.max( scope.scale, 0.1 );

		}

891 892 893 894 895 896
		if ( scope.mode !== currentMode || scope.space !== currentSpace || scope.scale !== currentScale ) {

			scope.setMode( scope.mode );
			scope.dispatchEvent( changeEvent );

		}
A
Aleksandar Rodic 已提交
897 898 899

	}

M
Mr.doob 已提交
900
	function intersectObjects( event, objects ) {
A
Aleksandar Rodic 已提交
901 902 903 904 905 906 907 908 909

		pointerVector.set(
			( event.layerX / scope.domElement.offsetWidth ) * 2 - 1,
			- ( event.layerY / scope.domElement.offsetHeight ) * 2 + 1,
			0.5
		);

		projector.unprojectVector( pointerVector, scope.camera );
		ray.set( camPosition, pointerVector.sub( camPosition ).normalize() );
910

A
Aleksandar Rodic 已提交
911 912
		var intersections = ray.intersectObjects( objects, true );
		return intersections[0] ? intersections[0] : false;
913

A
Aleksandar Rodic 已提交
914 915
	}

A
Aleksandar Rodic 已提交
916 917 918
	function isActive( name ) {
		if ( scope.active.search( name ) != -1 ) return true;
		else return false;
A
Aleksandar Rodic 已提交
919 920 921 922 923 924 925 926 927 928 929 930 931 932 933
	}

	function bakeTransformations( object ) {

		var tempGeometry = new THREE.Geometry();
		THREE.GeometryUtils.merge( tempGeometry, object );
		object.setGeometry( tempGeometry );
		object.position.set( 0, 0, 0 );
		object.rotation.set( 0, 0, 0 );
		object.scale.set( 1, 1, 1 );

	}

};

934
THREE.TransformControls.prototype = Object.create( THREE.EventDispatcher.prototype );