Viewport.js 10.8 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
		var object = transformControls.object;

		if ( object !== undefined ) {

M
Mr.doob 已提交
46 47
			selectionBox.update( object );

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

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

			}

		}

56
		render();
57

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

61
		controls.enabled = false;
M
Mr.doob 已提交
62

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

66
		signals.objectChanged.dispatch( transformControls.object );
67
		controls.enabled = true;
68 69

	} );
70

71
	sceneHelpers.add( transformControls );
A
alteredq 已提交
72

M
Mr.doob 已提交
73
	// fog
74

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

81 82
	// object picking

83
	var raycaster = new THREE.Raycaster();
84
	var mouse = new THREE.Vector2();
85

86 87
	// events

88
	var getIntersects = function ( point, objects ) {
89

90
		mouse.set( ( point.x * 2 ) - 1, - ( point.y * 2 ) + 1 );
91

92
		raycaster.setFromCamera( mouse, camera );
93

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

	};

M
Mr.doob 已提交
98 99 100
	var onDownPosition = new THREE.Vector2();
	var onUpPosition = new THREE.Vector2();
	var onDoubleClickPosition = new THREE.Vector2();
M
Mr.doob 已提交
101 102 103 104 105 106 107

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

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

	};
M
Mr.doob 已提交
108

M
Mr.doob 已提交
109
	var handleClick = function () {
110

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

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

M
Mr.doob 已提交
115
			if ( intersects.length > 0 ) {
M
Mr.doob 已提交
116

M
Mr.doob 已提交
117 118
				var object = intersects[ 0 ].object;

119
				if ( object.userData.object !== undefined ) {
120

121 122
					// helper

123
					editor.select( object.userData.object );
M
Mr.doob 已提交
124

125 126 127
				} else {

					editor.select( object );
128

M
Mr.doob 已提交
129
				}
130

M
Mr.doob 已提交
131 132
			} else {

133
				editor.select( null );
M
Mr.doob 已提交
134

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

M
Mr.doob 已提交
137
			render();
138

139 140
		}

M
Mr.doob 已提交
141 142 143 144 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
	};

	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 );
186

187
	};
188

189 190
	var onDoubleClick = function ( event ) {

M
Mr.doob 已提交
191
		var array = getMousePosition( container.dom, event.clientX, event.clientY );
M
Mr.doob 已提交
192
		onDoubleClickPosition.fromArray( array );
193

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

196
		if ( intersects.length > 0 ) {
197

198 199 200
			var intersect = intersects[ 0 ];

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

M
Mr.doob 已提交
202
		}
203 204 205

	};

206
	container.dom.addEventListener( 'mousedown', onMouseDown, false );
M
Mr.doob 已提交
207
	container.dom.addEventListener( 'touchstart', onTouchStart, false );
208
	container.dom.addEventListener( 'dblclick', onDoubleClick, false );
209

210 211 212
	// controls need to be added *after* main logic,
	// otherwise controls.enabled doesn't work.

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

217
		transformControls.update();
218
		signals.cameraChanged.dispatch( camera );
219

220
	} );
221

222
	// signals
223

224 225
	signals.editorCleared.add( function () {

226
		controls.center.set( 0, 0, 0 );
227 228 229 230
		render();

	} );

231
	var clearColor;
232

233
	signals.themeChanged.add( function ( value ) {
234

235 236
		switch ( value ) {

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

		}
247

248
		renderer.setClearColor( clearColor );
249 250 251 252 253

		render();

	} );

M
Mr.doob 已提交
254
	signals.transformModeChanged.add( function ( mode ) {
M
Mr.doob 已提交
255

256
		transformControls.setMode( mode );
A
Aleksandar Rodic 已提交
257 258 259 260 261

	} );

	signals.snapChanged.add( function ( dist ) {

262
		transformControls.setSnap( dist );
M
Mr.doob 已提交
263 264 265

	} );

266
	signals.spaceChanged.add( function ( space ) {
M
Mr.doob 已提交
267

268
		transformControls.setSpace( space );
M
Mr.doob 已提交
269 270 271

	} );

272 273 274
	signals.rendererChanged.add( function ( newRenderer ) {

		if ( renderer !== null ) {
275

276 277 278
			container.dom.removeChild( renderer.domElement );

		}
279

280
		renderer = newRenderer;
281 282 283 284 285

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

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

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

292
	} );
293

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

		render();

	} );

300 301
	var saveTimeout;

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

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

			clearTimeout( saveTimeout );

		}

		saveTimeout = setTimeout( function () {

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

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

319 320 321 322
		render();

	} );

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

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

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

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

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

			}

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

		}
M
Mr.doob 已提交
341

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

	} );

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

		controls.focus( object );

	} );

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

		selectionBox.update( editor.selected );

		render();

	} );
M
Mr.doob 已提交
359

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

362
		var materialsNeedUpdate = false;
363

364 365
		object.traverse( function ( child ) {

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

368 369 370 371
			objects.push( child );

		} );

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

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

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

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

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

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

384
		}
M
Mr.doob 已提交
385

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

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

		}
391

392
		render();
393

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

	signals.objectRemoved.add( function ( object ) {

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

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

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

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

406 407 408
		} );

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

	} );

	signals.helperAdded.add( function ( object ) {

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

	} );

	signals.helperRemoved.add( function ( object ) {

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

422 423
	} );

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

		render();

	} );

M
Mr.doob 已提交
430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447
	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 已提交
448
			updateMaterials();
M
Mr.doob 已提交
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 474

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

		render();

	} );

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

		grid.visible = showGrid;
		render();

	} );

498
	var animations = [];
499

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

502
		animations.push( animation );
503

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

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

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

		if ( index !== -1 ) {

			animations.splice( index, 1 );

		}
515 516

	} );
517

518 519
	//

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

	animate();

	//

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

M
Mr.doob 已提交
528
		editor.scene.traverse( function ( node ) {
M
Mr.doob 已提交
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 563

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

		requestAnimationFrame( animate );

568 569 570 571 572 573
		// animations

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

			THREE.AnimationHandler.update( 0.016 );

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

				var helper = sceneHelpers.children[ i ];

				if ( helper instanceof THREE.SkeletonHelper ) {

					helper.update();

				}

			}

586 587 588 589
			render();

		}

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

	function render() {

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

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

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

			renderer.render( sceneHelpers, camera );

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

	}

	return container;

}