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

M
Mr.doob 已提交
15 16 17 18 19
	//

	var renderer = null;

	var camera = editor.camera;
20 21 22
	var scene = editor.scene;
	var sceneHelpers = editor.sceneHelpers;

M
Mr.doob 已提交
23 24
	var objects = [];

M
Mr.doob 已提交
25 26 27 28 29 30 31 32 33 34 35 36
	//

	var vrEffect, vrControls;

	if ( WEBVR.isAvailable() === true ) {

		var vrCamera = new THREE.PerspectiveCamera();
		vrCamera.projectionMatrix = camera.projectionMatrix;
		camera.add( vrCamera );

	}

M
Mr.doob 已提交
37 38
	// helpers

M
Mugen87 已提交
39
	var grid = new THREE.GridHelper( 60, 60 );
M
Mr.doob 已提交
40 41
	sceneHelpers.add( grid );

A
Aleksandar Rodic 已提交
42 43
	//

M
Mr.doob 已提交
44 45
	var box = new THREE.Box3();

M
Mr.doob 已提交
46
	var selectionBox = new THREE.BoxHelper();
47 48
	selectionBox.material.depthTest = false;
	selectionBox.material.transparent = true;
M
Mr.doob 已提交
49
	selectionBox.visible = false;
50 51
	sceneHelpers.add( selectionBox );

52 53 54
	var objectPositionOnDown = null;
	var objectRotationOnDown = null;
	var objectScaleOnDown = null;
M
Mr.doob 已提交
55

56 57 58
	var transformControls = new THREE.TransformControls( camera, container.dom );
	transformControls.addEventListener( 'change', function () {

M
Mr.doob 已提交
59 60 61 62
		var object = transformControls.object;

		if ( object !== undefined ) {

M
Mugen87 已提交
63
			selectionBox.setFromObject( object );
M
Mr.doob 已提交
64

M
Mr.doob 已提交
65 66 67 68 69 70
			if ( editor.helpers[ object.id ] !== undefined ) {

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

			}

D
Daniel 已提交
71
			signals.refreshSidebarObject3D.dispatch( object );
72

M
Mr.doob 已提交
73 74
		}

75
		render();
76

77 78
	} );
	transformControls.addEventListener( 'mouseDown', function () {
M
Mr.doob 已提交
79

M
Mr.doob 已提交
80 81
		var object = transformControls.object;

82 83 84
		objectPositionOnDown = object.position.clone();
		objectRotationOnDown = object.rotation.clone();
		objectScaleOnDown = object.scale.clone();
M
Mr.doob 已提交
85

86
		controls.enabled = false;
M
Mr.doob 已提交
87

88
	} );
89
	transformControls.addEventListener( 'mouseUp', function () {
M
Mr.doob 已提交
90

M
Mr.doob 已提交
91 92
		var object = transformControls.object;

M
Mr.doob 已提交
93
		if ( object !== undefined ) {
94 95 96 97 98

			switch ( transformControls.getMode() ) {

				case 'translate':

M
Mr.doob 已提交
99 100 101
					if ( ! objectPositionOnDown.equals( object.position ) ) {

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

103
					}
M
Mr.doob 已提交
104

105
					break;
M
Mr.doob 已提交
106

107 108
				case 'rotate':

M
Mr.doob 已提交
109 110 111
					if ( ! objectRotationOnDown.equals( object.rotation ) ) {

						editor.execute( new SetRotationCommand( object, object.rotation, objectRotationOnDown ) );
M
Mr.doob 已提交
112 113

					}
M
Mr.doob 已提交
114

115
					break;
M
Mr.doob 已提交
116

117
				case 'scale':
M
Mr.doob 已提交
118

M
Mr.doob 已提交
119 120 121
					if ( ! objectScaleOnDown.equals( object.scale ) ) {

						editor.execute( new SetScaleCommand( object, object.scale, objectScaleOnDown ) );
122 123

					}
M
Mr.doob 已提交
124

125 126 127
					break;

			}
M
Mr.doob 已提交
128 129 130

		}

131
		controls.enabled = true;
132 133

	} );
134

135
	sceneHelpers.add( transformControls );
A
alteredq 已提交
136

137 138
	// object picking

139
	var raycaster = new THREE.Raycaster();
140
	var mouse = new THREE.Vector2();
141

142 143
	// events

M
Mr.doob 已提交
144
	function getIntersects( point, objects ) {
145

146
		mouse.set( ( point.x * 2 ) - 1, - ( point.y * 2 ) + 1 );
147

148
		raycaster.setFromCamera( mouse, camera );
149

150
		return raycaster.intersectObjects( objects );
151

M
Mr.doob 已提交
152
	}
153

M
Mr.doob 已提交
154 155 156
	var onDownPosition = new THREE.Vector2();
	var onUpPosition = new THREE.Vector2();
	var onDoubleClickPosition = new THREE.Vector2();
M
Mr.doob 已提交
157

M
Mr.doob 已提交
158
	function getMousePosition( dom, x, y ) {
M
Mr.doob 已提交
159 160 161 162

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

M
Mr.doob 已提交
163
	}
M
Mr.doob 已提交
164

M
Mr.doob 已提交
165
	function handleClick() {
166

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

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

M
Mr.doob 已提交
171
			if ( intersects.length > 0 ) {
M
Mr.doob 已提交
172

M
Mr.doob 已提交
173 174
				var object = intersects[ 0 ].object;

175
				if ( object.userData.object !== undefined ) {
176

177 178
					// helper

179
					editor.select( object.userData.object );
M
Mr.doob 已提交
180

181 182 183
				} else {

					editor.select( object );
184

M
Mr.doob 已提交
185
				}
186

M
Mr.doob 已提交
187 188
			} else {

189
				editor.select( null );
M
Mr.doob 已提交
190

M
Mr.doob 已提交
191
			}
M
Mr.doob 已提交
192

M
Mr.doob 已提交
193
			render();
194

195 196
		}

M
Mr.doob 已提交
197
	}
M
Mr.doob 已提交
198

M
Mr.doob 已提交
199
	function onMouseDown( event ) {
M
Mr.doob 已提交
200 201 202 203 204 205 206 207

		event.preventDefault();

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

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

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

M
Mr.doob 已提交
210
	function onMouseUp( event ) {
M
Mr.doob 已提交
211 212 213 214 215 216 217 218

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

		handleClick();

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

M
Mr.doob 已提交
219
	}
M
Mr.doob 已提交
220

M
Mr.doob 已提交
221
	function onTouchStart( event ) {
M
Mr.doob 已提交
222 223 224 225 226 227 228 229

		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 已提交
230
	}
M
Mr.doob 已提交
231

M
Mr.doob 已提交
232
	function onTouchEnd( event ) {
M
Mr.doob 已提交
233 234 235 236 237 238 239 240 241

		var touch = event.changedTouches[ 0 ];

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

		handleClick();

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

M
Mr.doob 已提交
243
	}
244

M
Mr.doob 已提交
245
	function onDoubleClick( event ) {
246

M
Mr.doob 已提交
247
		var array = getMousePosition( container.dom, event.clientX, event.clientY );
M
Mr.doob 已提交
248
		onDoubleClickPosition.fromArray( array );
249

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

252
		if ( intersects.length > 0 ) {
253

254 255 256
			var intersect = intersects[ 0 ];

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

M
Mr.doob 已提交
258
		}
259

M
Mr.doob 已提交
260
	}
261

262
	container.dom.addEventListener( 'mousedown', onMouseDown, false );
M
Mr.doob 已提交
263
	container.dom.addEventListener( 'touchstart', onTouchStart, false );
264
	container.dom.addEventListener( 'dblclick', onDoubleClick, false );
265

266 267 268
	// controls need to be added *after* main logic,
	// otherwise controls.enabled doesn't work.

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

272
		transformControls.update();
273
		signals.cameraChanged.dispatch( camera );
274

275
	} );
276

277
	// signals
278

279 280
	signals.editorCleared.add( function () {

281
		controls.center.set( 0, 0, 0 );
282 283 284 285
		render();

	} );

M
Mr.doob 已提交
286 287 288 289 290 291
	signals.enterVR.add( function () {

		vrEffect.isPresenting ? vrEffect.exitPresent() : vrEffect.requestPresent();

	} );

292
	signals.themeChanged.add( function ( value ) {
293

294 295
		switch ( value ) {

M
Mr.doob 已提交
296
			case 'css/light.css':
M
Michael Herzog 已提交
297
				sceneHelpers.remove( grid );
M
Mugen87 已提交
298
				grid = new THREE.GridHelper( 60, 60, 0x444444, 0x888888 );
M
Michael Herzog 已提交
299
				sceneHelpers.add( grid );
M
Mr.doob 已提交
300 301
				break;
			case 'css/dark.css':
M
Michael Herzog 已提交
302
				sceneHelpers.remove( grid );
M
Mugen87 已提交
303
				grid = new THREE.GridHelper( 60, 60, 0xbbbbbb, 0x888888 );
M
Michael Herzog 已提交
304
				sceneHelpers.add( grid );
M
Mr.doob 已提交
305
				break;
306 307

		}
308

309 310 311 312
		render();

	} );

M
Mr.doob 已提交
313
	signals.transformModeChanged.add( function ( mode ) {
M
Mr.doob 已提交
314

315
		transformControls.setMode( mode );
A
Aleksandar Rodic 已提交
316 317 318 319 320

	} );

	signals.snapChanged.add( function ( dist ) {

321
		transformControls.setTranslationSnap( dist );
M
Mr.doob 已提交
322 323 324

	} );

325
	signals.spaceChanged.add( function ( space ) {
M
Mr.doob 已提交
326

327
		transformControls.setSpace( space );
M
Mr.doob 已提交
328 329 330

	} );

331 332 333
	signals.rendererChanged.add( function ( newRenderer ) {

		if ( renderer !== null ) {
334

335 336 337
			container.dom.removeChild( renderer.domElement );

		}
338

339
		renderer = newRenderer;
340 341 342 343

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

346
		container.dom.appendChild( renderer.domElement );
M
Mr.doob 已提交
347

M
Mr.doob 已提交
348 349 350 351 352 353 354 355 356 357 358 359 360
		if ( WEBVR.isAvailable() === true ) {

			vrControls = new THREE.VRControls( vrCamera );
			vrEffect = new THREE.VREffect( renderer );

			window.addEventListener( 'vrdisplaypresentchange', function ( event ) {

				effect.isPresenting ? signals.enteredVR.dispatch() : signals.exitedVR.dispatch();

			}, false );

		}

361
		render();
M
Mr.doob 已提交
362

363
	} );
364

365 366 367 368 369 370
	signals.sceneGraphChanged.add( function () {

		render();

	} );

371 372 373 374 375 376
	signals.cameraChanged.add( function () {

		render();

	} );

M
Mr.doob 已提交
377
	signals.objectSelected.add( function ( object ) {
378

M
Mr.doob 已提交
379 380
		selectionBox.visible = false;
		transformControls.detach();
M
Mr.doob 已提交
381

M
Mugen87 已提交
382
		if ( object !== null && object !== scene && object !== camera ) {
M
Mr.doob 已提交
383

M
Mr.doob 已提交
384 385 386
			box.setFromObject( object );

			if ( box.isEmpty() === false ) {
M
Mr.doob 已提交
387

M
Mugen87 已提交
388
				selectionBox.setFromObject( object );
M
Mr.doob 已提交
389 390 391 392
				selectionBox.visible = true;

			}

393
			transformControls.attach( object );
M
Mr.doob 已提交
394 395

		}
M
Mr.doob 已提交
396

397
		render();
M
Mr.doob 已提交
398 399 400

	} );

401 402 403 404 405 406
	signals.objectFocused.add( function ( object ) {

		controls.focus( object );

	} );

407 408
	signals.geometryChanged.add( function ( object ) {

M
Mr.doob 已提交
409
		if ( object !== undefined ) {
410

M
Mugen87 已提交
411
			selectionBox.setFromObject( object );
412 413

		}
414 415 416 417

		render();

	} );
M
Mr.doob 已提交
418

M
Mr.doob 已提交
419 420
	signals.objectAdded.add( function ( object ) {

421 422 423 424 425 426
		object.traverse( function ( child ) {

			objects.push( child );

		} );

M
Mr.doob 已提交
427 428
	} );

429
	signals.objectChanged.add( function ( object ) {
430

431 432
		if ( editor.selected === object ) {

M
Mugen87 已提交
433
			selectionBox.setFromObject( object );
434 435 436
			transformControls.update();

		}
M
Mr.doob 已提交
437

438
		if ( object instanceof THREE.PerspectiveCamera ) {
M
Mr.doob 已提交
439

440
			object.updateProjectionMatrix();
M
Mr.doob 已提交
441

442
		}
M
Mr.doob 已提交
443

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

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

		}
449

450
		render();
451

M
Mr.doob 已提交
452 453 454 455
	} );

	signals.objectRemoved.add( function ( object ) {

456
		object.traverse( function ( child ) {
M
Mr.doob 已提交
457

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

460 461
		} );

462 463 464 465
	} );

	signals.helperAdded.add( function ( object ) {

M
Mr.doob 已提交
466
		objects.push( object.getObjectByName( 'picker' ) );
467 468 469 470 471

	} );

	signals.helperRemoved.add( function ( object ) {

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

474 475
	} );

M
Mr.doob 已提交
476
	signals.materialChanged.add( function ( material ) {
477 478 479 480 481

		render();

	} );

M
Mr.doob 已提交
482
	// fog
M
Mr.doob 已提交
483

484 485 486 487 488 489 490 491
	signals.sceneBackgroundChanged.add( function ( backgroundColor ) {

		scene.background.setHex( backgroundColor );

		render();

	} );

M
Mr.doob 已提交
492
	var currentFogType = null;
M
Mr.doob 已提交
493

M
Mr.doob 已提交
494
	signals.sceneFogChanged.add( function ( fogType, fogColor, fogNear, fogFar, fogDensity ) {
M
Mr.doob 已提交
495

M
Mr.doob 已提交
496
		if ( currentFogType !== fogType ) {
M
Mr.doob 已提交
497

M
Mr.doob 已提交
498
			switch ( fogType ) {
M
Mr.doob 已提交
499

M
Mr.doob 已提交
500 501 502 503 504 505 506 507 508
				case 'None':
					scene.fog = null;
					break;
				case 'Fog':
					scene.fog = new THREE.Fog();
					break;
				case 'FogExp2':
					scene.fog = new THREE.FogExp2();
					break;
M
Mr.doob 已提交
509 510 511

			}

M
Mr.doob 已提交
512
			currentFogType = fogType;
M
Mr.doob 已提交
513 514 515

		}

M
Mr.doob 已提交
516
		if ( scene.fog instanceof THREE.Fog ) {
M
Mr.doob 已提交
517

M
Mr.doob 已提交
518 519 520
			scene.fog.color.setHex( fogColor );
			scene.fog.near = fogNear;
			scene.fog.far = fogFar;
M
Mr.doob 已提交
521

M
Mr.doob 已提交
522
		} else if ( scene.fog instanceof THREE.FogExp2 ) {
M
Mr.doob 已提交
523

M
Mr.doob 已提交
524 525
			scene.fog.color.setHex( fogColor );
			scene.fog.density = fogDensity;
M
Mr.doob 已提交
526

M
Mr.doob 已提交
527
		}
M
Mr.doob 已提交
528 529 530 531 532

		render();

	} );

M
Mr.doob 已提交
533
	//
534

535 536
	signals.windowResize.add( function () {

M
Mr.doob 已提交
537 538 539 540 541
		// TODO: Move this out?

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

542 543 544 545 546 547 548 549 550
		camera.aspect = container.dom.offsetWidth / container.dom.offsetHeight;
		camera.updateProjectionMatrix();

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

		render();

	} );

C
Chris Jubb 已提交
551 552 553 554 555 556 557
	signals.showGridChanged.add( function ( showGrid ) {

		grid.visible = showGrid;
		render();

	} );

558 559
	//

M
Mr.doob 已提交
560 561 562 563
	function animate() {

		requestAnimationFrame( animate );

M
Mr.doob 已提交
564 565
		if ( vrEffect && vrEffect.isPresenting ) {

566 567 568 569
			render();

		}

M
Mr.doob 已提交
570 571 572 573
	}

	function render() {

M
Mr.doob 已提交
574
		sceneHelpers.updateMatrixWorld();
M
Mr.doob 已提交
575
		scene.updateMatrixWorld();
576

M
Mr.doob 已提交
577 578 579 580 581 582 583 584 585 586
		if ( vrEffect && vrEffect.isPresenting ) {

			vrControls.update();

			camera.updateMatrixWorld();

			vrEffect.render( scene, vrCamera );
			vrEffect.render( sceneHelpers, vrCamera );

		} else {
M
Mr.doob 已提交
587

M
Mr.doob 已提交
588
			renderer.render( scene, camera );
M
Mr.doob 已提交
589

M
Mr.doob 已提交
590 591 592 593 594
			if ( renderer instanceof THREE.RaytracingRenderer === false ) {

				renderer.render( sceneHelpers, camera );

			}
M
Mr.doob 已提交
595 596

		}
M
Mr.doob 已提交
597

M
Mr.doob 已提交
598

M
Mr.doob 已提交
599 600
	}

M
Mr.doob 已提交
601 602
	requestAnimationFrame( animate );

M
Mr.doob 已提交
603 604
	return container;

M
Mr.doob 已提交
605
};