Viewport.js 10.7 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 29
	camera.position.fromArray( editor.config.getKey( 'camera/position' ) );
	camera.lookAt( new THREE.Vector3().fromArray( editor.config.getKey( 'camera/target' ) ) );
30

A
Aleksandar Rodic 已提交
31
	//
M
Mr.doob 已提交
32

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

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

M
Mr.doob 已提交
42 43 44 45 46 47 48 49 50 51 52 53
		var object = transformControls.object;

		if ( object !== undefined ) {

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

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

			}

		}

54
		render();
55

56 57
	} );
	transformControls.addEventListener( 'mouseDown', function () {
M
Mr.doob 已提交
58

59
		controls.enabled = false;
M
Mr.doob 已提交
60

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

64
		signals.objectChanged.dispatch( transformControls.object );
65
		controls.enabled = true;
66 67

	} );
68

69
	sceneHelpers.add( transformControls );
A
alteredq 已提交
70

M
Mr.doob 已提交
71
	// fog
72

M
Mr.doob 已提交
73 74 75 76 77
	var oldFogType = "None";
	var oldFogColor = 0xaaaaaa;
	var oldFogNear = 1;
	var oldFogFar = 5000;
	var oldFogDensity = 0.00025;
78

79 80
	// object picking

81
	var raycaster = new THREE.Raycaster();
82
	var mouse = new THREE.Vector2();
83

84 85
	// events

M
Mr.doob 已提交
86
	var getIntersects = function ( point, object ) {
87

88
		mouse.set( ( point.x * 2 ) - 1, - ( point.y * 2 ) + 1 );
89

90
		raycaster.setFromCamera( mouse, camera );
91

92
		if ( Array.isArray( object ) ) {
93

94
			return raycaster.intersectObjects( object );
95 96 97

		}

98
		return raycaster.intersectObject( object );
99 100 101

	};

M
Mr.doob 已提交
102 103 104
	var onDownPosition = new THREE.Vector2();
	var onUpPosition = new THREE.Vector2();
	var onDoubleClickPosition = new THREE.Vector2();
M
Mr.doob 已提交
105 106 107 108 109 110 111

	var getMousePosition = function ( dom, x, y ) {

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

	};
M
Mr.doob 已提交
112

M
Mr.doob 已提交
113
	var handleClick = function () {
114

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

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

M
Mr.doob 已提交
119
			if ( intersects.length > 0 ) {
M
Mr.doob 已提交
120

M
Mr.doob 已提交
121 122
				var object = intersects[ 0 ].object;

123
				if ( object.userData.object !== undefined ) {
124

125 126
					// helper

127
					editor.select( object.userData.object );
M
Mr.doob 已提交
128

129 130 131
				} else {

					editor.select( object );
132

M
Mr.doob 已提交
133
				}
134

M
Mr.doob 已提交
135 136
			} else {

137
				editor.select( null );
M
Mr.doob 已提交
138

M
Mr.doob 已提交
139
			}
M
Mr.doob 已提交
140

M
Mr.doob 已提交
141
			render();
142

143 144
		}

M
Mr.doob 已提交
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
	};

	var onMouseDown = function ( event ) {

		event.preventDefault();

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

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

	};

	var onMouseUp = function ( event ) {

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

		handleClick();

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

	};

	var onTouchStart = function ( event ) {

		var touch = event.changedTouches[ 0 ];

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

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

	};

	var onTouchEnd = function ( event ) {

		var touch = event.changedTouches[ 0 ];

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

		handleClick();

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

191
	};
192

193 194
	var onDoubleClick = function ( event ) {

M
Mr.doob 已提交
195
		var array = getMousePosition( container.dom, event.clientX, event.clientY );
M
Mr.doob 已提交
196
		onDoubleClickPosition.fromArray( array );
197

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

200
		if ( intersects.length > 0 ) {
201

202 203 204
			var intersect = intersects[ 0 ];

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

M
Mr.doob 已提交
206
		}
207 208 209

	};

210
	container.dom.addEventListener( 'mousedown', onMouseDown, false );
M
Mr.doob 已提交
211
	container.dom.addEventListener( 'touchstart', onTouchStart, false );
212
	container.dom.addEventListener( 'dblclick', onDoubleClick, false );
213

214 215 216
	// controls need to be added *after* main logic,
	// otherwise controls.enabled doesn't work.

M
Mr.doob 已提交
217
	var controls = new THREE.EditorControls( camera, container.dom );
218
	controls.center.fromArray( editor.config.getKey( 'camera/target' ) );
219
	controls.addEventListener( 'change', function () {
220

221
		transformControls.update();
222
		signals.cameraChanged.dispatch( camera );
223

224
	} );
225

226
	// signals
227

228 229
	signals.editorCleared.add( function () {

230
		controls.center.set( 0, 0, 0 );
231 232 233 234
		render();

	} );

235 236
	signals.themeChanged.add( function ( value ) {

237 238
		var clearColor;

239 240
		switch ( value ) {

M
Mr.doob 已提交
241 242
			case 'css/light.css':
				grid.setColors( 0x444444, 0x888888 );
243
				clearColor = 0xaaaaaa;
M
Mr.doob 已提交
244 245 246
				break;
			case 'css/dark.css':
				grid.setColors( 0xbbbbbb, 0x888888 );
247
				clearColor = 0x333333;
M
Mr.doob 已提交
248
				break;
249 250

		}
251

252
		renderer.setClearColor( clearColor );
253 254 255 256 257

		render();

	} );

M
Mr.doob 已提交
258
	signals.transformModeChanged.add( function ( mode ) {
M
Mr.doob 已提交
259

260
		transformControls.setMode( mode );
A
Aleksandar Rodic 已提交
261 262 263 264 265

	} );

	signals.snapChanged.add( function ( dist ) {

266
		transformControls.setSnap( dist );
M
Mr.doob 已提交
267 268 269

	} );

270
	signals.spaceChanged.add( function ( space ) {
M
Mr.doob 已提交
271

272
		transformControls.setSpace( space );
M
Mr.doob 已提交
273 274 275

	} );

276 277 278
	signals.rendererChanged.add( function ( newRenderer ) {

		if ( renderer !== null ) {
279

280 281 282
			container.dom.removeChild( renderer.domElement );

		}
283

284
		renderer = newRenderer;
285
		renderer.setSize( container.dom.offsetWidth, container.dom.offsetHeight );
M
Mr.doob 已提交
286

287
		container.dom.appendChild( renderer.domElement );
M
Mr.doob 已提交
288

289
		render();
M
Mr.doob 已提交
290

291
	} );
292

293 294 295 296 297 298
	signals.sceneGraphChanged.add( function () {

		render();

	} );

299 300
	var saveTimeout;

301 302
	signals.cameraChanged.add( function () {

303 304 305 306 307 308 309 310
		if ( saveTimeout !== undefined ) {

			clearTimeout( saveTimeout );

		}

		saveTimeout = setTimeout( function () {

311 312 313 314
			editor.config.setKey(
				'camera/position', camera.position.toArray(),
				'camera/target', controls.center.toArray()
			);
315 316

		}, 1000 );
M
Mr.doob 已提交
317

318 319 320 321
		render();

	} );

M
Mr.doob 已提交
322
	signals.objectSelected.add( function ( object ) {
323

M
Mr.doob 已提交
324 325
		selectionBox.visible = false;
		transformControls.detach();
M
Mr.doob 已提交
326

M
Mr.doob 已提交
327
		if ( object !== null ) {
M
Mr.doob 已提交
328

329 330
			if ( object.geometry !== undefined &&
				 object instanceof THREE.Sprite === false ) {
M
Mr.doob 已提交
331 332 333 334 335 336

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

			}

337
			transformControls.attach( object );
M
Mr.doob 已提交
338 339

		}
M
Mr.doob 已提交
340

341
		render();
M
Mr.doob 已提交
342 343 344

	} );

345 346 347 348 349 350
	signals.objectFocused.add( function ( object ) {

		controls.focus( object );

	} );

351 352 353 354 355 356 357
	signals.geometryChanged.add( function ( geometry ) {

		selectionBox.update( editor.selected );

		render();

	} );
M
Mr.doob 已提交
358

M
Mr.doob 已提交
359 360
	signals.objectAdded.add( function ( object ) {

361
		var materialsNeedUpdate = false;
362

363 364
		object.traverse( function ( child ) {

365 366
			if ( child instanceof THREE.Light ) materialsNeedUpdate = true;

367 368 369 370
			objects.push( child );

		} );

371 372
		if ( materialsNeedUpdate === true ) updateMaterials();

M
Mr.doob 已提交
373 374
	} );

375
	signals.objectChanged.add( function ( object ) {
376

377
		transformControls.update();
M
Mr.doob 已提交
378

379
		if ( object instanceof THREE.PerspectiveCamera ) {
M
Mr.doob 已提交
380

381
			object.updateProjectionMatrix();
M
Mr.doob 已提交
382

383
		}
M
Mr.doob 已提交
384

385 386 387
		if ( editor.helpers[ object.id ] !== undefined ) {

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

		}
390

391
		render();
392

M
Mr.doob 已提交
393 394 395 396
	} );

	signals.objectRemoved.add( function ( object ) {

397
		var materialsNeedUpdate = false;
M
Mr.doob 已提交
398

399
		object.traverse( function ( child ) {
M
Mr.doob 已提交
400

401 402 403
			if ( child instanceof THREE.Light ) materialsNeedUpdate = true;

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

405 406 407
		} );

		if ( materialsNeedUpdate === true ) updateMaterials();
408 409 410 411 412

	} );

	signals.helperAdded.add( function ( object ) {

M
Mr.doob 已提交
413
		objects.push( object.getObjectByName( 'picker' ) );
414 415 416 417 418

	} );

	signals.helperRemoved.add( function ( object ) {

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

421 422
	} );

M
Mr.doob 已提交
423
	signals.materialChanged.add( function ( material ) {
424 425 426 427 428

		render();

	} );

M
Mr.doob 已提交
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
	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 已提交
447
			updateMaterials();
M
Mr.doob 已提交
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473

			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 );
474 475 476 477 478

		render();

	} );

479 480 481 482 483 484 485 486 487 488 489
	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 已提交
490 491 492 493 494 495 496
	signals.showGridChanged.add( function ( showGrid ) {

		grid.visible = showGrid;
		render();

	} );

497
	var animations = [];
498

499
	signals.playAnimation.add( function ( animation ) {
500

501
		animations.push( animation );
502

503
	} );
M
Mr.doob 已提交
504

505
	signals.stopAnimation.add( function ( animation ) {
506

507 508 509 510 511 512 513
		var index = animations.indexOf( animation );

		if ( index !== -1 ) {

			animations.splice( index, 1 );

		}
514 515

	} );
516

517 518
	//

519
	var renderer = null;
M
Mr.doob 已提交
520 521 522 523 524

	animate();

	//

M
Mr.doob 已提交
525
	function updateMaterials() {
M
Mr.doob 已提交
526

M
Mr.doob 已提交
527
		editor.scene.traverse( function ( node ) {
M
Mr.doob 已提交
528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562

			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 已提交
563 564 565 566
	function animate() {

		requestAnimationFrame( animate );

567 568 569 570 571 572
		// animations

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

			THREE.AnimationHandler.update( 0.016 );

M
Mr.doob 已提交
573 574 575 576 577 578 579 580 581 582 583 584
			for ( var i = 0, l = sceneHelpers.children.length; i < l; i ++ ) {

				var helper = sceneHelpers.children[ i ];

				if ( helper instanceof THREE.SkeletonHelper ) {

					helper.update();

				}

			}

585 586 587 588
			render();

		}

M
Mr.doob 已提交
589 590 591 592
	}

	function render() {

M
Mr.doob 已提交
593
		sceneHelpers.updateMatrixWorld();
M
Mr.doob 已提交
594
		scene.updateMatrixWorld();
595

M
Mr.doob 已提交
596
		renderer.clear();
M
Mr.doob 已提交
597
		renderer.render( scene, camera );
M
Mr.doob 已提交
598 599 600 601 602 603

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

			renderer.render( sceneHelpers, camera );

		}
M
Mr.doob 已提交
604 605 606 607 608 609

	}

	return container;

}