Viewport.js 11.0 KB
Newer Older
M
Mr.doob 已提交
1 2 3 4
/**
 * @author mrdoob / http://mrdoob.com/
 */

5 6 7
var Viewport = function ( editor ) {

	var signals = editor.signals;
M
Mr.doob 已提交
8

M
Mr.doob 已提交
9
	var container = new UI.Panel();
10
	container.setId( 'viewport' );
M
Mr.doob 已提交
11
	container.setPosition( 'absolute' );
M
Mr.doob 已提交
12

M
Mr.doob 已提交
13
	container.add( new Viewport.Info( editor ) );
M
Mr.doob 已提交
14

15 16 17
	var scene = editor.scene;
	var sceneHelpers = editor.sceneHelpers;

M
Mr.doob 已提交
18 19 20 21
	var objects = [];

	// helpers

M
Mr.doob 已提交
22
	var grid = new THREE.GridHelper( 500, 25 );
M
Mr.doob 已提交
23 24
	sceneHelpers.add( grid );

A
Aleksandar Rodic 已提交
25 26
	//

M
Mr.doob 已提交
27
	var camera = editor.camera;
28

A
Aleksandar Rodic 已提交
29
	//
M
Mr.doob 已提交
30

M
Mr.doob 已提交
31
	var selectionBox = new THREE.BoxHelper();
32 33
	selectionBox.material.depthTest = false;
	selectionBox.material.transparent = true;
M
Mr.doob 已提交
34
	selectionBox.visible = false;
35 36
	sceneHelpers.add( selectionBox );

37 38 39
	var objectPositionOnDown = null;
	var objectRotationOnDown = null;
	var objectScaleOnDown = null;
M
Mr.doob 已提交
40

41 42 43
	var transformControls = new THREE.TransformControls( camera, container.dom );
	transformControls.addEventListener( 'change', function () {

M
Mr.doob 已提交
44 45 46 47
		var object = transformControls.object;

		if ( object !== undefined ) {

M
Mr.doob 已提交
48 49
			selectionBox.update( object );

M
Mr.doob 已提交
50 51 52 53 54 55
			if ( editor.helpers[ object.id ] !== undefined ) {

				editor.helpers[ object.id ].update();

			}

56 57
			signals.updateSidebar.dispatch( object );

M
Mr.doob 已提交
58 59
		}

60
		render();
61

62 63
	} );
	transformControls.addEventListener( 'mouseDown', function () {
M
Mr.doob 已提交
64

M
Mr.doob 已提交
65 66
		var object = transformControls.object;

67 68 69
		objectPositionOnDown = object.position.clone();
		objectRotationOnDown = object.rotation.clone();
		objectScaleOnDown = object.scale.clone();
M
Mr.doob 已提交
70

71
		controls.enabled = false;
M
Mr.doob 已提交
72

73
	} );
74
	transformControls.addEventListener( 'mouseUp', function () {
M
Mr.doob 已提交
75

M
Mr.doob 已提交
76 77
		var object = transformControls.object;

78 79 80 81 82 83 84 85
		if ( object != null ) {

			switch ( transformControls.getMode() ) {

				case 'translate':
					if (!objectPositionOnDown.equals(object.position)) {

						editor.execute(new CmdSetPosition( object, object.position, objectPositionOnDown ));
M
Mr.doob 已提交
86

87 88 89 90 91 92
					}
					break;
				case 'rotate':
					if (!objectRotationOnDown.equals(object.rotation)) {

						editor.execute(new CmdSetRotation( object, object.rotation, objectRotationOnDown ));
M
Mr.doob 已提交
93 94

					}
95 96 97
					break;
				case 'scale':
					if (!objectScaleOnDown.equals(object.scale)) {
M
Mr.doob 已提交
98

99 100 101 102 103 104
						editor.execute(new CmdSetScale( object, object.scale, objectScaleOnDown ));

					}
					break;

			}
M
Mr.doob 已提交
105 106 107 108

		}

		signals.objectChanged.dispatch( object );
109
		controls.enabled = true;
110 111

	} );
112

113
	sceneHelpers.add( transformControls );
A
alteredq 已提交
114

M
Mr.doob 已提交
115
	// fog
116

M
Mr.doob 已提交
117 118 119 120 121
	var oldFogType = "None";
	var oldFogColor = 0xaaaaaa;
	var oldFogNear = 1;
	var oldFogFar = 5000;
	var oldFogDensity = 0.00025;
122

123 124
	// object picking

125
	var raycaster = new THREE.Raycaster();
126
	var mouse = new THREE.Vector2();
127

128 129
	// events

M
Mr.doob 已提交
130
	function getIntersects( point, objects ) {
131

132
		mouse.set( ( point.x * 2 ) - 1, - ( point.y * 2 ) + 1 );
133

134
		raycaster.setFromCamera( mouse, camera );
135

136
		return raycaster.intersectObjects( objects );
137 138 139

	};

M
Mr.doob 已提交
140 141 142
	var onDownPosition = new THREE.Vector2();
	var onUpPosition = new THREE.Vector2();
	var onDoubleClickPosition = new THREE.Vector2();
M
Mr.doob 已提交
143

M
Mr.doob 已提交
144
	function getMousePosition( dom, x, y ) {
M
Mr.doob 已提交
145 146 147 148 149

		var rect = dom.getBoundingClientRect();
		return [ ( x - rect.left ) / rect.width, ( y - rect.top ) / rect.height ];

	};
M
Mr.doob 已提交
150

M
Mr.doob 已提交
151
	function handleClick() {
152

M
Mr.doob 已提交
153
		if ( onDownPosition.distanceTo( onUpPosition ) == 0 ) {
154

M
Mr.doob 已提交
155
			var intersects = getIntersects( onUpPosition, objects );
M
Mr.doob 已提交
156

M
Mr.doob 已提交
157
			if ( intersects.length > 0 ) {
M
Mr.doob 已提交
158

M
Mr.doob 已提交
159 160
				var object = intersects[ 0 ].object;

161
				if ( object.userData.object !== undefined ) {
162

163 164
					// helper

165
					editor.select( object.userData.object );
M
Mr.doob 已提交
166

167 168 169
				} else {

					editor.select( object );
170

M
Mr.doob 已提交
171
				}
172

M
Mr.doob 已提交
173 174
			} else {

175
				editor.select( null );
M
Mr.doob 已提交
176

M
Mr.doob 已提交
177
			}
M
Mr.doob 已提交
178

M
Mr.doob 已提交
179
			render();
180

181 182
		}

M
Mr.doob 已提交
183 184
	};

M
Mr.doob 已提交
185
	function onMouseDown( event ) {
M
Mr.doob 已提交
186 187 188 189 190 191 192 193 194 195

		event.preventDefault();

		var array = getMousePosition( container.dom, event.clientX, event.clientY );
		onDownPosition.fromArray( array );

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

	};

M
Mr.doob 已提交
196
	function onMouseUp( event ) {
M
Mr.doob 已提交
197 198 199 200 201 202 203 204 205 206

		var array = getMousePosition( container.dom, event.clientX, event.clientY );
		onUpPosition.fromArray( array );

		handleClick();

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

	};

M
Mr.doob 已提交
207
	function onTouchStart( event ) {
M
Mr.doob 已提交
208 209 210 211 212 213 214 215 216 217

		var touch = event.changedTouches[ 0 ];

		var array = getMousePosition( container.dom, touch.clientX, touch.clientY );
		onDownPosition.fromArray( array );

		document.addEventListener( 'touchend', onTouchEnd, false );

	};

M
Mr.doob 已提交
218
	function onTouchEnd( event ) {
M
Mr.doob 已提交
219 220 221 222 223 224 225 226 227

		var touch = event.changedTouches[ 0 ];

		var array = getMousePosition( container.dom, touch.clientX, touch.clientY );
		onUpPosition.fromArray( array );

		handleClick();

		document.removeEventListener( 'touchend', onTouchEnd, false );
228

229
	};
230

M
Mr.doob 已提交
231
	function onDoubleClick( event ) {
232

M
Mr.doob 已提交
233
		var array = getMousePosition( container.dom, event.clientX, event.clientY );
M
Mr.doob 已提交
234
		onDoubleClickPosition.fromArray( array );
235

M
Mr.doob 已提交
236
		var intersects = getIntersects( onDoubleClickPosition, objects );
237

238
		if ( intersects.length > 0 ) {
239

240 241 242
			var intersect = intersects[ 0 ];

			signals.objectFocused.dispatch( intersect.object );
243

M
Mr.doob 已提交
244
		}
245 246 247

	};

248
	container.dom.addEventListener( 'mousedown', onMouseDown, false );
M
Mr.doob 已提交
249
	container.dom.addEventListener( 'touchstart', onTouchStart, false );
250
	container.dom.addEventListener( 'dblclick', onDoubleClick, false );
251

252 253 254
	// controls need to be added *after* main logic,
	// otherwise controls.enabled doesn't work.

M
Mr.doob 已提交
255
	var controls = new THREE.EditorControls( camera, container.dom );
256
	controls.addEventListener( 'change', function () {
257

258
		transformControls.update();
259
		signals.cameraChanged.dispatch( camera );
260

261
	} );
262

263
	// signals
264

265 266
	signals.editorCleared.add( function () {

267
		controls.center.set( 0, 0, 0 );
268 269 270 271
		render();

	} );

272
	var clearColor;
273

274
	signals.themeChanged.add( function ( value ) {
275

276 277
		switch ( value ) {

M
Mr.doob 已提交
278 279
			case 'css/light.css':
				grid.setColors( 0x444444, 0x888888 );
280
				clearColor = 0xaaaaaa;
M
Mr.doob 已提交
281 282 283
				break;
			case 'css/dark.css':
				grid.setColors( 0xbbbbbb, 0x888888 );
284
				clearColor = 0x333333;
M
Mr.doob 已提交
285
				break;
286 287

		}
288

289
		renderer.setClearColor( clearColor );
290 291 292 293 294

		render();

	} );

M
Mr.doob 已提交
295
	signals.transformModeChanged.add( function ( mode ) {
M
Mr.doob 已提交
296

297
		transformControls.setMode( mode );
A
Aleksandar Rodic 已提交
298 299 300 301 302

	} );

	signals.snapChanged.add( function ( dist ) {

303
		transformControls.setTranslationSnap( dist );
M
Mr.doob 已提交
304 305 306

	} );

307
	signals.spaceChanged.add( function ( space ) {
M
Mr.doob 已提交
308

309
		transformControls.setSpace( space );
M
Mr.doob 已提交
310 311 312

	} );

313 314 315
	signals.rendererChanged.add( function ( newRenderer ) {

		if ( renderer !== null ) {
316

317 318 319
			container.dom.removeChild( renderer.domElement );

		}
320

321
		renderer = newRenderer;
322 323 324 325 326

		renderer.autoClear = false;
		renderer.autoUpdateScene = false;
		renderer.setClearColor( clearColor );
		renderer.setPixelRatio( window.devicePixelRatio );
327
		renderer.setSize( container.dom.offsetWidth, container.dom.offsetHeight );
M
Mr.doob 已提交
328

329
		container.dom.appendChild( renderer.domElement );
M
Mr.doob 已提交
330

331
		render();
M
Mr.doob 已提交
332

333
	} );
334

335 336 337 338 339 340
	signals.sceneGraphChanged.add( function () {

		render();

	} );

341 342
	var saveTimeout;

343 344 345 346 347 348
	signals.cameraChanged.add( function () {

		render();

	} );

M
Mr.doob 已提交
349
	signals.objectSelected.add( function ( object ) {
350

M
Mr.doob 已提交
351 352
		selectionBox.visible = false;
		transformControls.detach();
M
Mr.doob 已提交
353

M
Mr.doob 已提交
354
		if ( object !== null ) {
M
Mr.doob 已提交
355

356 357
			if ( object.geometry !== undefined &&
				 object instanceof THREE.Sprite === false ) {
M
Mr.doob 已提交
358 359 360 361 362 363

				selectionBox.update( object );
				selectionBox.visible = true;

			}

364
			transformControls.attach( object );
M
Mr.doob 已提交
365 366

		}
M
Mr.doob 已提交
367

368
		render();
M
Mr.doob 已提交
369 370 371

	} );

372 373 374 375 376 377
	signals.objectFocused.add( function ( object ) {

		controls.focus( object );

	} );

378 379 380
	signals.geometryChanged.add( function ( object ) {

		if ( object !== null ) {
381

382 383 384
			selectionBox.update( object );

		}
385 386 387 388

		render();

	} );
M
Mr.doob 已提交
389

M
Mr.doob 已提交
390 391
	signals.objectAdded.add( function ( object ) {

392
		var materialsNeedUpdate = false;
393

394 395
		object.traverse( function ( child ) {

396 397
			if ( child instanceof THREE.Light ) materialsNeedUpdate = true;

398 399 400 401
			objects.push( child );

		} );

402 403
		if ( materialsNeedUpdate === true ) updateMaterials();

M
Mr.doob 已提交
404 405
	} );

406
	signals.objectChanged.add( function ( object ) {
407

408 409 410 411 412 413
		if ( editor.selected === object ) {

			selectionBox.update( object );
			transformControls.update();

		}
M
Mr.doob 已提交
414

415
		if ( object instanceof THREE.PerspectiveCamera ) {
M
Mr.doob 已提交
416

417
			object.updateProjectionMatrix();
M
Mr.doob 已提交
418

419
		}
M
Mr.doob 已提交
420

421 422 423
		if ( editor.helpers[ object.id ] !== undefined ) {

			editor.helpers[ object.id ].update();
424 425

		}
426

427
		render();
428

M
Mr.doob 已提交
429 430 431 432
	} );

	signals.objectRemoved.add( function ( object ) {

433
		var materialsNeedUpdate = false;
M
Mr.doob 已提交
434

435
		object.traverse( function ( child ) {
M
Mr.doob 已提交
436

437 438 439
			if ( child instanceof THREE.Light ) materialsNeedUpdate = true;

			objects.splice( objects.indexOf( child ), 1 );
M
Mr.doob 已提交
440

441 442 443
		} );

		if ( materialsNeedUpdate === true ) updateMaterials();
444 445 446 447 448

	} );

	signals.helperAdded.add( function ( object ) {

M
Mr.doob 已提交
449
		objects.push( object.getObjectByName( 'picker' ) );
450 451 452 453 454

	} );

	signals.helperRemoved.add( function ( object ) {

M
Mr.doob 已提交
455
		objects.splice( objects.indexOf( object.getObjectByName( 'picker' ) ), 1 );
456

457 458
	} );

M
Mr.doob 已提交
459
	signals.materialChanged.add( function ( material ) {
460 461 462 463 464

		render();

	} );

M
Mr.doob 已提交
465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482
	signals.fogTypeChanged.add( function ( fogType ) {

		if ( fogType !== oldFogType ) {

			if ( fogType === "None" ) {

				scene.fog = null;

			} else if ( fogType === "Fog" ) {

				scene.fog = new THREE.Fog( oldFogColor, oldFogNear, oldFogFar );

			} else if ( fogType === "FogExp2" ) {

				scene.fog = new THREE.FogExp2( oldFogColor, oldFogDensity );

			}

M
Mr.doob 已提交
483
			updateMaterials();
M
Mr.doob 已提交
484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509

			oldFogType = fogType;

		}

		render();

	} );

	signals.fogColorChanged.add( function ( fogColor ) {

		oldFogColor = fogColor;

		updateFog( scene );

		render();

	} );

	signals.fogParametersChanged.add( function ( near, far, density ) {

		oldFogNear = near;
		oldFogFar = far;
		oldFogDensity = density;

		updateFog( scene );
510 511 512 513 514

		render();

	} );

515 516 517 518 519 520 521 522 523 524 525
	signals.windowResize.add( function () {

		camera.aspect = container.dom.offsetWidth / container.dom.offsetHeight;
		camera.updateProjectionMatrix();

		renderer.setSize( container.dom.offsetWidth, container.dom.offsetHeight );

		render();

	} );

C
Chris Jubb 已提交
526 527 528 529 530 531 532
	signals.showGridChanged.add( function ( showGrid ) {

		grid.visible = showGrid;
		render();

	} );

533 534
	//

535
	var renderer = null;
M
Mr.doob 已提交
536 537 538 539 540

	animate();

	//

M
Mr.doob 已提交
541
	function updateMaterials() {
M
Mr.doob 已提交
542

M
Mr.doob 已提交
543
		editor.scene.traverse( function ( node ) {
M
Mr.doob 已提交
544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578

			if ( node.material ) {

				node.material.needsUpdate = true;

				if ( node.material instanceof THREE.MeshFaceMaterial ) {

					for ( var i = 0; i < node.material.materials.length; i ++ ) {

						node.material.materials[ i ].needsUpdate = true;

					}

				}

			}

		} );

	}

	function updateFog( root ) {

		if ( root.fog ) {

			root.fog.color.setHex( oldFogColor );

			if ( root.fog.near !== undefined ) root.fog.near = oldFogNear;
			if ( root.fog.far !== undefined ) root.fog.far = oldFogFar;
			if ( root.fog.density !== undefined ) root.fog.density = oldFogDensity;

		}

	}

M
Mr.doob 已提交
579 580 581 582
	function animate() {

		requestAnimationFrame( animate );

583 584
		/*

585 586 587 588 589 590
		// animations

		if ( THREE.AnimationHandler.animations.length > 0 ) {

			THREE.AnimationHandler.update( 0.016 );

M
Mr.doob 已提交
591 592 593 594 595 596 597 598 599 600 601 602
			for ( var i = 0, l = sceneHelpers.children.length; i < l; i ++ ) {

				var helper = sceneHelpers.children[ i ];

				if ( helper instanceof THREE.SkeletonHelper ) {

					helper.update();

				}

			}

603 604 605 606
			render();

		}

607 608
		*/

M
Mr.doob 已提交
609 610 611 612
	}

	function render() {

M
Mr.doob 已提交
613
		sceneHelpers.updateMatrixWorld();
M
Mr.doob 已提交
614
		scene.updateMatrixWorld();
615

M
Mr.doob 已提交
616
		renderer.clear();
M
Mr.doob 已提交
617
		renderer.render( scene, camera );
M
Mr.doob 已提交
618 619 620 621 622 623

		if ( renderer instanceof THREE.RaytracingRenderer === false ) {

			renderer.render( sceneHelpers, camera );

		}
M
Mr.doob 已提交
624 625 626 627 628 629

	}

	return container;

}