I'm using Three.DragControls to drag an object around a scene. As the object gets dragged it's distance from camera seems to be getting further away.
My question is similar to this unanswered one Drag object locked at certain distance/radius from camera view
Is there a clever way to fix that _intersection.sub( _offset ) a certain distance from the camera in the centre of the scene?
I've added a sphere to the scene
dragSphere = new THREE.Mesh(new THREE.SphereGeometry(200, 60, 40 ),new THREE.MeshBasicMaterial());
dragSphere.name = "dragSphere";
dragSphere.visible = false;
dragSphere.scale.x = -1;
scene.add(dragSphere);
Somewhere in here
function onDocumentMouseMove( event ) {
event.preventDefault();
var offset = $("#container").offset();
var rect = _domElement.getBoundingClientRect();
_mouse.x = ( ( event.clientX - rect.left - (offset.left/2) ) / ( rect.width - rect.left ) ) * 2 - 1;
_mouse.y = - ( ( event.clientY - rect.top ) / ( rect.bottom - rect.top) ) * 2 + 1;
_raycaster.setFromCamera( _mouse, _camera );
if ( _selected && scope.enabled ) {
if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) {
if(_right){
_deltaX = event.x - _startPoint.x;
_deltaY = event.y - _startPoint.y;
_selected.rotation.y += (_deltaX/50);
_selected.rotation.x += (_deltaY/50);
console.log(_selected.position);
_startPoint.x = event.x;
_startPoint.y = event.y;
_lastMoveTimestamp = new Date();
}
else{
_selected.position.copy( _intersection.sub( _offset ) );
_selected.lookAt(camera.position);
}
}
scope.dispatchEvent( { type: 'drag', object: _selected } );
return;
}
_raycaster.setFromCamera( _mouse, _camera );
var intersects = _raycaster.intersectObjects( _objects , true );
if ( intersects.length > 0 ) {
var object = intersects[ 0 ].object;
if(object.type === "Mesh")
if(object.parent)
if(object.parent.type == "Object3D")
object = object.parent;
_plane.setFromNormalAndCoplanarPoint( _camera.getWorldDirection( _plane.normal ), object.position );
if ( _hovered !== object ) {
scope.dispatchEvent( { type: 'hoveron', object: object } );
_domElement.style.cursor = 'pointer';
_hovered = object;
}
} else {
if ( _hovered !== null ) {
scope.dispatchEvent( { type: 'hoveroff', object: _hovered } );
_domElement.style.cursor = 'auto';
_hovered = null;
}
}
}
function onDocumentMouseDown( event ) {
event.preventDefault();
_right = event.which == 3 || event.button == 2;
_raycaster.setFromCamera( _mouse, _camera );
var intersects = _raycaster.intersectObjects( _objects , true );
if ( intersects.length > 0 ) {
_selected = intersects[ 0 ].object;
if(_selected.type == "Mesh" && _selected.parent.type == "Object3D")
_selected = _selected.parent;
if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) {
if(_right){
_mouseDown = true;
_startPoint = {
x: event.clientX,
y: event.clientY
};
_rotateStartPoint = _rotateEndPoint = projectOnTrackball(0, 0);
}
else
_offset.copy( _intersection ).sub( _selected.position );
}
_domElement.style.cursor = 'move';
scope.dispatchEvent( { type: 'dragstart', object: _selected } );
}
else
scope.dispatchEvent( { type: 'nodrag' } );
}
In the part that does the dragging, i.e.
if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) {
_selected.position.copy( _intersection.sub( _offset ) );
_selected.lookAt(camera.position);
}
I need to get it to use the Sphere intersection to apply the position so it drags along the surface of the sphere.
This might not be a full answer, but could get you pointed in the right direction since I am in a similar situation where I was trying to get objects to drag along a plane. I created my own modified version of the DragControls.js function to support passing in a plane as a parameter (renaming it to DragControlsPlane.js first), like so:
THREE.DragControlsPlane = function (_objects, _camera, _domElement, _plane)
Thats at the top of the original DragControls.js. Then comment out the line that initializes the _plane var:
//var _plane = new THREE.Plane();
Then you'll need to comment out the line that shifts the plane to the camera's view (about midway down):
//_plane.setFromNormalAndCoplanarPoint(_camera.getWorldDirection(_plane.normal), object.position);
Then at the bottom rename these to line up with your new function name:
THREE.DragControlsPlane.prototype = Object.create(THREE.EventDispatcher.prototype);
THREE.DragControlsPlane.prototype.constructor = THREE.DragControlsPlane;
And then use the new function in your scripts. The rest of the DragControls already does the rest, but you might need to modify it a little more to work with a sphere. This is working for me, at least for a plane surface. Maybe mr. doob can add this as an actual feature soon, wink wink. Let me know if you get it working for a sphere! I don't expect an upvote on this as it's not the full answer, but hopefully it will help someone out there!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With