diff --git a/docs/examples/en/controls/DragControls.html b/docs/examples/en/controls/DragControls.html index 067a29a19b67b1..2970bc4dab2fcf 100644 --- a/docs/examples/en/controls/DragControls.html +++ b/docs/examples/en/controls/DragControls.html @@ -111,6 +111,16 @@

[property:Boolean transformGroup]

If set to `true`, [name] does not transform individual objects but the entire group. Default is `false`.

+

[property:String mode]

+

+ The current transformation mode. Possible values are `translate`, and `rotate`. Default is `translate`. +

+ +

[property:Float rotateSpeed]

+

+ The speed at which the object will rotate when dragged in `rotate` mode. The higher the number the faster the rotation. Default is `1`. +

+

Methods

See the base [page:EventDispatcher] class for common methods.

diff --git a/examples/jsm/controls/DragControls.js b/examples/jsm/controls/DragControls.js index f93f7745075561..bd21ef1a97f164 100644 --- a/examples/jsm/controls/DragControls.js +++ b/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 ); } diff --git a/examples/misc_controls_drag.html b/examples/misc_controls_drag.html index 90578cf3436dcc..8462a3cddb97e3 100644 --- a/examples/misc_controls_drag.html +++ b/examples/misc_controls_drag.html @@ -20,6 +20,7 @@
three.js webgl - drag controls
Use "Shift+Click" to add/remove objects to/from a group.
+ Use "M" to toggle between rotate and translate mode.
Grouped objects can be transformed as a union.
@@ -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'; + + } }