1

Following up from my original post Three.JS Object following a spline path - rotation / tangent issues & constant speed issue, I am still having the issue that the object flips at certain points along the path.

View this happening on this fiddle: http://jsfiddle.net/jayfield1979/T2t59/7/

function moveBox() {
if (counter <= 1) {

    box.position.x = spline.getPointAt(counter).x;
    box.position.y = spline.getPointAt(counter).y;

    tangent = spline.getTangentAt(counter).normalize();

    axis.cross(up, tangent).normalize();

    var radians = Math.acos(up.dot(tangent));

    box.quaternion.setFromAxisAngle(axis, radians);

    counter += 0.005
} else {
    counter = 0;
}

}

The above code is what moves my objects along the defined spline path (an oval in this instance). It was mentioned by @WestLangley that: "Warning: cross product is not well-defined if the two vectors are parallel.".

As you can see, from the shape of the path, I am going to encounter a number of parallel vectors. Is there anything I can do to prevent this flipping from happening?

Community
  • 1
  • 1
jayfield1979
  • 355
  • 1
  • 5
  • 16
  • See if this works for you: http://jsfiddle.net/T2t59/8/. – WestLangley Jul 28 '14 at 14:24
  • That worked great. I see you have removed some vectors where the flipping occurred. That's fine but in my final application, those values are created dynamically at run time. I removed all the functions that take an array and create the vectors based on the track pieces for the sake of brevity. Is there any way this will work without removing any of the vectors as eventually, there is going to be a lot of dynamically created track! Thanks for your time so far. I appreciate it. – jayfield1979 Jul 28 '14 at 14:34
  • 1
    You have to redo your demo and place the track in the XZ plane with Y up. As you have it, `up` points in the positive x direction. The box's `up` is in the positive y direction. It is a mess. If you do it right, the tangent will always be in the XZ plane, up will be in the Y direction, and the cross product will be well-defined. – WestLangley Jul 28 '14 at 15:03
  • 1
    Also, an easier approach may be to orient your box so the long side points in the positive-z direction. That way, all your need to do is `box.lookAt( point )`, where point is a position further along the track. – WestLangley Jul 29 '14 at 19:06
  • Ooooo that's an interesting approach. Will give that a try too! – jayfield1979 Jul 29 '14 at 22:50

1 Answers1

3

To answer the why question in the title. The reason its happening is that at some points on the curve the vector up (1,0,0) and the tangent are parallel. This means their cross product is zero and the construction of the quaternion fails.

You could follow WestLangley suggestion. You really want the up direction to be the normal to the plane the track is in.

Quaternion rotation is tricky to understand the setFromAxisAngle function rotates around the axis by a given angle.

If the track lies in the X-Y plane then we will want to rotate around the Z-axis. To find the angle use Math.atan2 to find the angle of the tangent

var angle = Math.atan2(tangent.y,tangent.x);

putting this together set

var ZZ = new THREE.Vector3( 0, 0, 1 );

and

tangent = spline.getTangentAt(counter).normalize();
var angle = Math.atan2(tangent.y,tangent.x);    
box.quaternion.setFromAxisAngle(ZZ, angle);

If the track leaves the X-Y plane things will get trickier.

Salix alba
  • 7,536
  • 2
  • 32
  • 38
  • Thanks for this. This will serve the purpose of the application I'm working on for now nicely. The track will eventually leave the XY plane so I'm going to have to keep this in mind. I do take the point @WestLangley made. This demo is a mess. It's tricky because i'm working with a mixture of native geometry and imported meshes from 3DS MAX which just loves to mess up the up axis. I often have to work in 2 plane configurations. I aim to try and sort this soon. Thanks both. – jayfield1979 Jul 29 '14 at 18:05
  • Can you help me just a little more.. In my demo: http://jsfiddle.net/jayfield1979/T2t59/10/ everything looks correct but the boxes were created with the wrong dimensions (x being the longest side when it should be y). If you look at this demo: http://jsfiddle.net/jayfield1979/uM8K9/ they are now the right dimensions (with the y side being the longest) but it now doesn't follow the track with the correct orientation. Is there anything I can do without manually resorting to rotating each box 90 degrees or creating them with the wrong dimensions? Thanks. – jayfield1979 Jul 30 '14 at 13:12
  • Sorry for the second demo see: http://jsfiddle.net/jayfield1979/uM8K9/1/ to see more cleraly what I mean, look at revision 2:http://jsfiddle.net/jayfield1979/uM8K9/2/ and without the MoveBox function being called, the boxes are added along the correct plane/orientation... – jayfield1979 Jul 30 '14 at 13:19
  • Or even better see: http://jsfiddle.net/jayfield1979/uM8K9/3/ to demonstrate how the boxes are oriented correctly for the first 3 seconds until moveBox is called and then they no longer face along the correct orientation. – jayfield1979 Jul 30 '14 at 13:45
  • Try `box.quaternion.setFromAxisAngle(up, angle-Math.PI/2);` – Salix alba Jul 30 '14 at 16:51
  • What can I do if my object is in the XZ plane with Y up? Somehow I cannot get the `Math.atan2(tangent.z,tangent.x)` to work in any combination :( – Balazs Nemeth Nov 22 '16 at 16:18
  • What values do you get for tangent.z and tangent.x? You might need a different vector in the setFromAxisAngle function. – Salix alba Nov 22 '16 at 18:51