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

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

7
THREE.TransformGizmoMaterial = function ( parameters ) {
A
Aleksandar Rodic 已提交
8

9
	THREE.MeshBasicMaterial.call( this );
10

11 12 13 14
	this.depthTest = false;
	this.depthWrite = false;
	this.side = THREE.DoubleSide;
	this.transparent = true;
A
Aleksandar Rodic 已提交
15

16
	this.setValues( parameters );
17

18
}
19

20
THREE.TransformGizmoMaterial.prototype = Object.create( THREE.MeshBasicMaterial.prototype );
A
Aleksandar Rodic 已提交
21

22
THREE.TransformGizmo = function () {
23

24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
	this.handleGizmos = {
		X: [
			new THREE.Mesh( new THREE.CylinderGeometry( 0.005, 0.005, 1, 4, 1, false ), new THREE.TransformGizmoMaterial( { color: "red" } ) ),
			new THREE.Vector3( 0.5, 0, 0 ),
			new THREE.Vector3( 0, 0, -Math.PI/2 )
		],
		Y: [
			new THREE.Mesh( new THREE.CylinderGeometry( 0.005, 0.005, 1, 4, 1, false ), new THREE.TransformGizmoMaterial( { color: "green" } ) ),
			new THREE.Vector3( 0, 0.5, 0 )
		],
		Z: [
			new THREE.Mesh( new THREE.CylinderGeometry( 0.005, 0.005, 1, 4, 1, false ), new THREE.TransformGizmoMaterial( { color: "blue" } ) ),
			new THREE.Vector3( 0, 0, 0.5 ),
			new THREE.Vector3( Math.PI/2, 0, 0 )
		]
	}
A
Aleksandar Rodic 已提交
40

41 42
	var showPickers = false; //debug
	var showActivePlane = false; //debug
43

44
	this.init = function () {
A
Aleksandar Rodic 已提交
45

46
		THREE.Object3D.call( this );
A
Aleksandar Rodic 已提交
47

48 49 50
		this.handles = new THREE.Object3D();
		this.pickers = new THREE.Object3D();
		this.planes = new THREE.Object3D();
A
Aleksandar Rodic 已提交
51

52 53 54
		this.add(this.handles);
		this.add(this.pickers);
		this.add(this.planes);
A
Aleksandar Rodic 已提交
55

56
		//// PLANES
57

58 59 60
		var planeGeometry = new THREE.PlaneGeometry( 50, 50, 2, 2 );
		var planeMaterial = new THREE.MeshBasicMaterial( { wireframe: true } );
		planeMaterial.side = THREE.DoubleSide;
A
Aleksandar Rodic 已提交
61

62 63 64 65 66 67
		var planes = {
			"XY": new THREE.Mesh( planeGeometry, planeMaterial ),
			"YZ": new THREE.Mesh( planeGeometry, planeMaterial ),
			"XZ": new THREE.Mesh( planeGeometry, planeMaterial ),
			"XYZE": new THREE.Mesh( planeGeometry, planeMaterial )
		};
A
Aleksandar Rodic 已提交
68

69 70
		planes["YZ"].rotation.set( 0, Math.PI/2, 0 );
		planes["XZ"].rotation.set( -Math.PI/2, 0, 0 );
A
Aleksandar Rodic 已提交
71

72 73 74 75 76 77
		for (var i in planes) {
			planes[i].name = i;
			this.planes.add(planes[i]);
			this.planes[i] = planes[i];
			planes[i].visible = false;
		}
A
Aleksandar Rodic 已提交
78

79
		//// HANDLES AND PICKERS
A
Aleksandar Rodic 已提交
80

81
		for ( var i in this.handleGizmos ) {
A
Aleksandar Rodic 已提交
82

83 84 85 86 87 88
			var handle = this.handleGizmos[i][0];
			handle.name = i;
			if ( this.handleGizmos[i][1] ) handle.position.set( this.handleGizmos[i][1].x, this.handleGizmos[i][1].y, this.handleGizmos[i][1].z );
			if ( this.handleGizmos[i][2] ) handle.rotation.set( this.handleGizmos[i][2].x, this.handleGizmos[i][2].y, this.handleGizmos[i][2].z );
			
			this.handles.add( handle );
89

90
			if ( this.pickerGizmos && this.pickerGizmos[i] ) {
91

92 93 94 95 96
				var picker = this.pickerGizmos[i][0];
				if ( this.pickerGizmos[i][1] ) picker.position.set( this.pickerGizmos[i][1].x, this.pickerGizmos[i][1].y, this.pickerGizmos[i][1].z );
				if ( this.pickerGizmos[i][2] ) picker.rotation.set( this.pickerGizmos[i][2].x, this.pickerGizmos[i][2].y, this.pickerGizmos[i][2].z );
			
			} else {
97

98 99 100 101 102 103
				var picker = handle.clone();

			}

			picker.name = i;
			this.pickers.add( picker );
104 105 106

		}

107 108 109 110 111 112 113 114 115 116 117 118 119
		// reset Transformations

		this.traverse(function (child) {
			if (child instanceof THREE.Mesh) {			
				var tempGeometry = new THREE.Geometry();
				THREE.GeometryUtils.merge( tempGeometry, child );
				child.geometry = tempGeometry;
				child.position.set( 0, 0, 0 );
				child.rotation.set( 0, 0, 0 );
				child.scale.set( 1, 1, 1 );

			}
		});
120 121 122

	}

123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
	this.hide = function () {

		for ( var j in this.handles.children ) this.handles.children[j].visible = false;

		for ( var j in this.pickers.children ) this.pickers.children[j].visible = false;

		for ( var j in this.planes.children ) this.planes.children[j].visible = false;

	}

	this.show = function () {

		for ( var i in this.handles.children ) {

			this.handles.children[i].visible = true;

A
Aleksandar Rodic 已提交
139 140
		}

141 142 143 144
		for ( var i in this.pickers.children ) {

			this.pickers.children[i].visible = showPickers;

A
Aleksandar Rodic 已提交
145 146
		}

147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
		if (this.activePlane) this.activePlane.visible = showActivePlane;

	}

	this.highlight = function ( axis ) {

		var handle;

		for ( var i in this.handleGizmos ) {

			handle = this.handleGizmos[ i ][0];

			if ( handle.material.oldColor ) {

				handle.material.color.copy( handle.material.oldColor );
				handle.material.opacity = handle.material.oldOpacity;

A
Aleksandar Rodic 已提交
164 165 166 167
			}

		}

168
		if ( this.handleGizmos[ axis ] ) {
169 170
		
			handle = this.handleGizmos[ axis ][0];
A
Aleksandar Rodic 已提交
171

172 173 174 175 176
			handle.material.oldColor = handle.material.color.clone();
			handle.material.oldOpacity = handle.material.opacity;
	 
			handle.material.color.setRGB( 1, 1, 0 );
			handle.material.opacity = 1;
A
Aleksandar Rodic 已提交
177

178
		}
A
Aleksandar Rodic 已提交
179

180
	}
A
Aleksandar Rodic 已提交
181

182
	this.init();
A
Aleksandar Rodic 已提交
183

184
}
185

186
THREE.TransformGizmo.prototype = Object.create( THREE.Object3D.prototype );
A
Aleksandar Rodic 已提交
187

188
THREE.TransformGizmo.prototype.update = function ( rotation, eye ) {
A
Aleksandar Rodic 已提交
189

190 191 192
	var vec1 = new THREE.Vector3( 0, 0, 0 );
	var vec2 = new THREE.Vector3( 0, 1, 0 );
	var lookAtMatrix = new THREE.Matrix4();
A
Aleksandar Rodic 已提交
193

194
	for ( var i in this.children ) {
A
Aleksandar Rodic 已提交
195

196
		for ( var j in this.children[i].children ) {
197

198
			var object = this.children[i].children[j];
A
Aleksandar Rodic 已提交
199

200 201 202 203 204 205 206 207 208 209 210
			if ( object.name.search("E") != -1 ) {

				object.quaternion.setFromRotationMatrix( lookAtMatrix.lookAt( eye, vec1, vec2 ) );

			} else {

				object.quaternion.setFromEuler( rotation );

			}

		}
A
Aleksandar Rodic 已提交
211 212 213

	}

214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
}

THREE.TransformGizmoTranslate = function () {

	THREE.TransformGizmo.call( this );

	var arrowGeometry = new THREE.CylinderGeometry( 0.005, 0.005, 1, 4, 1, false );
	var mesh = new THREE.Mesh( new THREE.CylinderGeometry( 0, 0.05, 0.2, 12, 1, false ) );
	mesh.position.y = 0.5;
	THREE.GeometryUtils.merge( arrowGeometry, mesh );
				
	this.handleGizmos = {

		X: [
			new THREE.Mesh( arrowGeometry, new THREE.TransformGizmoMaterial( { color: "red" } ) ),
			new THREE.Vector3( 0.5, 0, 0 ),
			new THREE.Vector3( 0, 0, -Math.PI/2 )
		],
		Y: [
			new THREE.Mesh( arrowGeometry, new THREE.TransformGizmoMaterial( { color: "green" } ) ),
			new THREE.Vector3( 0, 0.5, 0 )
		],
		Z: [
			new THREE.Mesh( arrowGeometry, new THREE.TransformGizmoMaterial( { color: "blue" } ) ),
			new THREE.Vector3( 0, 0, 0.5 ),
			new THREE.Vector3( Math.PI/2, 0, 0 )
		],
		XYZ: [
			new THREE.Mesh( new THREE.OctahedronGeometry( 0.1, 0 ), new THREE.TransformGizmoMaterial( { color: "white", opacity: 0.25 } ) )
		],
		XY: [
			new THREE.Mesh( new THREE.PlaneGeometry( 0.29, 0.29 ), new THREE.TransformGizmoMaterial( { color: "yellow", opacity: 0.25 } ) ),
			new THREE.Vector3( 0.15, 0.15, 0 )
		],
		YZ: [
			new THREE.Mesh( new THREE.PlaneGeometry( 0.29, 0.29 ), new THREE.TransformGizmoMaterial( { color: "cyan", opacity: 0.25 } ) ),
			new THREE.Vector3( 0, 0.15, 0.15 ),
			new THREE.Vector3( 0, Math.PI/2, 0 )
		],
		XZ: [
			new THREE.Mesh( new THREE.PlaneGeometry( 0.29, 0.29 ), new THREE.TransformGizmoMaterial( { color: "magenta", opacity: 0.25 } ) ),
			new THREE.Vector3( 0.15, 0, 0.15 ),
256
			new THREE.Vector3( -Math.PI/2, 0, 0 )
257
		]
A
Aleksandar Rodic 已提交
258

259
	}
260

261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
	this.pickerGizmos = {

		X: [
			new THREE.Mesh( new THREE.CylinderGeometry( 0.075, 0, 1, 4, 1, false ), new THREE.TransformGizmoMaterial( { color: "red", opacity: 0.25 } ) ),
			new THREE.Vector3( 0.6, 0, 0 ),
			new THREE.Vector3( 0, 0, -Math.PI/2 )
		],
		Y: [
			new THREE.Mesh( new THREE.CylinderGeometry( 0.075, 0, 1, 4, 1, false ), new THREE.TransformGizmoMaterial( { color: "green", opacity: 0.25 } ) ),
			new THREE.Vector3( 0, 0.6, 0 )
		],
		Z: [
			new THREE.Mesh( new THREE.CylinderGeometry( 0.075, 0, 1, 4, 1, false ), new THREE.TransformGizmoMaterial( { color: "blue", opacity: 0.25 } ) ),
			new THREE.Vector3( 0, 0, 0.6 ),
			new THREE.Vector3( Math.PI/2, 0, 0 )
		]
A
Aleksandar Rodic 已提交
277

278
	}
A
Aleksandar Rodic 已提交
279

280
	this.setActivePlane = function ( axis, eye ) {
A
Aleksandar Rodic 已提交
281

282 283
		var tempMatrix = new THREE.Matrix4();
		eye.applyProjection( tempMatrix.getInverse( tempMatrix.extractRotation( this.planes[ "XY" ].matrixWorld ) ) );
284

285 286 287 288 289 290 291 292 293
		if ( axis == "X" ) {
			this.activePlane = this.planes[ "XY" ];
			if ( Math.abs(eye.y) > Math.abs(eye.z) ) this.activePlane = this.planes[ "XZ" ];
		}

		if ( axis == "Y" ){
			this.activePlane = this.planes[ "XY" ];
			if ( Math.abs(eye.x) > Math.abs(eye.z) ) this.activePlane = this.planes[ "YZ" ];
		}
A
Aleksandar Rodic 已提交
294

295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
		if ( axis == "Z" ){
			this.activePlane = this.planes[ "XZ" ];
			if ( Math.abs(eye.x) > Math.abs(eye.y) ) this.activePlane = this.planes[ "YZ" ];
		}

		if ( axis == "XYZ" ) this.activePlane = this.planes[ "XYZE" ];

		if ( axis == "XY" ) this.activePlane = this.planes[ "XY" ];

		if ( axis == "YZ" ) this.activePlane = this.planes[ "YZ" ];

		if ( axis == "XZ" ) this.activePlane = this.planes[ "XZ" ];

		this.hide();
		this.show();
A
Aleksandar Rodic 已提交
310

311
	}
A
Aleksandar Rodic 已提交
312

313
	this.init();
A
Aleksandar Rodic 已提交
314

315
}
316

317
THREE.TransformGizmoTranslate.prototype = Object.create( THREE.TransformGizmo.prototype );
A
Aleksandar Rodic 已提交
318

319
THREE.TransformGizmoRotate = function () {
A
Aleksandar Rodic 已提交
320

321
	THREE.TransformGizmo.call( this );
A
Aleksandar Rodic 已提交
322

323
	this.handleGizmos = {
324

325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
		X: [
			new THREE.Mesh( new THREE.TorusGeometry( 1, 0.005, 4, 32, Math.PI ), new THREE.TransformGizmoMaterial( { color: "red" } ) ),
			new THREE.Vector3( 0, 0, 0 ),
			new THREE.Vector3( 0, -Math.PI/2, -Math.PI/2 )
		],
		Y: [
			new THREE.Mesh( new THREE.TorusGeometry( 1, 0.005, 4, 32, Math.PI ), new THREE.TransformGizmoMaterial( { color: "green" } ) ),
			new THREE.Vector3( 0, 0, 0 ),
			new THREE.Vector3( Math.PI/2, 0, 0 )
		],
		Z: [
			new THREE.Mesh( new THREE.TorusGeometry( 1, 0.005, 4, 32, Math.PI ), new THREE.TransformGizmoMaterial( { color: "blue" } ) ),
			new THREE.Vector3( 0, 0, 0 ),
			new THREE.Vector3( 0, 0, -Math.PI/2 )
		],
		E: [
			new THREE.Mesh( new THREE.TorusGeometry( 1.25, 0.005, 4, 64 ), new THREE.TransformGizmoMaterial( { color: "yellow", opacity: 0.25 } ) )
		],
		XYZE: [
			new THREE.Mesh( new THREE.TorusGeometry( 1, 0.005, 4, 64 ), new THREE.TransformGizmoMaterial( { color: "gray" } ) )
		]
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
	}

	this.pickerGizmos = {

		X: [
			new THREE.Mesh( new THREE.TorusGeometry( 1, 0.05, 4, 12, Math.PI ), new THREE.TransformGizmoMaterial( { color: "red", opacity: 0.25 } ) ),
			new THREE.Vector3( 0, 0, 0 ),
			new THREE.Vector3( 0, -Math.PI/2, -Math.PI/2 )
		],
		Y: [
			new THREE.Mesh( new THREE.TorusGeometry( 1, 0.05, 4, 12, Math.PI ), new THREE.TransformGizmoMaterial( { color: "green", opacity: 0.25 } ) ),
			new THREE.Vector3( 0, 0, 0 ),
			new THREE.Vector3( Math.PI/2, 0, 0 )
		],
		Z: [
			new THREE.Mesh( new THREE.TorusGeometry( 1, 0.05, 4, 12, Math.PI ), new THREE.TransformGizmoMaterial( { color: "blue", opacity: 0.25 } ) ),
			new THREE.Vector3( 0, 0, 0 ),
			new THREE.Vector3( 0, 0, -Math.PI/2 )
		],
		E: [
			new THREE.Mesh( new THREE.TorusGeometry( 1.25, 0.05, 2, 24 ), new THREE.TransformGizmoMaterial( { color: "yellow", opacity: 0.25 } ) )
		],
		XYZE: [
			new THREE.Mesh( new THREE.Geometry() ) // TODO
		]
A
Aleksandar Rodic 已提交
372

373
	}
A
Aleksandar Rodic 已提交
374

375
	this.setActivePlane = function ( axis ) {
376

377
		if ( axis == "E" ) this.activePlane = this.planes[ "XYZE" ];
A
Aleksandar Rodic 已提交
378

379
	 	if ( axis == "X" ) this.activePlane = this.planes[ "YZ" ];
A
Aleksandar Rodic 已提交
380

381
		if ( axis == "Y" ) this.activePlane = this.planes[ "XZ" ];
A
Aleksandar Rodic 已提交
382

383
		if ( axis == "Z" ) this.activePlane = this.planes[ "XY" ];
A
Aleksandar Rodic 已提交
384

385 386
		this.hide();
		this.show();
A
Aleksandar Rodic 已提交
387

388
	}
A
Aleksandar Rodic 已提交
389

390
	this.update = function ( rotation, eye2 ) {
A
Aleksandar Rodic 已提交
391

392
		THREE.TransformGizmo.prototype.update.apply( this, arguments );
A
Aleksandar Rodic 已提交
393

394 395 396 397
		var group = {
			handles: this["handles"],
			pickers: this["pickers"],
		}
A
Aleksandar Rodic 已提交
398

399 400 401 402 403 404 405 406 407 408
		var tempMatrix = new THREE.Matrix4();
		var worldRotation = new THREE.Euler( 0, 0, 1 );
		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 quaternionX = new THREE.Quaternion();
		var quaternionY = new THREE.Quaternion();
		var quaternionZ = new THREE.Quaternion();
		var eye = eye2.clone();
409

410 411
		worldRotation.copy( this.planes["XY"].rotation );
		tempQuaternion.setFromEuler( worldRotation );
412

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

416
		for ( var i in group ) {
A
Aleksandar Rodic 已提交
417

418
			for ( var j in group[i].children ) {
A
Aleksandar Rodic 已提交
419

420
				var object = group[i].children[j];
A
Aleksandar Rodic 已提交
421

422
				tempQuaternion.setFromEuler( worldRotation );
A
Aleksandar Rodic 已提交
423

424 425 426 427
				if ( object.name == "X" ) {
					quaternionX.setFromAxisAngle( unitX, Math.atan2( -eye.y, eye.z ) );
					tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionX );
					object.quaternion.copy( tempQuaternion );
A
Aleksandar Rodic 已提交
428 429
				}

430 431 432 433 434 435 436 437 438 439 440
				if ( object.name == "Y" ) {
					quaternionY.setFromAxisAngle( unitY, Math.atan2( eye.x, eye.z ) );
					tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionY );
					object.quaternion.copy( tempQuaternion );
				}

				if ( object.name == "Z" ) {
					quaternionZ.setFromAxisAngle( unitZ, Math.atan2( eye.y, eye.x ) );
					tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionZ );
					object.quaternion.copy( tempQuaternion );
				}
A
Aleksandar Rodic 已提交
441

442
			}
A
Aleksandar Rodic 已提交
443 444
		}

445 446
	}

447
	this.init();
A
Aleksandar Rodic 已提交
448

449
}
A
Aleksandar Rodic 已提交
450

451
THREE.TransformGizmoRotate.prototype = Object.create( THREE.TransformGizmo.prototype );
A
Aleksandar Rodic 已提交
452

453
THREE.TransformGizmoScale = function () {
A
Aleksandar Rodic 已提交
454

455
	THREE.TransformGizmo.call( this );
A
Aleksandar Rodic 已提交
456

457 458 459 460 461 462
	var arrowGeometry = new THREE.CylinderGeometry( 0.005, 0.005, 1, 4, 1, false );
	var mesh = new THREE.Mesh( new THREE.CubeGeometry( 0.125, 0.125, 0.125 ) );
	mesh.position.y = 0.5;
	THREE.GeometryUtils.merge( arrowGeometry, mesh );

	this.handleGizmos = {
A
Aleksandar Rodic 已提交
463

464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480
		XYZ: [
			new THREE.Mesh( new THREE.CubeGeometry( 0.125, 0.125, 0.125 ), new THREE.TransformGizmoMaterial( { color: "white", opacity: 0.25 } ) )
		],
		X: [
			new THREE.Mesh( arrowGeometry, new THREE.TransformGizmoMaterial( { color: "red" } ) ),
			new THREE.Vector3( 0.5, 0, 0 ),
			new THREE.Vector3( 0, 0, -Math.PI/2 )
		],
		Y: [
			new THREE.Mesh( arrowGeometry, new THREE.TransformGizmoMaterial( { color: "green" } ) ),
			new THREE.Vector3( 0, 0.5, 0 )
		],
		Z: [
			new THREE.Mesh( arrowGeometry, new THREE.TransformGizmoMaterial( { color: "blue" } ) ),
			new THREE.Vector3( 0, 0, 0.5 ),
			new THREE.Vector3( Math.PI/2, 0, 0 )
		]
A
Aleksandar Rodic 已提交
481

482
	}
A
Aleksandar Rodic 已提交
483

484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500
	this.pickerGizmos = {

		X: [
			new THREE.Mesh( new THREE.CylinderGeometry( 0.125, 0, 1, 4, 1, false ), new THREE.TransformGizmoMaterial( { color: "red", opacity: 0.25 } ) ),
			new THREE.Vector3( 0.6, 0, 0 ),
			new THREE.Vector3( Math.PI/4, 0, -Math.PI/2 )
		],
		Y: [
			new THREE.Mesh( new THREE.CylinderGeometry( 0.125, 0, 1, 4, 1, false ), new THREE.TransformGizmoMaterial( { color: "green", opacity: 0.25 } ) ),
			new THREE.Vector3( 0, 0.6, 0 ),
			new THREE.Vector3( 0, Math.PI/4, 0 )
		],
		Z: [
			new THREE.Mesh( new THREE.CylinderGeometry( 0.125, 0, 1, 4, 1, false ), new THREE.TransformGizmoMaterial( { color: "blue", opacity: 0.25 } ) ),
			new THREE.Vector3( 0, 0, 0.6 ),
			new THREE.Vector3( Math.PI/2, Math.PI/4, 0 )
		]
A
Aleksandar Rodic 已提交
501

502 503 504 505 506 507
	}

	this.setActivePlane = function ( axis, eye ) {

		var tempMatrix = new THREE.Matrix4();
		eye.applyProjection( tempMatrix.getInverse( tempMatrix.extractRotation( this.planes[ "XY" ].matrixWorld ) ) );
A
Aleksandar Rodic 已提交
508

509 510 511
		if ( axis == "X" ) {
			this.activePlane = this.planes[ "XY" ];
			if ( Math.abs(eye.y) > Math.abs(eye.z) ) this.activePlane = this.planes[ "XZ" ];
512
		}
A
Aleksandar Rodic 已提交
513

514 515 516 517
		if ( axis == "Y" ){
			this.activePlane = this.planes[ "XY" ];
			if ( Math.abs(eye.x) > Math.abs(eye.z) ) this.activePlane = this.planes[ "YZ" ];
		}
A
Aleksandar Rodic 已提交
518

519 520 521 522
		if ( axis == "Z" ){
			this.activePlane = this.planes[ "XZ" ];
			if ( Math.abs(eye.x) > Math.abs(eye.y) ) this.activePlane = this.planes[ "YZ" ];
		}
523

524
		if ( axis == "XYZ" ) this.activePlane = this.planes[ "XYZE" ];
A
Aleksandar Rodic 已提交
525

526
		this.hide();
527
		this.show();
A
Aleksandar Rodic 已提交
528

529
	}
A
Aleksandar Rodic 已提交
530

531
	this.init();
A
Aleksandar Rodic 已提交
532

533
}
534

535 536 537
THREE.TransformGizmoScale.prototype = Object.create( THREE.TransformGizmo.prototype );

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

539 540
	// TODO: Make non-uniform scale and rotate play nice in hierarchies
	// TODO: ADD RXYZ contol
A
Aleksandar Rodic 已提交
541

542
	THREE.Object3D.call( this );
543

544
	domElement = ( domElement !== undefined ) ? domElement : document;
A
Aleksandar Rodic 已提交
545

546 547 548 549
	this.gizmo = {}
	this.gizmo["translate"] = new THREE.TransformGizmoTranslate();
	this.gizmo["rotate"] = new THREE.TransformGizmoRotate();
	this.gizmo["scale"] = new THREE.TransformGizmoScale();
A
Aleksandar Rodic 已提交
550

551 552 553
	this.add(this.gizmo["translate"]);
	this.add(this.gizmo["rotate"]);
	this.add(this.gizmo["scale"]);
A
Aleksandar Rodic 已提交
554

555 556 557
	this.gizmo["translate"].hide();
	this.gizmo["rotate"].hide();
	this.gizmo["scale"].hide();
A
Aleksandar Rodic 已提交
558

559
	this.object = false;
560 561 562
	this.snap = false;
	this.space = "world";
	this.size = 1;
563
	this.axis = false;
A
Aleksandar Rodic 已提交
564

565 566
	var scope = this;
	
567
	var _dragging = false;
568 569
	var _mode = "translate";
	var _plane = "XY";
570

571
	var changeEvent = { type: "change" };
572

573 574 575
	var ray = new THREE.Raycaster();
	var projector = new THREE.Projector();
	var pointerVector = new THREE.Vector3();
576

577 578
	var point = new THREE.Vector3();
	var offset = new THREE.Vector3();
579

580 581 582
	var rotation = new THREE.Vector3();
	var offsetRotation = new THREE.Vector3();
	var scale = 1;
583

584 585
	var lookAtMatrix = new THREE.Matrix4();
	var eye = new THREE.Vector3()
586

587 588 589 590 591 592
	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 );
A
Aleksandar Rodic 已提交
593

594 595 596 597 598
	var quaternionXYZ = new THREE.Quaternion();
	var quaternionX = new THREE.Quaternion();
	var quaternionY = new THREE.Quaternion();
	var quaternionZ = new THREE.Quaternion();
	var quaternionE = new THREE.Quaternion();
A
Aleksandar Rodic 已提交
599

600 601 602
	var oldPosition = new THREE.Vector3();
	var oldScale = new THREE.Vector3();
	var oldRotationMatrix = new THREE.Matrix4();
A
Aleksandar Rodic 已提交
603

604 605
	var parentRotationMatrix  = new THREE.Matrix4();
	var parentScale = new THREE.Vector3();
606

607 608 609 610 611
	var worldPosition = new THREE.Vector3();
	var worldRotation = new THREE.Euler();
	var worldRotationMatrix  = new THREE.Matrix4();
	var camPosition = new THREE.Vector3();
	var camRotation = new THREE.Euler();
612

613 614 615 616 617 618 619 620 621 622 623 624 625 626 627
	domElement.addEventListener( "mousedown", onPointerDown, false );
	domElement.addEventListener( "touchstart", onPointerDown, false );

	domElement.addEventListener( "mousemove", onPointerHover, false );
	domElement.addEventListener( "touchmove", onPointerHover, false );

	domElement.addEventListener( "mousemove", onPointerMove, false );
	domElement.addEventListener( "touchmove", onPointerMove, false );

	domElement.addEventListener( "mouseup", onPointerUp, false );
	domElement.addEventListener( "mouseout", onPointerUp, false );
	domElement.addEventListener( "touchend", onPointerUp, false );
	domElement.addEventListener( "touchcancel", onPointerUp, false );
	domElement.addEventListener( "touchleave", onPointerUp, false );

628
	this.attach = function ( object ) {
629

630
		scope.object = object;
631

632 633 634 635
	 	this.gizmo["translate"].hide();
	 	this.gizmo["rotate"].hide();
	 	this.gizmo["scale"].hide();
	 	this.gizmo[_mode].show();
636

637
	 	scope.dispatchEvent( changeEvent );
638
	 	scope.update();
A
Aleksandar Rodic 已提交
639

640
	}
A
Aleksandar Rodic 已提交
641

642
	this.detach = function ( object ) {
A
Aleksandar Rodic 已提交
643

644 645
		scope.object = false;
		this.axis = false;
A
Aleksandar Rodic 已提交
646

647 648 649
	 	this.gizmo["translate"].hide();
	 	this.gizmo["rotate"].hide();
	 	this.gizmo["scale"].hide();
A
Aleksandar Rodic 已提交
650

651
	}
A
Aleksandar Rodic 已提交
652

653
	this.setMode = function ( mode ) {
A
Aleksandar Rodic 已提交
654

655
		_mode = mode ? mode : _mode;
A
Aleksandar Rodic 已提交
656

657
		if ( _mode == "scale" ) scope.space = "local";
A
Aleksandar Rodic 已提交
658

659 660 661 662
	 	this.gizmo["translate"].hide();
	 	this.gizmo["rotate"].hide();
	 	this.gizmo["scale"].hide();	
	 	this.gizmo[_mode].show();
A
Aleksandar Rodic 已提交
663

664
	 	scope.dispatchEvent( changeEvent );
665
		this.update();
A
Aleksandar Rodic 已提交
666

667
	}
A
Aleksandar Rodic 已提交
668

669
	this.setSnap = function ( snap ) {
A
Aleksandar Rodic 已提交
670

671
		scope.snap = snap;
A
Aleksandar Rodic 已提交
672

673
	}
A
Aleksandar Rodic 已提交
674

675
	this.setSize = function ( size ) {
A
Aleksandar Rodic 已提交
676

677 678
		scope.size = size;
	 	scope.dispatchEvent( changeEvent );
679
		this.update();
680 681
	 	
	}
682

683
	this.setSpace = function ( space ) {
684

685
		scope.space = space;
A
Aleksandar Rodic 已提交
686

687
	 	scope.dispatchEvent( changeEvent );
688
		this.update();
689

690
	}
A
Aleksandar Rodic 已提交
691

692
	this.update = function () {
693

694
		if ( !scope.object ) return;
695

696 697 698
		scope.object.updateMatrixWorld();
		worldPosition.getPositionFromMatrix( scope.object.matrixWorld );
		worldRotation.setFromRotationMatrix( tempMatrix.extractRotation( scope.object.matrixWorld ) );
699

700 701 702
		camera.updateMatrixWorld();
		camPosition.getPositionFromMatrix( camera.matrixWorld );
		camRotation.setFromRotationMatrix( tempMatrix.extractRotation( camera.matrixWorld ) );
703

704 705 706
		scale = worldPosition.distanceTo( camPosition ) / 6 * scope.size;
		this.position.copy( worldPosition )
		this.scale.set( scale, scale, scale );
707

708
		eye.copy( camPosition ).sub( worldPosition ).normalize();
709

710 711
		if ( scope.space == "local" )
			this.gizmo[_mode].update( worldRotation, eye );
712

713 714
		else if ( scope.space == "world" )
			this.gizmo[_mode].update( new THREE.Euler(), eye );
715

716
		this.gizmo[_mode].highlight( scope.axis );
717

718
	}
719

720
	function onPointerHover( event ) {
721

722
		if ( !scope.object || _dragging ) return;
723

724 725
		event.preventDefault();
		event.stopPropagation();
726

727
		var pointer = event.touches? event.touches[0] : event;
728

729
		var intersect = intersectObjects( pointer, scope.gizmo[_mode].pickers.children );
730

731
		if ( intersect ) {
732

733 734 735
			scope.axis = intersect.object.name;
			scope.dispatchEvent( changeEvent );
			scope.update();
736

737
		} else {
738

739 740 741
			scope.axis = false;
			scope.dispatchEvent( changeEvent );
			scope.update();
742 743 744 745 746

		}

	};

747 748 749
	function onPointerDown( event ) {

		if ( !scope.object || _dragging ) return;
A
Aleksandar Rodic 已提交
750 751

		event.preventDefault();
752 753 754
		event.stopPropagation();

		var pointer = event.touches? event.touches[0] : event;
A
Aleksandar Rodic 已提交
755

756
		if ( pointer.button === 0 || pointer.button == undefined ) {
A
Aleksandar Rodic 已提交
757

758
			var intersect = intersectObjects( pointer, scope.gizmo[_mode].pickers.children );
A
Aleksandar Rodic 已提交
759

A
Aleksandar Rodic 已提交
760
			if ( intersect ) {
A
Aleksandar Rodic 已提交
761

762
				scope.axis = intersect.object.name;
A
Aleksandar Rodic 已提交
763

764
				scope.update();
A
Aleksandar Rodic 已提交
765

766 767
				eye.copy( camPosition ).sub( worldPosition ).normalize();

768
				scope.gizmo[_mode].setActivePlane( scope.axis, eye );
769

770
				var planeIntersect = intersectObjects( pointer, [scope.gizmo[_mode].activePlane] );
A
Aleksandar Rodic 已提交
771

A
Aleksandar Rodic 已提交
772 773
				if ( planeIntersect ) {

774 775
					oldPosition.copy( scope.object.position );
					oldScale.copy( scope.object.scale );
A
Aleksandar Rodic 已提交
776

777 778
					oldRotationMatrix.extractRotation( scope.object.matrix );
					worldRotationMatrix.extractRotation( scope.object.matrixWorld );
A
Aleksandar Rodic 已提交
779

780 781
					parentRotationMatrix.extractRotation( scope.object.parent.matrixWorld );
					parentScale.getScaleFromMatrix( tempMatrix.getInverse( scope.object.parent.matrixWorld ) );
A
Aleksandar Rodic 已提交
782

A
Aleksandar Rodic 已提交
783 784 785
					offset.copy( planeIntersect.point );

				}
A
Aleksandar Rodic 已提交
786 787 788 789 790

			}

		}

791
		_dragging = true;
A
Aleksandar Rodic 已提交
792 793 794

	};

795
	function onPointerMove( event ) {
A
Aleksandar Rodic 已提交
796

797
		if ( !scope.object || !scope.axis || !_dragging ) return;
A
Aleksandar Rodic 已提交
798

799 800
		event.preventDefault();
		event.stopPropagation();
A
Aleksandar Rodic 已提交
801

802
		var pointer = event.touches? event.touches[0] : event;
A
Aleksandar Rodic 已提交
803

804
		var planeIntersect = intersectObjects( pointer, [scope.gizmo[_mode].activePlane] );
A
Aleksandar Rodic 已提交
805

806
		if ( planeIntersect ) {
807

808
			point.copy( planeIntersect.point );
A
Aleksandar Rodic 已提交
809

810
			if ( _mode == "translate" ) {
A
Aleksandar Rodic 已提交
811

812 813 814 815
				point.sub( offset );
				point.multiply(parentScale);

				if ( scope.space == "local" ) {
A
Aleksandar Rodic 已提交
816

817
					point.applyMatrix4( tempMatrix.getInverse( worldRotationMatrix ) );
A
Aleksandar Rodic 已提交
818

819 820 821
					if ( scope.axis.search("X") == -1 ) point.x = 0;
					if ( scope.axis.search("Y") == -1 ) point.y = 0;
					if ( scope.axis.search("Z") == -1 ) point.z = 0;
A
Aleksandar Rodic 已提交
822

823
					point.applyMatrix4( oldRotationMatrix );
A
Aleksandar Rodic 已提交
824

825 826
					scope.object.position.copy( oldPosition );
					scope.object.position.add( point );
A
Aleksandar Rodic 已提交
827

828
				} 
A
Aleksandar Rodic 已提交
829

830
				if ( scope.space == "world" || scope.axis.search("XYZ") != -1 ) {
A
Aleksandar Rodic 已提交
831

832 833 834
					if ( scope.axis.search("X") == -1 ) point.x = 0;
					if ( scope.axis.search("Y") == -1 ) point.y = 0;
					if ( scope.axis.search("Z") == -1 ) point.z = 0;
A
Aleksandar Rodic 已提交
835

836
					point.applyMatrix4( tempMatrix.getInverse( parentRotationMatrix ) );
837

838 839
					scope.object.position.copy( oldPosition );
					scope.object.position.add( point );
840

841
					if ( scope.snap ) {
A
Aleksandar Rodic 已提交
842

843 844 845 846
						if ( scope.axis.search("X") != -1 ) scope.object.position.x = Math.round( scope.object.position.x / scope.snap ) * scope.snap;
						if ( scope.axis.search("Y") != -1 ) scope.object.position.y = Math.round( scope.object.position.y / scope.snap ) * scope.snap;
						if ( scope.axis.search("Z") != -1 ) scope.object.position.z = Math.round( scope.object.position.z / scope.snap ) * scope.snap;
					
A
Aleksandar Rodic 已提交
847 848
					}

849
				}
A
Aleksandar Rodic 已提交
850

851
			} else if ( _mode == "scale" ) {
A
Aleksandar Rodic 已提交
852

853 854
				point.sub( offset );
				point.multiply(parentScale);
A
Aleksandar Rodic 已提交
855

856
				if ( scope.space == "local" ) {
857

858
					if ( scope.axis == "XYZ") {
A
Aleksandar Rodic 已提交
859

860
						scale = 1 + ( ( point.y ) / 50 );
A
Aleksandar Rodic 已提交
861

862 863 864
						scope.object.scale.x = oldScale.x * scale;
						scope.object.scale.y = oldScale.y * scale;
						scope.object.scale.z = oldScale.z * scale;
865

866
					} else {
A
Aleksandar Rodic 已提交
867

868
						point.applyMatrix4( tempMatrix.getInverse( worldRotationMatrix ) );
A
Aleksandar Rodic 已提交
869

870 871 872
						if ( scope.axis == "X" ) scope.object.scale.x = oldScale.x * ( 1 + point.x / 50 );
						if ( scope.axis == "Y" ) scope.object.scale.y = oldScale.y * ( 1 + point.y / 50 );
						if ( scope.axis == "Z" ) scope.object.scale.z = oldScale.z * ( 1 + point.z / 50 );
A
Aleksandar Rodic 已提交
873

A
Aleksandar Rodic 已提交
874
					}
A
Aleksandar Rodic 已提交
875

876
				}
A
Aleksandar Rodic 已提交
877

878
			} else if ( _mode == "rotate" ) {
A
Aleksandar Rodic 已提交
879

880 881 882 883
				point.sub( worldPosition );
				point.multiply(parentScale);
				tempVector.copy(offset).sub( worldPosition );
				tempVector.multiply(parentScale);
A
Aleksandar Rodic 已提交
884

885
				if ( scope.axis == "E" ) {
A
Aleksandar Rodic 已提交
886

887 888
					point.applyMatrix4( tempMatrix.getInverse( lookAtMatrix ) );
					tempVector.applyMatrix4( tempMatrix.getInverse( lookAtMatrix ) );
A
Aleksandar Rodic 已提交
889

890 891
					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 已提交
892

893
					tempQuaternion.setFromRotationMatrix( tempMatrix.getInverse( parentRotationMatrix ) );
A
Aleksandar Rodic 已提交
894

895 896
					quaternionE.setFromAxisAngle( eye, rotation.z - offsetRotation.z );
					quaternionXYZ.setFromRotationMatrix( worldRotationMatrix );
897

898 899
					tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionE );
					tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionXYZ );
A
Aleksandar Rodic 已提交
900

901
					scope.object.quaternion.copy( tempQuaternion );
902

903
				} else if ( scope.axis == "XYZE" ) {
A
Aleksandar Rodic 已提交
904

905
					quaternionE.setFromEuler( point.clone().cross(tempVector).normalize() ); // rotation axis
906

907 908 909
					tempQuaternion.setFromRotationMatrix( tempMatrix.getInverse( parentRotationMatrix ) );
					quaternionX.setFromAxisAngle( quaternionE, - point.clone().angleTo(tempVector) );
					quaternionXYZ.setFromRotationMatrix( worldRotationMatrix );
910

911 912
					tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionX );
					tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionXYZ );
A
Aleksandar Rodic 已提交
913

914
					scope.object.quaternion.copy( tempQuaternion );
A
Aleksandar Rodic 已提交
915

916
				} else if ( scope.space == "local" ) {
A
Aleksandar Rodic 已提交
917

918
					point.applyMatrix4( tempMatrix.getInverse( worldRotationMatrix ) );
A
Aleksandar Rodic 已提交
919

920
					tempVector.applyMatrix4( tempMatrix.getInverse( worldRotationMatrix ) );
A
Aleksandar Rodic 已提交
921

922 923
					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 已提交
924

925 926 927 928
					quaternionXYZ.setFromRotationMatrix( oldRotationMatrix );
					quaternionX.setFromAxisAngle( unitX, rotation.x - offsetRotation.x );
					quaternionY.setFromAxisAngle( unitY, rotation.y - offsetRotation.y );
					quaternionZ.setFromAxisAngle( unitZ, rotation.z - offsetRotation.z );
929

930 931 932
					if ( scope.axis == "X" ) quaternionXYZ.multiplyQuaternions( quaternionXYZ, quaternionX );
					if ( scope.axis == "Y" ) quaternionXYZ.multiplyQuaternions( quaternionXYZ, quaternionY );
					if ( scope.axis == "Z" ) quaternionXYZ.multiplyQuaternions( quaternionXYZ, quaternionZ );
A
Aleksandar Rodic 已提交
933

934
					scope.object.quaternion.copy( quaternionXYZ );
A
Aleksandar Rodic 已提交
935

936
				} else if ( scope.space == "world" ) {
A
Aleksandar Rodic 已提交
937

938 939
					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 已提交
940

941
					tempQuaternion.setFromRotationMatrix( tempMatrix.getInverse( parentRotationMatrix ) );
A
Aleksandar Rodic 已提交
942

943 944 945 946
					quaternionX.setFromAxisAngle( unitX, rotation.x - offsetRotation.x );
					quaternionY.setFromAxisAngle( unitY, rotation.y - offsetRotation.y );
					quaternionZ.setFromAxisAngle( unitZ, rotation.z - offsetRotation.z );
					quaternionXYZ.setFromRotationMatrix( worldRotationMatrix );
A
Aleksandar Rodic 已提交
947

948 949 950
					if ( scope.axis == "X" ) tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionX );
					if ( scope.axis == "Y" ) tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionY );
					if ( scope.axis == "Z" ) tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionZ );
951

952
					tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionXYZ );
A
Aleksandar Rodic 已提交
953

954
					scope.object.quaternion.copy( tempQuaternion );
A
Aleksandar Rodic 已提交
955 956 957 958 959

				}

			}

960
		}
A
Aleksandar Rodic 已提交
961

962 963
		scope.dispatchEvent( changeEvent );
		scope.update();
A
Aleksandar Rodic 已提交
964

965
	}
A
Aleksandar Rodic 已提交
966

967
	function onPointerUp( event ) {
A
Aleksandar Rodic 已提交
968

969 970 971 972
		scope.axis = false;
		_dragging = false;
		scope.dispatchEvent( changeEvent );
		scope.update();
A
Aleksandar Rodic 已提交
973 974 975

	}

976
	function intersectObjects( pointer, objects ) {
A
Aleksandar Rodic 已提交
977

978
	    var rect = domElement.getBoundingClientRect();
979 980
	    var x = (pointer.clientX - rect.left) / rect.width;
	    var y = (pointer.clientY - rect.top) / rect.height;
981
		pointerVector.set( ( x ) * 2 - 1, - ( y ) * 2 + 1, 0.5 );
A
Aleksandar Rodic 已提交
982

983
		projector.unprojectVector( pointerVector, camera );
A
Aleksandar Rodic 已提交
984
		ray.set( camPosition, pointerVector.sub( camPosition ).normalize() );
985

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

A
Aleksandar Rodic 已提交
989 990 991 992
	}

};

993
THREE.TransformControls.prototype = Object.create( THREE.Object3D.prototype );