Browse Source

Merge pull request #19774 from Mugen87/dev43

ViewHelper: Introduce animated view presets.
Mr.doob 5 years ago
parent
commit
113e58e306
2 changed files with 187 additions and 6 deletions
  1. 168 2
      editor/js/Viewport.ViewHelper.js
  2. 19 4
      editor/js/Viewport.js

+ 168 - 2
editor/js/Viewport.ViewHelper.js

@@ -2,16 +2,53 @@
  * @author Mugen87 / https://github.com/Mugen87
  */
 
+import { UIPanel } from './libs/ui.js';
+
 import * as THREE from '../../build/three.module.js';
 
-function ViewHelper() {
+function ViewHelper( editorCamera, container ) {
 
 	THREE.Object3D.call( this );
 
+	this.animating = false;
+	this.controls = null;
+
+	var panel = new UIPanel();
+	panel.setId( 'viewHelper' );
+	panel.setPosition( 'absolute' );
+	panel.setRight( '0px' );
+	panel.setBottom( '0px' );
+	panel.setHeight( '128px' );
+	panel.setWidth( '128px' );
+	panel.setBottom( '0px' );
+
+	var scope = this;
+
+	panel.dom.addEventListener( 'mouseup', function ( event ) {
+
+		event.stopPropagation();
+
+		scope.handleClick( event );
+
+	} );
+
+	panel.dom.addEventListener( 'mousedown', function ( event ) {
+
+		event.stopPropagation();
+
+	} );
+
+	container.add( panel );
+
 	var color1 = new THREE.Color( '#ff3653' );
 	var color2 = new THREE.Color( '#8adb00' );
 	var color3 = new THREE.Color( '#2c8fff' );
 
+	var interactiveObjects = [];
+	var raycaster = new THREE.Raycaster();
+	var mouse = new THREE.Vector2();
+	var dummy = new THREE.Object3D();
+
 	var camera = new THREE.OrthographicCamera( - 2, 2, 2, - 2, 0, 4 );
 	camera.position.set( 0, 0, 2 );
 
@@ -29,11 +66,17 @@ function ViewHelper() {
 	this.add( yAxis );
 
 	var posXAxisHelper = new THREE.Sprite( getSpriteMaterial( color1, 'X' ) );
+	posXAxisHelper.userData.type = 'posX';
 	var posYAxisHelper = new THREE.Sprite( getSpriteMaterial( color2, 'Y' ) );
+	posYAxisHelper.userData.type = 'posY';
 	var posZAxisHelper = new THREE.Sprite( getSpriteMaterial( color3, 'Z' ) );
+	posZAxisHelper.userData.type = 'posZ';
 	var negXAxisHelper = new THREE.Sprite( getSpriteMaterial( color1 ) );
+	negXAxisHelper.userData.type = 'negX';
 	var negYAxisHelper = new THREE.Sprite( getSpriteMaterial( color2 ) );
+	negYAxisHelper.userData.type = 'negY';
 	var negZAxisHelper = new THREE.Sprite( getSpriteMaterial( color3 ) );
+	negZAxisHelper.userData.type = 'negZ';
 
 	posXAxisHelper.position.x = 1;
 	posYAxisHelper.position.y = 1;
@@ -52,10 +95,18 @@ function ViewHelper() {
 	this.add( negYAxisHelper );
 	this.add( negZAxisHelper );
 
+	interactiveObjects.push( posXAxisHelper );
+	interactiveObjects.push( posYAxisHelper );
+	interactiveObjects.push( posZAxisHelper );
+	interactiveObjects.push( negXAxisHelper );
+	interactiveObjects.push( negYAxisHelper );
+	interactiveObjects.push( negZAxisHelper );
+
 	var point = new THREE.Vector3();
 	var dim = 128;
+	var turnRate = 2 * Math.PI; // turn rate in angles per second
 
-	this.render = function ( renderer, editorCamera, container ) {
+	this.render = function ( renderer ) {
 
 		this.quaternion.copy( editorCamera.quaternion ).inverse();
 		this.updateMatrixWorld();
@@ -109,6 +160,121 @@ function ViewHelper() {
 
 	};
 
+	var targetPosition = new THREE.Vector3();
+	var targetQuaternion = new THREE.Quaternion();
+
+	var q1 = new THREE.Quaternion();
+	var q2 = new THREE.Quaternion();
+	var radius = 0;
+
+	this.handleClick = function ( event ) {
+
+		if ( this.animating === true ) return false;
+
+		var rect = container.dom.getBoundingClientRect();
+		var offsetX = rect.left + ( container.dom.offsetWidth - dim );
+		var offsetY = rect.top + ( container.dom.offsetHeight - dim );
+		mouse.x = ( ( event.clientX - offsetX ) / ( rect.width - offsetX ) ) * 2 - 1;
+		mouse.y = - ( ( event.clientY - offsetY ) / ( rect.bottom - offsetY ) ) * 2 + 1;
+
+		raycaster.setFromCamera( mouse, camera );
+
+		var intersects = raycaster.intersectObjects( interactiveObjects );
+
+		if ( intersects.length > 0 ) {
+
+			var intersection = intersects[ 0 ];
+			var object = intersection.object;
+
+			prepareAnimationData( object, this.controls.center );
+
+			this.animating = true;
+
+			return true;
+
+		} else {
+
+			return false;
+
+		}
+
+	};
+
+	this.update = function ( delta ) {
+
+		var step = delta * turnRate;
+
+		// animate position by doing a slerp and then scaling the position on the unit sphere
+
+		q1.rotateTowards( q2, step );
+		editorCamera.position.set( 0, 0, 1 ).applyQuaternion( q1 ).multiplyScalar( radius );
+
+		// animate orientation
+
+		editorCamera.quaternion.rotateTowards( targetQuaternion, step );
+
+		if ( q1.angleTo( q2 ) === 0 ) {
+
+			this.animating = false;
+
+		}
+
+	};
+
+	function prepareAnimationData( object, focusPoint ) {
+
+		switch ( object.userData.type ) {
+
+			case 'posX':
+				targetPosition.set( 1, 0, 0 );
+				targetQuaternion.setFromEuler( new THREE.Euler( 0, Math.PI * 0.5, 0 ) );
+				break;
+
+			case 'posY':
+				targetPosition.set( 0, 1, 0 );
+				targetQuaternion.setFromEuler( new THREE.Euler( - Math.PI * 0.5, 0, 0 ) );
+				break;
+
+			case 'posZ':
+				targetPosition.set( 0, 0, 1 );
+				targetQuaternion.setFromEuler( new THREE.Euler() );
+				break;
+
+			case 'negX':
+				targetPosition.set( - 1, 0, 0 );
+				targetQuaternion.setFromEuler( new THREE.Euler( 0, - Math.PI * 0.5, 0 ) );
+				break;
+
+			case 'negY':
+				targetPosition.set( 0, - 1, 0 );
+				targetQuaternion.setFromEuler( new THREE.Euler( Math.PI * 0.5, 0, 0 ) );
+				break;
+
+			case 'negZ':
+				targetPosition.set( 0, 0, - 1 );
+				targetQuaternion.setFromEuler( new THREE.Euler( 0, Math.PI, 0 ) );
+				break;
+
+			default:
+				console.error( 'ViewHelper: Invalid axis.' );
+
+		}
+
+		//
+
+		radius = editorCamera.position.distanceTo( focusPoint );
+		targetPosition.multiplyScalar( radius );
+
+		dummy.position.copy( focusPoint );
+
+		dummy.lookAt( editorCamera.position );
+		q1.copy( dummy.quaternion );
+
+		dummy.lookAt( targetPosition );
+		q2.copy( dummy.quaternion );
+
+	}
+
 	function getAxisMaterial( color ) {
 
 		return new THREE.MeshBasicMaterial( { color: color, toneMapped: false } );

+ 19 - 4
editor/js/Viewport.js

@@ -59,7 +59,7 @@ function Viewport( editor ) {
 
 	//
 
-	var viewHelper = new ViewHelper();
+	var viewHelper = new ViewHelper( camera, container );
 
 	//
 
@@ -190,6 +190,8 @@ function Viewport( editor ) {
 
 		if ( onDownPosition.distanceTo( onUpPosition ) === 0 ) {
 
+			// only test 3D objects if there is no UI interaction
+
 			var intersects = getIntersects( onUpPosition, objects );
 
 			if ( intersects.length > 0 ) {
@@ -297,6 +299,7 @@ function Viewport( editor ) {
 		signals.refreshSidebarObject3D.dispatch( camera );
 
 	} );
+	viewHelper.controls = controls;
 
 	// signals
 
@@ -694,14 +697,26 @@ function Viewport( editor ) {
 		requestAnimationFrame( animate );
 
 		var mixer = editor.mixer;
+		var delta = clock.getDelta();
+
+		var needsUpdate = false;
 
 		if ( mixer.stats.actions.inUse > 0 ) {
 
-			mixer.update( clock.getDelta() );
-			render();
+			mixer.update( delta );
+			needsUpdate = true;
+
+		}
+
+		if ( viewHelper.animating === true ) {
+
+			viewHelper.update( delta );
+			needsUpdate = true;
 
 		}
 
+		if ( needsUpdate === true ) render();
+
 	}
 
 	requestAnimationFrame( animate );
@@ -727,7 +742,7 @@ function Viewport( editor ) {
 
 			renderer.autoClear = false;
 			renderer.render( sceneHelpers, camera );
-			viewHelper.render( renderer, camera, container );
+			viewHelper.render( renderer );
 			renderer.autoClear = true;
 
 		}