Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Three.js drag controls fix distance from camera

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.

like image 601
beek Avatar asked Jan 17 '17 20:01

beek


1 Answers

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!

like image 189
Xenophage Avatar answered Sep 29 '22 14:09

Xenophage