TransformControls.js 29.1 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
	this.handleGizmos = {
		X: [
26
			new THREE.Mesh( new THREE.CylinderGeometry( 0.005, 0.005, 1, 4, 1, false ), new THREE.TransformGizmoMaterial( { color: 0xff0000 } ) ),
27 28 29 30
			new THREE.Vector3( 0.5, 0, 0 ),
			new THREE.Vector3( 0, 0, -Math.PI/2 )
		],
		Y: [
31
			new THREE.Mesh( new THREE.CylinderGeometry( 0.005, 0.005, 1, 4, 1, false ), new THREE.TransformGizmoMaterial( { color: 0x00ff00 } ) ),
32 33 34
			new THREE.Vector3( 0, 0.5, 0 )
		],
		Z: [
35
			new THREE.Mesh( new THREE.CylinderGeometry( 0.005, 0.005, 1, 4, 1, false ), new THREE.TransformGizmoMaterial( { color: 0x0000ff } ) ),
36 37 38 39
			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
	this.activePlane = undefined;
44

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

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

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

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

57
		//// PLANES
58

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

63 64 65 66 67 68
		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 已提交
69

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

73 74 75 76 77 78
		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 已提交
79

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

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

84 85 86 87 88 89
			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 );
90

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

93 94 95 96 97
				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 {
98

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

			}

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

		}

108 109 110 111 112 113 114 115 116 117 118 119 120
		// 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 );

			}
		});
121 122 123

	}

124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
	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 已提交
140 141
		}

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

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

A
Aleksandar Rodic 已提交
146 147
		}

148
		if ( this.activePlane !== undefined ) this.activePlane.visible = showActivePlane;
149 150 151 152 153 154 155 156 157 158 159

	}

	this.highlight = function ( axis ) {

		var handle;

		for ( var i in this.handleGizmos ) {

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

160
			if ( handle.material.oldColor !== undefined ) {
161 162 163 164

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

A
Aleksandar Rodic 已提交
165 166 167 168
			}

		}

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

173 174 175 176 177
			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 已提交
178

179
		}
A
Aleksandar Rodic 已提交
180

181
	}
A
Aleksandar Rodic 已提交
182

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

185
}
186

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

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

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

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

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

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

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

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

			} else {

				object.quaternion.setFromEuler( rotation );

			}

		}
A
Aleksandar Rodic 已提交
212 213 214

	}

215 216 217 218 219 220 221 222 223 224 225 226 227 228
}

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: [
229
			new THREE.Mesh( arrowGeometry, new THREE.TransformGizmoMaterial( { color: 0xff0000 } ) ),
230 231 232 233
			new THREE.Vector3( 0.5, 0, 0 ),
			new THREE.Vector3( 0, 0, -Math.PI/2 )
		],
		Y: [
234
			new THREE.Mesh( arrowGeometry, new THREE.TransformGizmoMaterial( { color: 0x00ff00 } ) ),
235 236 237
			new THREE.Vector3( 0, 0.5, 0 )
		],
		Z: [
238
			new THREE.Mesh( arrowGeometry, new THREE.TransformGizmoMaterial( { color: 0x0000ff } ) ),
239 240 241 242
			new THREE.Vector3( 0, 0, 0.5 ),
			new THREE.Vector3( Math.PI/2, 0, 0 )
		],
		XYZ: [
243
			new THREE.Mesh( new THREE.OctahedronGeometry( 0.1, 0 ), new THREE.TransformGizmoMaterial( { color: 0xffffff, opacity: 0.25 } ) )
244 245
		],
		XY: [
246
			new THREE.Mesh( new THREE.PlaneGeometry( 0.29, 0.29 ), new THREE.TransformGizmoMaterial( { color: 0xffff00, opacity: 0.25 } ) ),
247 248 249
			new THREE.Vector3( 0.15, 0.15, 0 )
		],
		YZ: [
250
			new THREE.Mesh( new THREE.PlaneGeometry( 0.29, 0.29 ), new THREE.TransformGizmoMaterial( { color: 0x00ffff, opacity: 0.25 } ) ),
251 252 253 254
			new THREE.Vector3( 0, 0.15, 0.15 ),
			new THREE.Vector3( 0, Math.PI/2, 0 )
		],
		XZ: [
255
			new THREE.Mesh( new THREE.PlaneGeometry( 0.29, 0.29 ), new THREE.TransformGizmoMaterial( { color: 0xff00ff, opacity: 0.25 } ) ),
256
			new THREE.Vector3( 0.15, 0, 0.15 ),
257
			new THREE.Vector3( -Math.PI/2, 0, 0 )
258
		]
A
Aleksandar Rodic 已提交
259

260
	}
261

262 263 264
	this.pickerGizmos = {

		X: [
265
			new THREE.Mesh( new THREE.CylinderGeometry( 0.2, 0, 1, 4, 1, false ), new THREE.TransformGizmoMaterial( { color: 0xff0000, opacity: 0.25 } ) ),
266 267 268 269
			new THREE.Vector3( 0.6, 0, 0 ),
			new THREE.Vector3( 0, 0, -Math.PI/2 )
		],
		Y: [
270
			new THREE.Mesh( new THREE.CylinderGeometry( 0.2, 0, 1, 4, 1, false ), new THREE.TransformGizmoMaterial( { color: 0x00ff00, opacity: 0.25 } ) ),
271 272 273
			new THREE.Vector3( 0, 0.6, 0 )
		],
		Z: [
274
			new THREE.Mesh( new THREE.CylinderGeometry( 0.2, 0, 1, 4, 1, false ), new THREE.TransformGizmoMaterial( { color: 0x0000ff, opacity: 0.25 } ) ),
275 276
			new THREE.Vector3( 0, 0, 0.6 ),
			new THREE.Vector3( Math.PI/2, 0, 0 )
A
Aleksandar Rodic 已提交
277 278
		],
		XYZ: [
279
			new THREE.Mesh( new THREE.OctahedronGeometry( 0.2, 0 ), new THREE.TransformGizmoMaterial( { color: 0xffffff, opacity: 0.25 } ) )
A
Aleksandar Rodic 已提交
280 281
		],
		XY: [
282
			new THREE.Mesh( new THREE.PlaneGeometry( 0.4, 0.4 ), new THREE.TransformGizmoMaterial( { color: 0xffff00, opacity: 0.25 } ) ),
A
Aleksandar Rodic 已提交
283 284 285
			new THREE.Vector3( 0.2, 0.2, 0 )
		],
		YZ: [
286
			new THREE.Mesh( new THREE.PlaneGeometry( 0.4, 0.4 ), new THREE.TransformGizmoMaterial( { color: 0x00ffff, opacity: 0.25 } ) ),
A
Aleksandar Rodic 已提交
287 288 289 290
			new THREE.Vector3( 0, 0.2, 0.2 ),
			new THREE.Vector3( 0, Math.PI/2, 0 )
		],
		XZ: [
291
			new THREE.Mesh( new THREE.PlaneGeometry( 0.4, 0.4 ), new THREE.TransformGizmoMaterial( { color: 0xff00ff, opacity: 0.25 } ) ),
A
Aleksandar Rodic 已提交
292 293
			new THREE.Vector3( 0.2, 0, 0.2 ),
			new THREE.Vector3( -Math.PI/2, 0, 0 )
294
		]
A
Aleksandar Rodic 已提交
295

296
	}
A
Aleksandar Rodic 已提交
297

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

300 301
		var tempMatrix = new THREE.Matrix4();
		eye.applyProjection( tempMatrix.getInverse( tempMatrix.extractRotation( this.planes[ "XY" ].matrixWorld ) ) );
302

303 304 305 306 307 308 309 310 311
		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 已提交
312

313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
		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 已提交
328

329
	}
A
Aleksandar Rodic 已提交
330

331
	this.init();
A
Aleksandar Rodic 已提交
332

333
}
334

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

337
THREE.TransformGizmoRotate = function () {
A
Aleksandar Rodic 已提交
338

339
	THREE.TransformGizmo.call( this );
A
Aleksandar Rodic 已提交
340

341
	this.handleGizmos = {
342

343
		X: [
344
			new THREE.Mesh( new THREE.TorusGeometry( 1, 0.005, 4, 32, Math.PI ), new THREE.TransformGizmoMaterial( { color: 0xff0000 } ) ),
345 346 347 348
			new THREE.Vector3( 0, 0, 0 ),
			new THREE.Vector3( 0, -Math.PI/2, -Math.PI/2 )
		],
		Y: [
349
			new THREE.Mesh( new THREE.TorusGeometry( 1, 0.005, 4, 32, Math.PI ), new THREE.TransformGizmoMaterial( { color: 0x00ff00 } ) ),
350 351 352 353
			new THREE.Vector3( 0, 0, 0 ),
			new THREE.Vector3( Math.PI/2, 0, 0 )
		],
		Z: [
354
			new THREE.Mesh( new THREE.TorusGeometry( 1, 0.005, 4, 32, Math.PI ), new THREE.TransformGizmoMaterial( { color: 0x0000ff } ) ),
355 356 357 358
			new THREE.Vector3( 0, 0, 0 ),
			new THREE.Vector3( 0, 0, -Math.PI/2 )
		],
		E: [
359
			new THREE.Mesh( new THREE.TorusGeometry( 1.25, 0.005, 4, 64 ), new THREE.TransformGizmoMaterial( { color: 0xffff00, opacity: 0.25 } ) )
360 361
		],
		XYZE: [
362
			new THREE.Mesh( new THREE.TorusGeometry( 1, 0.005, 4, 64 ), new THREE.TransformGizmoMaterial( { color: 0x787878 } ) )
363
		]
364

365 366 367 368 369
	}

	this.pickerGizmos = {

		X: [
370
			new THREE.Mesh( new THREE.TorusGeometry( 1, 0.12, 4, 12, Math.PI ), new THREE.TransformGizmoMaterial( { color: 0xff0000, opacity: 0.25 } ) ),
371 372 373 374
			new THREE.Vector3( 0, 0, 0 ),
			new THREE.Vector3( 0, -Math.PI/2, -Math.PI/2 )
		],
		Y: [
375
			new THREE.Mesh( new THREE.TorusGeometry( 1, 0.12, 4, 12, Math.PI ), new THREE.TransformGizmoMaterial( { color: 0x00ff00, opacity: 0.25 } ) ),
376 377 378 379
			new THREE.Vector3( 0, 0, 0 ),
			new THREE.Vector3( Math.PI/2, 0, 0 )
		],
		Z: [
380
			new THREE.Mesh( new THREE.TorusGeometry( 1, 0.12, 4, 12, Math.PI ), new THREE.TransformGizmoMaterial( { color: 0x0000ff, opacity: 0.25 } ) ),
381 382 383 384
			new THREE.Vector3( 0, 0, 0 ),
			new THREE.Vector3( 0, 0, -Math.PI/2 )
		],
		E: [
385
			new THREE.Mesh( new THREE.TorusGeometry( 1.25, 0.12, 2, 24 ), new THREE.TransformGizmoMaterial( { color: 0xffff00, opacity: 0.25 } ) )
386 387 388 389
		],
		XYZE: [
			new THREE.Mesh( new THREE.Geometry() ) // TODO
		]
A
Aleksandar Rodic 已提交
390

391
	}
A
Aleksandar Rodic 已提交
392

393
	this.setActivePlane = function ( axis ) {
394

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

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

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

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

403 404
		this.hide();
		this.show();
A
Aleksandar Rodic 已提交
405

406
	}
A
Aleksandar Rodic 已提交
407

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

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

412 413 414 415
		var group = {
			handles: this["handles"],
			pickers: this["pickers"],
		}
A
Aleksandar Rodic 已提交
416

417 418 419 420 421 422 423 424 425 426
		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();
427

428 429
		worldRotation.copy( this.planes["XY"].rotation );
		tempQuaternion.setFromEuler( worldRotation );
430

431 432
		tempMatrix.makeRotationFromQuaternion( tempQuaternion ).getInverse( tempMatrix );
		eye.applyProjection( tempMatrix );
A
Aleksandar Rodic 已提交
433

434
		for ( var i in group ) {
A
Aleksandar Rodic 已提交
435

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

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

440
				tempQuaternion.setFromEuler( worldRotation );
A
Aleksandar Rodic 已提交
441

442 443 444 445
				if ( object.name == "X" ) {
					quaternionX.setFromAxisAngle( unitX, Math.atan2( -eye.y, eye.z ) );
					tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionX );
					object.quaternion.copy( tempQuaternion );
A
Aleksandar Rodic 已提交
446 447
				}

448 449 450 451 452 453 454 455 456 457 458
				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 已提交
459

460
			}
A
Aleksandar Rodic 已提交
461 462
		}

463 464
	}

465
	this.init();
A
Aleksandar Rodic 已提交
466

467
}
A
Aleksandar Rodic 已提交
468

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

471
THREE.TransformGizmoScale = function () {
A
Aleksandar Rodic 已提交
472

473
	THREE.TransformGizmo.call( this );
A
Aleksandar Rodic 已提交
474

475 476 477 478 479 480
	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 已提交
481

482
		X: [
483
			new THREE.Mesh( arrowGeometry, new THREE.TransformGizmoMaterial( { color: 0xff0000 } ) ),
484 485 486 487
			new THREE.Vector3( 0.5, 0, 0 ),
			new THREE.Vector3( 0, 0, -Math.PI/2 )
		],
		Y: [
488
			new THREE.Mesh( arrowGeometry, new THREE.TransformGizmoMaterial( { color: 0x00ff00 } ) ),
489 490 491
			new THREE.Vector3( 0, 0.5, 0 )
		],
		Z: [
492
			new THREE.Mesh( arrowGeometry, new THREE.TransformGizmoMaterial( { color: 0x0000ff } ) ),
493 494
			new THREE.Vector3( 0, 0, 0.5 ),
			new THREE.Vector3( Math.PI/2, 0, 0 )
A
Aleksandar Rodic 已提交
495 496
		],
		XYZ: [
497
			new THREE.Mesh( new THREE.CubeGeometry( 0.125, 0.125, 0.125 ), new THREE.TransformGizmoMaterial( { color: 0xffffff, opacity: 0.25 } ) )
498
		]
A
Aleksandar Rodic 已提交
499

500
	}
A
Aleksandar Rodic 已提交
501

502 503 504
	this.pickerGizmos = {

		X: [
505
			new THREE.Mesh( new THREE.CylinderGeometry( 0.2, 0, 1, 4, 1, false ), new THREE.TransformGizmoMaterial( { color: 0xff0000, opacity: 0.25 } ) ),
506
			new THREE.Vector3( 0.6, 0, 0 ),
A
Aleksandar Rodic 已提交
507
			new THREE.Vector3( 0, 0, -Math.PI/2 )
508 509
		],
		Y: [
510
			new THREE.Mesh( new THREE.CylinderGeometry( 0.2, 0, 1, 4, 1, false ), new THREE.TransformGizmoMaterial( { color: 0x00ff00, opacity: 0.25 } ) ),
A
Aleksandar Rodic 已提交
511
			new THREE.Vector3( 0, 0.6, 0 )
512 513
		],
		Z: [
514
			new THREE.Mesh( new THREE.CylinderGeometry( 0.2, 0, 1, 4, 1, false ), new THREE.TransformGizmoMaterial( { color: 0x0000ff, opacity: 0.25 } ) ),
515
			new THREE.Vector3( 0, 0, 0.6 ),
A
Aleksandar Rodic 已提交
516 517 518
			new THREE.Vector3( Math.PI/2, 0, 0 )
		],
		XYZ: [
519
			new THREE.Mesh( new THREE.CubeGeometry( 0.4, 0.4, 0.4 ), new THREE.TransformGizmoMaterial( { color: 0xffffff, opacity: 0.25 } ) )
520 521 522 523 524 525 526
		]
	}

	this.setActivePlane = function ( axis, eye ) {

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

528 529 530
		if ( axis == "X" ) {
			this.activePlane = this.planes[ "XY" ];
			if ( Math.abs(eye.y) > Math.abs(eye.z) ) this.activePlane = this.planes[ "XZ" ];
531
		}
A
Aleksandar Rodic 已提交
532

533 534 535 536
		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 已提交
537

538 539 540 541
		if ( axis == "Z" ){
			this.activePlane = this.planes[ "XZ" ];
			if ( Math.abs(eye.x) > Math.abs(eye.y) ) this.activePlane = this.planes[ "YZ" ];
		}
542

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

545
		this.hide();
546
		this.show();
A
Aleksandar Rodic 已提交
547

548
	}
A
Aleksandar Rodic 已提交
549

550
	this.init();
A
Aleksandar Rodic 已提交
551

552
}
553

554 555 556
THREE.TransformGizmoScale.prototype = Object.create( THREE.TransformGizmo.prototype );

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

558 559
	// TODO: Make non-uniform scale and rotate play nice in hierarchies
	// TODO: ADD RXYZ contol
A
Aleksandar Rodic 已提交
560

561
	THREE.Object3D.call( this );
562

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

565 566 567 568
	this.gizmo = {}
	this.gizmo["translate"] = new THREE.TransformGizmoTranslate();
	this.gizmo["rotate"] = new THREE.TransformGizmoRotate();
	this.gizmo["scale"] = new THREE.TransformGizmoScale();
A
Aleksandar Rodic 已提交
569

570 571 572
	this.add(this.gizmo["translate"]);
	this.add(this.gizmo["rotate"]);
	this.add(this.gizmo["scale"]);
A
Aleksandar Rodic 已提交
573

574 575 576
	this.gizmo["translate"].hide();
	this.gizmo["rotate"].hide();
	this.gizmo["scale"].hide();
A
Aleksandar Rodic 已提交
577

578
	this.object = undefined;
579 580 581
	this.snap = false;
	this.space = "world";
	this.size = 1;
582
	this.axis = undefined;
A
Aleksandar Rodic 已提交
583

584 585
	var scope = this;
	
586
	var _dragging = false;
587 588
	var _mode = "translate";
	var _plane = "XY";
589

590
	var changeEvent = { type: "change" };
591

592 593 594
	var ray = new THREE.Raycaster();
	var projector = new THREE.Projector();
	var pointerVector = new THREE.Vector3();
595

596 597
	var point = new THREE.Vector3();
	var offset = new THREE.Vector3();
598

599 600 601
	var rotation = new THREE.Vector3();
	var offsetRotation = new THREE.Vector3();
	var scale = 1;
602

603 604
	var lookAtMatrix = new THREE.Matrix4();
	var eye = new THREE.Vector3()
605

606 607 608 609 610 611
	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 已提交
612

613 614 615 616 617
	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 已提交
618

619 620 621
	var oldPosition = new THREE.Vector3();
	var oldScale = new THREE.Vector3();
	var oldRotationMatrix = new THREE.Matrix4();
A
Aleksandar Rodic 已提交
622

623 624
	var parentRotationMatrix  = new THREE.Matrix4();
	var parentScale = new THREE.Vector3();
625

626 627 628 629 630
	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();
631

632 633 634 635 636 637 638 639 640 641 642 643 644 645 646
	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 );

647
	this.attach = function ( object ) {
648

649
		scope.object = object;
650

651 652 653 654
	 	this.gizmo["translate"].hide();
	 	this.gizmo["rotate"].hide();
	 	this.gizmo["scale"].hide();
	 	this.gizmo[_mode].show();
655

656
	 	scope.update();
A
Aleksandar Rodic 已提交
657

658
	}
A
Aleksandar Rodic 已提交
659

660
	this.detach = function ( object ) {
A
Aleksandar Rodic 已提交
661

662 663
		scope.object = undefined;
		this.axis = undefined;
A
Aleksandar Rodic 已提交
664

665 666 667
	 	this.gizmo["translate"].hide();
	 	this.gizmo["rotate"].hide();
	 	this.gizmo["scale"].hide();
A
Aleksandar Rodic 已提交
668

669
	}
A
Aleksandar Rodic 已提交
670

671
	this.setMode = function ( mode ) {
A
Aleksandar Rodic 已提交
672

673
		_mode = mode ? mode : _mode;
A
Aleksandar Rodic 已提交
674

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

677 678 679 680
	 	this.gizmo["translate"].hide();
	 	this.gizmo["rotate"].hide();
	 	this.gizmo["scale"].hide();	
	 	this.gizmo[_mode].show();
A
Aleksandar Rodic 已提交
681

682
		this.update();
683
		scope.dispatchEvent( changeEvent );
A
Aleksandar Rodic 已提交
684

685
	}
A
Aleksandar Rodic 已提交
686

687
	this.setSnap = function ( snap ) {
A
Aleksandar Rodic 已提交
688

689
		scope.snap = snap;
A
Aleksandar Rodic 已提交
690

691
	}
A
Aleksandar Rodic 已提交
692

693
	this.setSize = function ( size ) {
A
Aleksandar Rodic 已提交
694

695
		scope.size = size;
696
		this.update();
697
		scope.dispatchEvent( changeEvent );
698 699
	 	
	}
700

701
	this.setSpace = function ( space ) {
702

703
		scope.space = space;
704
		this.update();
705
		scope.dispatchEvent( changeEvent );
706

707
	}
A
Aleksandar Rodic 已提交
708

709
	this.update = function () {
710

711
		if ( scope.object === undefined ) return;
712

713 714 715
		scope.object.updateMatrixWorld();
		worldPosition.getPositionFromMatrix( scope.object.matrixWorld );
		worldRotation.setFromRotationMatrix( tempMatrix.extractRotation( scope.object.matrixWorld ) );
716

717 718 719
		camera.updateMatrixWorld();
		camPosition.getPositionFromMatrix( camera.matrixWorld );
		camRotation.setFromRotationMatrix( tempMatrix.extractRotation( camera.matrixWorld ) );
720

721 722 723
		scale = worldPosition.distanceTo( camPosition ) / 6 * scope.size;
		this.position.copy( worldPosition )
		this.scale.set( scale, scale, scale );
724

725
		eye.copy( camPosition ).sub( worldPosition ).normalize();
726

727 728
		if ( scope.space == "local" )
			this.gizmo[_mode].update( worldRotation, eye );
729

730 731
		else if ( scope.space == "world" )
			this.gizmo[_mode].update( new THREE.Euler(), eye );
732

733
		this.gizmo[_mode].highlight( scope.axis );
734

735
	}
736

737
	function onPointerHover( event ) {
738

739
		if ( scope.object === undefined || _dragging == true ) return;
740

741
		event.preventDefault();
742

M
Mr.doob 已提交
743
		var pointer = event.touches ? event.touches[ 0 ] : event;
744

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

747
		if ( intersect ) {
748

749 750
			scope.axis = intersect.object.name;
			scope.update();
751
			scope.dispatchEvent( changeEvent );
752

753
		} else if ( scope.axis !== undefined ) {
754

755
			scope.axis = undefined;
756
			scope.update();
757
			scope.dispatchEvent( changeEvent );
758 759 760 761 762

		}

	};

763 764
	function onPointerDown( event ) {

765
		if ( scope.object === undefined || _dragging == true ) return;
A
Aleksandar Rodic 已提交
766 767

		event.preventDefault();
768 769
		event.stopPropagation();

M
Mr.doob 已提交
770
		var pointer = event.touches ? event.touches[ 0 ] : event;
A
Aleksandar Rodic 已提交
771

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

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

A
Aleksandar Rodic 已提交
776
			if ( intersect ) {
A
Aleksandar Rodic 已提交
777

778
				scope.axis = intersect.object.name;
A
Aleksandar Rodic 已提交
779

780
				scope.update();
A
Aleksandar Rodic 已提交
781

782 783
				eye.copy( camPosition ).sub( worldPosition ).normalize();

784
				scope.gizmo[_mode].setActivePlane( scope.axis, eye );
785

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

788 789
				oldPosition.copy( scope.object.position );
				oldScale.copy( scope.object.scale );
A
Aleksandar Rodic 已提交
790

791 792
				oldRotationMatrix.extractRotation( scope.object.matrix );
				worldRotationMatrix.extractRotation( scope.object.matrixWorld );
A
Aleksandar Rodic 已提交
793

794 795
				parentRotationMatrix.extractRotation( scope.object.parent.matrixWorld );
				parentScale.getScaleFromMatrix( tempMatrix.getInverse( scope.object.parent.matrixWorld ) );
A
Aleksandar Rodic 已提交
796

797
				offset.copy( planeIntersect.point );
A
Aleksandar Rodic 已提交
798 799 800 801 802

			}

		}

803
		_dragging = true;
A
Aleksandar Rodic 已提交
804 805 806

	};

807
	function onPointerMove( event ) {
A
Aleksandar Rodic 已提交
808

809
		if ( scope.object === undefined || scope.axis === undefined || _dragging == false ) return;
A
Aleksandar Rodic 已提交
810

811 812
		event.preventDefault();
		event.stopPropagation();
A
Aleksandar Rodic 已提交
813

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

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

818
		point.copy( planeIntersect.point );
A
Aleksandar Rodic 已提交
819

820
		if ( _mode == "translate" ) {
A
Aleksandar Rodic 已提交
821

822 823
			point.sub( offset );
			point.multiply(parentScale);
824

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

827
				point.applyMatrix4( tempMatrix.getInverse( worldRotationMatrix ) );
A
Aleksandar Rodic 已提交
828

829 830 831
				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 已提交
832

833
				point.applyMatrix4( oldRotationMatrix );
A
Aleksandar Rodic 已提交
834

835 836
				scope.object.position.copy( oldPosition );
				scope.object.position.add( point );
A
Aleksandar Rodic 已提交
837

838
			} 
A
Aleksandar Rodic 已提交
839

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

842 843 844
				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;
845

846
				point.applyMatrix4( tempMatrix.getInverse( parentRotationMatrix ) );
847

848 849
				scope.object.position.copy( oldPosition );
				scope.object.position.add( point );
A
Aleksandar Rodic 已提交
850

851
				if ( scope.snap == true ) {
A
Aleksandar Rodic 已提交
852

853 854 855 856
					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;
				
857
				}
A
Aleksandar Rodic 已提交
858

859
			}
A
Aleksandar Rodic 已提交
860

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

863 864
			point.sub( offset );
			point.multiply(parentScale);
865

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

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

870
					scale = 1 + ( ( point.y ) / 50 );
871

872 873 874
					scope.object.scale.x = oldScale.x * scale;
					scope.object.scale.y = oldScale.y * scale;
					scope.object.scale.z = oldScale.z * scale;
A
Aleksandar Rodic 已提交
875

876
				} else {
A
Aleksandar Rodic 已提交
877

878
					point.applyMatrix4( tempMatrix.getInverse( worldRotationMatrix ) );
A
Aleksandar Rodic 已提交
879

880 881 882
					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 已提交
883

884
				}
A
Aleksandar Rodic 已提交
885

886
			}
A
Aleksandar Rodic 已提交
887

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

890 891 892 893
			point.sub( worldPosition );
			point.multiply(parentScale);
			tempVector.copy(offset).sub( worldPosition );
			tempVector.multiply(parentScale);
A
Aleksandar Rodic 已提交
894

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

897 898
				point.applyMatrix4( tempMatrix.getInverse( lookAtMatrix ) );
				tempVector.applyMatrix4( tempMatrix.getInverse( lookAtMatrix ) );
A
Aleksandar Rodic 已提交
899

900 901
				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 已提交
902

903
				tempQuaternion.setFromRotationMatrix( tempMatrix.getInverse( parentRotationMatrix ) );
904

905 906
				quaternionE.setFromAxisAngle( eye, rotation.z - offsetRotation.z );
				quaternionXYZ.setFromRotationMatrix( worldRotationMatrix );
A
Aleksandar Rodic 已提交
907

908 909
				tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionE );
				tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionXYZ );
910

911
				scope.object.quaternion.copy( tempQuaternion );
A
Aleksandar Rodic 已提交
912

913
			} else if ( scope.axis == "XYZE" ) {
914

915
				quaternionE.setFromEuler( point.clone().cross(tempVector).normalize() ); // rotation axis
916

917 918 919
				tempQuaternion.setFromRotationMatrix( tempMatrix.getInverse( parentRotationMatrix ) );
				quaternionX.setFromAxisAngle( quaternionE, - point.clone().angleTo(tempVector) );
				quaternionXYZ.setFromRotationMatrix( worldRotationMatrix );
A
Aleksandar Rodic 已提交
920

921 922
				tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionX );
				tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionXYZ );
A
Aleksandar Rodic 已提交
923

924
				scope.object.quaternion.copy( tempQuaternion );
A
Aleksandar Rodic 已提交
925

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

928
				point.applyMatrix4( tempMatrix.getInverse( worldRotationMatrix ) );
A
Aleksandar Rodic 已提交
929

930
				tempVector.applyMatrix4( tempMatrix.getInverse( worldRotationMatrix ) );
A
Aleksandar Rodic 已提交
931

932 933
				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 ) );
934

935 936 937 938
				quaternionXYZ.setFromRotationMatrix( oldRotationMatrix );
				quaternionX.setFromAxisAngle( unitX, rotation.x - offsetRotation.x );
				quaternionY.setFromAxisAngle( unitY, rotation.y - offsetRotation.y );
				quaternionZ.setFromAxisAngle( unitZ, rotation.z - offsetRotation.z );
A
Aleksandar Rodic 已提交
939

940 941 942
				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 已提交
943

944
				scope.object.quaternion.copy( quaternionXYZ );
A
Aleksandar Rodic 已提交
945

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

948 949
				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 已提交
950

951
				tempQuaternion.setFromRotationMatrix( tempMatrix.getInverse( parentRotationMatrix ) );
A
Aleksandar Rodic 已提交
952

953 954 955 956
				quaternionX.setFromAxisAngle( unitX, rotation.x - offsetRotation.x );
				quaternionY.setFromAxisAngle( unitY, rotation.y - offsetRotation.y );
				quaternionZ.setFromAxisAngle( unitZ, rotation.z - offsetRotation.z );
				quaternionXYZ.setFromRotationMatrix( worldRotationMatrix );
957

958 959 960
				if ( scope.axis == "X" ) tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionX );
				if ( scope.axis == "Y" ) tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionY );
				if ( scope.axis == "Z" ) tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionZ );
A
Aleksandar Rodic 已提交
961

962
				tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionXYZ );
A
Aleksandar Rodic 已提交
963

964
				scope.object.quaternion.copy( tempQuaternion );
A
Aleksandar Rodic 已提交
965 966 967

			}

968
		}
A
Aleksandar Rodic 已提交
969

970
		scope.update();
971
		scope.dispatchEvent( changeEvent );
A
Aleksandar Rodic 已提交
972

973
	}
A
Aleksandar Rodic 已提交
974

975
	function onPointerUp( event ) {
A
Aleksandar Rodic 已提交
976

977
		_dragging = false;
978
		onPointerHover( event );
A
Aleksandar Rodic 已提交
979 980 981

	}

982
	function intersectObjects( pointer, objects ) {
A
Aleksandar Rodic 已提交
983

M
Mr.doob 已提交
984 985 986
		var rect = domElement.getBoundingClientRect();
		var x = (pointer.clientX - rect.left) / rect.width;
		var y = (pointer.clientY - rect.top) / rect.height;
987
		pointerVector.set( ( x ) * 2 - 1, - ( y ) * 2 + 1, 0.5 );
A
Aleksandar Rodic 已提交
988

989
		projector.unprojectVector( pointerVector, camera );
A
Aleksandar Rodic 已提交
990
		ray.set( camPosition, pointerVector.sub( camPosition ).normalize() );
991

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

A
Aleksandar Rodic 已提交
995 996 997 998
	}

};

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