Moving objects parallel to projection plane in three.js


I want to move objects along a plane parallel to the projection plane with the mouse. This means during the movement the distance between any picked object and camera projection plane (not camera position) must remain constant. A similar question has been asked: <a href="https://stackoverflow.com/questions/13055214/mouse-canvas-x-y-to-three-js-world-x-y-z" rel="nofollow">Mouse / Canvas X, Y to Three.js World X, Y, Z</a> , but unlike there I need a solution working for arbitrary camera angles and camera/object positions not only for the plane with z=0. It also has to work for orthographic projection. Now I created a fiddle

<a href="http://jsfiddle.net/nmrNR/" rel="nofollow">http://jsfiddle.net/nmrNR/</a>

the code in the mousemove event handler:

var v = new THREE.Vector3( (event.clientX/window.innerWidth)*2-1, -(event.clientY/window.innerHeight)*2+1, 1 ); projector.unprojectVector(v,camera); var dist = circle.position.sub(camera.position,circle.position), pos = camera.position.clone(); pos = pos.add(pos, v.sub(v,camera.position).normalize().multiplyScalar(dist.length()) );

The circle is following the mouse position but its distance to the camera position is constant so it is actually performing a spherical movement. When switching to the ortographic camera (click) it also does not follow the mouse position as expected.


I've modified the questioners excellent working version to work in a more current version (and a little more efficiently for me - just giving back, thanks. At first I found myself using clone to avoid jumpy behavior. Then I noted moving the object back and forth crept it forward so I used an initial click position (to get the distanceTo). There where also issues with warnings saying use addVectors and subVectors, but that was not necessary either.

camPos = cam.position; var mv = new THREE.Vector3((event.clientX / window.innerWidth) * 2 - 1, -(event.clientY/window.innerHeight) * 2 + 1, 1).unproject(cam); var pos = camPos.clone(); pos.add(mv.sub(camPos).normalize().multiplyScalar(initalClickPos.distanceTo(camPos)));

Setting the target object being moved's position to pos will move it from the mouse move position in the current camera plane, but it does in a way rotate as the camera distance is maintained for the object in perspective view.

It still looks a little funky to me so I'm thinking maybe this can be improved further with add and sub being cleaner. Possibly as seen in the others answer posted.

I still have issues with an offset for where I initially click so the position center doesn't pop around, maybe setting the objects pivot temporarily is worth exploring. This is working with r71.


An older question which you might have long solved by now, here is an answer anyway.

You're not using a control like OrbitControls which possibly makes this slightly easier, if only for visualising it in your head. OrbitControls has not only the camera, but also a target object which directs the camera (it is always looking at it, and the y-axis is always up). The movement you want to achieve is perpendicular to the vector from camera to target, rather than the vector to your object which changes as you move the object and whose change explains the circular movement. And handily, OrbitControls provides the math you need.

From <a href="https://github.com/mrdoob/three.js/blob/master/examples/js/controls/OrbitControls.js#L147-L171" rel="nofollow">https://github.com/mrdoob/three.js/blob/master/examples/js/controls/OrbitControls.js#L147-L171</a>, these functions compute a vector which are used to shift the camera and the target (which should work just as well for your object, though you'll probably need to invert the movement). Note that this.object is the camera.

// pass in distance in world space to move left this.panLeft = function ( distance ) { var te = this.object.matrix.elements; // get X column of matrix panOffset.set( te[ 0 ], te[ 1 ], te[ 2 ] ); panOffset.multiplyScalar( - distance ); pan.add( panOffset ); }; // pass in distance in world space to move up this.panUp = function ( distance ) { var te = this.object.matrix.elements; // get Y column of matrix panOffset.set( te[ 4 ], te[ 5 ], te[ 6 ] ); panOffset.multiplyScalar( distance ); pan.add( panOffset ); };

Code is from r.68, if you have an older version it might not work without modification.


  • Double Numerical Integration Error
  • perl one-liner + add condition before edit file
  • Getting connection returns false even when the device has connection
  • Understanding the implementation of memcpy()
  • Mapping shapes from a flat equirectangular panorama to planes within A-Frame
  • How to print a large JPanel in several page
  • preg_split is case insensitive with special characters
  • Bash convert string to timestamp
  • How can I combine values of checkboxes with values of text in php?
  • how to get the absolute position of loaded .obj in three.js?
  • Get Current NT Header Data of running Process with C/C++
  • Algorithm that Generates Unique Serial Number for Each English Word
  • Current x86 privilege level on a custom OS
  • Miller Rabin Primality test in C++ bug?
  • Creating certificate using makecert without pvk file
  • c# Resize parent control when a child pictureBox changes the Image
  • How to search and isolate attributes of FASTA formatted text in R
  • VerifyError: Error #1079: Native methods are not allowed in loaded code
  • Extracting data from a string where the data structure is embedded in the string itself
  • Eclipse Swing WindowBuilder returns error when trying to set border
  • d3.js - Tree Layout - How can I flip it?
  • Are channel sends preemption points for goroutine scheduling?
  • How to normalize a database schema
  • Suspending event listeners
  • VB.NET - RichTextBox - Apply formatting to selected text
  • Give wx.StaticBitmap a transparent background? wxpython
  • AngularJS : transclude ng-repeat inside directive
  • C++ how to get substring after get position of its index
  • Cannot convert a char value to money. The char value has incorrect syntax
  • Simplify where clause with repeated associated type restrictions
  • How to open html table in xls on click of a button
  • Subclassing QGraphicsItem prevents me from being able to use itemAt() on a QGraphicsScene/View
  • align graphs with different xlab
  • Angular 2 constructor injection vs direct access
  • Java static initializers and reflection
  • Change div Background jquery
  • Android Google Maps API OnLocationChanged only called once
  • apache spark aggregate function using min value
  • How can I use `wmic` in a Windows PE script?
  • UserPrincipal.Current returns apppool on IIS