Viewport.js 9.9 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 25 26
	var objects = [];

	// helpers

M
Mr.doob 已提交
27
	var grid = new THREE.GridHelper( 30, 30, 0x444444, 0x888888 );
M
Mr.doob 已提交
28 29
	sceneHelpers.add( grid );

M
Mr.doob 已提交
30 31 32 33 34 35 36 37 38 39 40 41
	var array = grid.geometry.attributes.color.array;

	for ( var i = 0; i < array.length; i += 60 ) {

		for ( var j = 0; j < 12; j ++ ) {

			array[ i + j ] = 0.26;

		}

	}

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
			switch ( transformControls.getMode() ) {
96 97 98

				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
		signals.cameraChanged.dispatch( camera );
273

274
	} );
275

276
	// signals
277

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

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

	} );

M
Mr.doob 已提交
285
	signals.transformModeChanged.add( function ( mode ) {
M
Mr.doob 已提交
286

287
		transformControls.setMode( mode );
A
Aleksandar Rodic 已提交
288 289 290 291 292

	} );

	signals.snapChanged.add( function ( dist ) {

293
		transformControls.setTranslationSnap( dist );
M
Mr.doob 已提交
294 295 296

	} );

297
	signals.spaceChanged.add( function ( space ) {
M
Mr.doob 已提交
298

299
		transformControls.setSpace( space );
M
Mr.doob 已提交
300 301 302

	} );

303 304 305
	signals.rendererChanged.add( function ( newRenderer ) {

		if ( renderer !== null ) {
306

307 308 309
			container.dom.removeChild( renderer.domElement );

		}
310

311
		renderer = newRenderer;
312 313 314 315

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

318
		container.dom.appendChild( renderer.domElement );
M
Mr.doob 已提交
319

320
		render();
M
Mr.doob 已提交
321

322
	} );
323

324 325 326 327 328 329
	signals.sceneGraphChanged.add( function () {

		render();

	} );

330 331 332 333 334 335
	signals.cameraChanged.add( function () {

		render();

	} );

M
Mr.doob 已提交
336
	signals.objectSelected.add( function ( object ) {
337

M
Mr.doob 已提交
338 339
		selectionBox.visible = false;
		transformControls.detach();
M
Mr.doob 已提交
340

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

M
Mr.doob 已提交
343 344 345
			box.setFromObject( object );

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

M
Mugen87 已提交
347
				selectionBox.setFromObject( object );
M
Mr.doob 已提交
348 349 350 351
				selectionBox.visible = true;

			}

352
			transformControls.attach( object );
M
Mr.doob 已提交
353 354

		}
M
Mr.doob 已提交
355

356
		render();
M
Mr.doob 已提交
357 358 359

	} );

360 361 362 363 364 365
	signals.objectFocused.add( function ( object ) {

		controls.focus( object );

	} );

366 367
	signals.geometryChanged.add( function ( object ) {

M
Mr.doob 已提交
368
		if ( object !== undefined ) {
369

M
Mugen87 已提交
370
			selectionBox.setFromObject( object );
371 372

		}
373 374 375 376

		render();

	} );
M
Mr.doob 已提交
377

M
Mr.doob 已提交
378 379
	signals.objectAdded.add( function ( object ) {

380 381 382 383 384 385
		object.traverse( function ( child ) {

			objects.push( child );

		} );

M
Mr.doob 已提交
386 387
	} );

388
	signals.objectChanged.add( function ( object ) {
389

390 391
		if ( editor.selected === object ) {

M
Mugen87 已提交
392
			selectionBox.setFromObject( object );
393 394

		}
M
Mr.doob 已提交
395

M
Mr.doob 已提交
396
		if ( object.isPerspectiveCamera ) {
M
Mr.doob 已提交
397

398
			object.updateProjectionMatrix();
M
Mr.doob 已提交
399

400
		}
M
Mr.doob 已提交
401

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

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

		}
407

408
		render();
409

M
Mr.doob 已提交
410 411 412
	} );

	signals.objectRemoved.add( function ( object ) {
M
Mr.doob 已提交
413 414 415

		if ( object === transformControls.object ) {

Y
Yugloocamai 已提交
416
			transformControls.detach();
M
Mr.doob 已提交
417

Y
Yugloocamai 已提交
418
		}
M
Mr.doob 已提交
419

420
		object.traverse( function ( child ) {
M
Mr.doob 已提交
421

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

424 425
		} );

426 427 428 429
	} );

	signals.helperAdded.add( function ( object ) {

M
Mr.doob 已提交
430
		objects.push( object.getObjectByName( 'picker' ) );
431 432 433 434 435

	} );

	signals.helperRemoved.add( function ( object ) {

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

438 439
	} );

M
Mr.doob 已提交
440
	signals.materialChanged.add( function ( material ) {
441 442 443 444 445

		render();

	} );

M
Mr.doob 已提交
446
	// fog
M
Mr.doob 已提交
447

448 449 450 451 452 453 454 455
	signals.sceneBackgroundChanged.add( function ( backgroundColor ) {

		scene.background.setHex( backgroundColor );

		render();

	} );

M
Mr.doob 已提交
456
	var currentFogType = null;
M
Mr.doob 已提交
457

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

M
Mr.doob 已提交
460
		if ( currentFogType !== fogType ) {
M
Mr.doob 已提交
461

M
Mr.doob 已提交
462
			switch ( fogType ) {
M
Mr.doob 已提交
463

M
Mr.doob 已提交
464 465 466 467 468 469 470 471 472
				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 已提交
473 474 475

			}

M
Mr.doob 已提交
476
			currentFogType = fogType;
M
Mr.doob 已提交
477 478 479

		}

M
Mr.doob 已提交
480
		if ( scene.fog.isFog ) {
M
Mr.doob 已提交
481

M
Mr.doob 已提交
482 483 484
			scene.fog.color.setHex( fogColor );
			scene.fog.near = fogNear;
			scene.fog.far = fogFar;
M
Mr.doob 已提交
485

M
Mr.doob 已提交
486
		} else if ( scene.fog.isFogExp2 ) {
M
Mr.doob 已提交
487

M
Mr.doob 已提交
488 489
			scene.fog.color.setHex( fogColor );
			scene.fog.density = fogDensity;
M
Mr.doob 已提交
490

M
Mr.doob 已提交
491
		}
M
Mr.doob 已提交
492 493 494 495 496

		render();

	} );

M
Mr.doob 已提交
497
	//
498

499 500
	signals.windowResize.add( function () {

M
Mr.doob 已提交
501 502 503 504 505
		// TODO: Move this out?

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

506 507 508 509 510 511 512 513 514
		camera.aspect = container.dom.offsetWidth / container.dom.offsetHeight;
		camera.updateProjectionMatrix();

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

		render();

	} );

C
Chris Jubb 已提交
515 516 517 518 519 520 521
	signals.showGridChanged.add( function ( showGrid ) {

		grid.visible = showGrid;
		render();

	} );

M
Mr.doob 已提交
522 523 524 525 526 527 528 529
	// animations

	var prevTime = performance.now();

	function animate( time ) {

		requestAnimationFrame( animate );

M
Mr.doob 已提交
530
		var mixer = editor.mixer;
M
Mr.doob 已提交
531 532 533

		if ( mixer.stats.actions.inUse > 0 ) {

M
Mr.doob 已提交
534
			mixer.update( ( time - prevTime ) / 1000 );
M
Mr.doob 已提交
535 536 537 538 539 540 541 542 543 544
			render();

		}

		prevTime = time;

	}

	requestAnimationFrame( animate );

545 546
	//

M
Mr.doob 已提交
547 548
	function render() {

M
Mr.doob 已提交
549
		sceneHelpers.updateMatrixWorld();
M
Mr.doob 已提交
550
		scene.updateMatrixWorld();
551

M
Mr.doob 已提交
552
		renderer.render( scene, camera );
M
Mr.doob 已提交
553

M
Mr.doob 已提交
554
		if ( renderer instanceof THREE.RaytracingRenderer === false ) {
M
Mr.doob 已提交
555

M
Mr.doob 已提交
556
			renderer.render( sceneHelpers, camera );
M
Mr.doob 已提交
557 558

		}
M
Mr.doob 已提交
559 560 561 562 563

	}

	return container;

M
Mr.doob 已提交
564
};