Bläddra i källkod

DragControls: Add `rotate` mode. (#27689)

* added rotation to DragControls

* Update misc_controls_drag.html

Clean up.

* updated code per code review see #27689 for details

* Update DragControls.js

Clean up.

* Update DragControls.html

Clean up.

* Update DragControls.html

Fix type.

* Update DragControls.js

* Update DragControls.js

* Update DragControls.js

---------

Co-authored-by: Michael Herzog <[email protected]>
lewibs 1 år sedan
förälder
incheckning
8aef01602b

+ 10 - 0
docs/examples/en/controls/DragControls.html

@@ -111,6 +111,16 @@
 			If set to `true`, [name] does not transform individual objects but the entire group. Default is `false`.
 		</p>
 
+		<h3>[property:String mode]</h3>
+		<p>
+			The current transformation mode. Possible values are `translate`, and `rotate`. Default is `translate`.
+		</p>
+
+		<h3>[property:Float rotateSpeed]</h3>
+		<p>
+			The speed at which the object will rotate when dragged in `rotate` mode. The higher the number the faster the rotation. Default is `1`.
+		</p>
+
 		<h2>Methods</h2>
 
 		<p>See the base [page:EventDispatcher] class for common methods.</p>

+ 63 - 29
examples/jsm/controls/DragControls.js

@@ -12,10 +12,15 @@ const _raycaster = new Raycaster();
 
 const _pointer = new Vector2();
 const _offset = new Vector3();
+const _diff = new Vector2();
+const _previousPointer = new Vector2();
 const _intersection = new Vector3();
 const _worldPosition = new Vector3();
 const _inverseMatrix = new Matrix4();
 
+const _up = new Vector3();
+const _right = new Vector3();
+
 class DragControls extends EventDispatcher {
 
 	constructor( _objects, _camera, _domElement ) {
@@ -28,6 +33,10 @@ class DragControls extends EventDispatcher {
 
 		const _intersections = [];
 
+		this.mode = 'translate';
+
+		this.rotateSpeed = 1;
+
 		//
 
 		const scope = this;
@@ -80,59 +89,71 @@ class DragControls extends EventDispatcher {
 
 			if ( _selected ) {
 
-				if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) {
+				if ( scope.mode === 'translate' ) {
+
+					if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) {
 
-					_selected.position.copy( _intersection.sub( _offset ).applyMatrix4( _inverseMatrix ) );
+						_selected.position.copy( _intersection.sub( _offset ).applyMatrix4( _inverseMatrix ) );
+
+					}
+
+				} else if ( scope.mode === 'rotate' ) {
+
+					_diff.subVectors( _pointer, _previousPointer ).multiplyScalar( scope.rotateSpeed );
+					_selected.rotateOnWorldAxis( _up, _diff.x );
+					_selected.rotateOnWorldAxis( _right.normalize(), - _diff.y );
 
 				}
 
 				scope.dispatchEvent( { type: 'drag', object: _selected } );
 
-				return;
+				_previousPointer.copy( _pointer );
 
-			}
+			} else {
 
-			// hover support
+				// hover support
 
-			if ( event.pointerType === 'mouse' || event.pointerType === 'pen' ) {
+				if ( event.pointerType === 'mouse' || event.pointerType === 'pen' ) {
 
-				_intersections.length = 0;
+					_intersections.length = 0;
 
-				_raycaster.setFromCamera( _pointer, _camera );
-				_raycaster.intersectObjects( _objects, scope.recursive, _intersections );
+					_raycaster.setFromCamera( _pointer, _camera );
+					_raycaster.intersectObjects( _objects, scope.recursive, _intersections );
 
-				if ( _intersections.length > 0 ) {
+					if ( _intersections.length > 0 ) {
 
-					const object = _intersections[ 0 ].object;
+						const object = _intersections[ 0 ].object;
 
-					_plane.setFromNormalAndCoplanarPoint( _camera.getWorldDirection( _plane.normal ), _worldPosition.setFromMatrixPosition( object.matrixWorld ) );
+						_plane.setFromNormalAndCoplanarPoint( _camera.getWorldDirection( _plane.normal ), _worldPosition.setFromMatrixPosition( object.matrixWorld ) );
 
-					if ( _hovered !== object && _hovered !== null ) {
+						if ( _hovered !== object && _hovered !== null ) {
 
-						scope.dispatchEvent( { type: 'hoveroff', object: _hovered } );
+							scope.dispatchEvent( { type: 'hoveroff', object: _hovered } );
 
-						_domElement.style.cursor = 'auto';
-						_hovered = null;
+							_domElement.style.cursor = 'auto';
+							_hovered = null;
 
-					}
+						}
 
-					if ( _hovered !== object ) {
+						if ( _hovered !== object ) {
 
-						scope.dispatchEvent( { type: 'hoveron', object: object } );
+							scope.dispatchEvent( { type: 'hoveron', object: object } );
 
-						_domElement.style.cursor = 'pointer';
-						_hovered = object;
+							_domElement.style.cursor = 'pointer';
+							_hovered = object;
 
-					}
+						}
+
+					} else {
 
-				} else {
+						if ( _hovered !== null ) {
 
-					if ( _hovered !== null ) {
+							scope.dispatchEvent( { type: 'hoveroff', object: _hovered } );
 
-						scope.dispatchEvent( { type: 'hoveroff', object: _hovered } );
+							_domElement.style.cursor = 'auto';
+							_hovered = null;
 
-						_domElement.style.cursor = 'auto';
-						_hovered = null;
+						}
 
 					}
 
@@ -140,6 +161,8 @@ class DragControls extends EventDispatcher {
 
 			}
 
+			_previousPointer.copy( _pointer );
+
 		}
 
 		function onPointerDown( event ) {
@@ -161,8 +184,18 @@ class DragControls extends EventDispatcher {
 
 				if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) {
 
-					_inverseMatrix.copy( _selected.parent.matrixWorld ).invert();
-					_offset.copy( _intersection ).sub( _worldPosition.setFromMatrixPosition( _selected.matrixWorld ) );
+					if ( scope.mode === 'translate' ) {
+
+						_inverseMatrix.copy( _selected.parent.matrixWorld ).invert();
+						_offset.copy( _intersection ).sub( _worldPosition.setFromMatrixPosition( _selected.matrixWorld ) );
+
+					} else if ( scope.mode === 'rotate' ) {
+
+						// the controls only support Y+ up
+						_up.set( 0, 1, 0 ).applyQuaternion( _camera.quaternion ).normalize();
+						_right.set( 1, 0, 0 ).applyQuaternion( _camera.quaternion ).normalize();
+
+					}
 
 				}
 
@@ -172,6 +205,7 @@ class DragControls extends EventDispatcher {
 
 			}
 
+			_previousPointer.copy( _pointer );
 
 		}
 

+ 8 - 0
examples/misc_controls_drag.html

@@ -20,6 +20,7 @@
 		<div id="info">
 			<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> webgl - drag controls<br />
 			Use "Shift+Click" to add/remove objects to/from a group.<br />
+			Use "M" to toggle between rotate and translate mode.<br />
 			Grouped objects can be transformed as a union.
 		</div>
 
@@ -113,6 +114,7 @@
 				container.appendChild( renderer.domElement );
 
 				controls = new DragControls( [ ... objects ], camera, renderer.domElement );
+				controls.rotateSpeed = 2;
 				controls.addEventListener( 'drag', render );
 
 				//
@@ -141,6 +143,12 @@
 			function onKeyDown( event ) {
 
 				enableSelection = ( event.keyCode === 16 ) ? true : false;
+				
+				if ( event.keyCode === 77 ) {
+
+					controls.mode = ( controls.mode === 'translate' ) ? 'rotate' : 'translate';
+			
+				}
 
 			}