Help w/ Advanced Rotations

Hi! First post. Recently started with Three.js, no background in 3d, but am an experienced programmer. I’m attempting to develop an app for “Flow Arts” which emulates moving object positions and rotations from point to point. I’m up against the final hurdle, ROTATIONS!

Here’s what I have to work with:
~ 26 points from radius/phi/theta, which were based from a Cube and collapsed into a sphere (plus the center point, but that’s irrelevant currently) and I am
able to animate from any of the points on the sphere to another (with the exception of the furthest point, which I’ve disabled from selection)
~ Each point is currently an object which uses lookAt() and faces toward the center of the sphere, giving me a rotation for each destination point
~ 25 thin Torus’ which visually provide paths between all of the points, and rotation is generated using coordinates from 3 of the points. I’m also able to determine which Torus is associated with the path between two points, making that rotation available for computations

Here’s the goal: Lets say I have a user defined value setting the rotation.
~ 0 would be the equivalent of calling lookAt() on center of sphere with each frame.
~ 1 would rotate the object an additional 180 degrees in the direction of the destination point. (In flow arts, we call this “Spin” or “Pro-Spin”)
~ -1 would rotate the object in the opposite direction, but end in the same rotation that the previous value would (In flow arts, we call this “Anti-Spin”)
~ I’d like to implement 0.5 and -0.5 as options as well (but likely not anything in between 0.5/1) but I’ll worry about that once the above items can be accomplished

I understand this is likely far beyond me, and is probably no easy feat. I started with using Quaternion Slerps going from one rotation to the other (expecting it to emulate sphere.lookAt() w/ each frame) but depending on the angle that we’re animating around the circle, the rotation was diagnal and didn’t work the way I expected. The start and end rotation was correct though. I’ve tried playing with some other things but haven’t gotten anywhere.

This is literally the final hurdle before I can start piecing the rest of it together, and would really appreciate some help! Heck, I’m so frustrated I’d be willing to pay someone a bit to help me get these goals accomplished lol. This is just a personal project that will be open source when complete, and no financial gains will be made. Thanks in advance to anyone that can help get me going!

Here is what I have so far…
https://pastebin.com/aAeS7L5z

I’ve now used Slerp, QuaternionKeyframeTrack, as well as several methods I wrote to manually interpolate between the rotations. I’m getting odd results from all of them, and strangely enough they all seem to be pretty similar, where the object has a very odd motion at certain angles.

I guess I’ll just have to roll with it, at least for now.

(Also looks like I’m gonna roll with Keyframes for adding rotations, multiply, applyFromAxisAngle, etc.)

Read it several times. Although it is a very detailed description, I lack the necessary imagination to visualize the problem (and there is no minimal working example to debug).

  • I’m not sure what does “animate from any of the points on the sphere to another”. Do you move some object (e.g. a spaceship), or you move the camera?
  • Rotations in 3D space are more complex. For example I cannot understand the meaning of “rotate the object an additional 180 degrees in the direction of the destination point”.
  • Also it is hard to understand “the object has a very odd motion at certain angles” without seeing the motion and without knowing what you consider as “normal motion”.
  • A minimal debuggable example would be very helpful. Or an illustration that shows what is animated and how it is expected to be rotated.

PS. I’m not familiar with flow arts motions, so this might be the reason for my confusion. I’m sorry about my ignorance.

1 Like

Thanks for taking a look, and good points. A pastebin definitely isn’t sufficient.

I crudely slapped this together, but its working.

Note how the moving object starts and ends at the correct angle, but it “wobbles” and doesn’t stay aligned with the plane. Many of the planes work as expected, but some of them are even worse than the demo shows.

Comment out lines 295-300 for it to randomly select the next destination point and move around (instead of the 2 points I hacked in as a demo) – You can also change the speed on line 243: ttotal

The goal is to remain aligned with the plane, and the next goal is to rotate additionally both directions while remaining aligned with the plane, in between the initial and destination point (180, 360 degrees, 540, etc.)

Just realized, I can use the points connected on the plane as a reference for the rotations (since I call lookAt center of sphere on each one), and build Keyframe Tracks (or slerp with a lot more logic) – Just need to order them correctly. This won’t eliminate all of the wobbling, but the worst ones come from longer destinations and I can add anything in between them as frames. Should be able to logically build the tracks to also spin additional 180, 360 and beyond degrees.

If you or anyone else has a better method to calculate the rotation based on the plane (large / skinny torus in the demo) to completely eliminate the wobbling, in addition to setting a -180 to 180 or 360 adjustment, please share or point me in the right direction. I imagine this could also simplify a lot of the code, compared to the route I’m about to go down.

I might try to look at it tomorrow (unless someone answers meanwhile). Just to clarify, the scenario is:

There are two points in space, on a circle, which center is (0,0,0). You have a cylinder at one of the points and the cylinder points towards (0,0,0). You want to move the cylinder smoothly along the circle until it reaches the other point. While moving the cylinder is always pointing towards (0,0,0). This, the three points, the circle and the cylinder’s axis are always in one and the same plane.

Is my understanding correct?

If yes, would you mind suggestions that do not use mixers and clips? Especially if these suggestion lead to much shorter and easier to manage code?

Yes – But it needs to point in any of 360 (or -180 to 180, radians, etc.) in relation to the plane, to accomplish the next and final goal, or some way to apply that. I’m sure there’s a mathematical solution, or maybe something built into Three.js I haven’t found yet, but I didn’t exactly take Trig and hey… :smiley:

I would absolutely love something simpler, and not use clips / mixer / keyframetrack. I’m dreading the idea of using it, but atm seems like the easiest solution for the approach I’m currently looking at.

Also… It won’t necessarily be using (0,0,0) as the center, especially the final product as multiple “props” will be animated, but I’m guessing that doesn’t matter and you were just giving examples / clarification.

Oh, and I’d gladly throw $100+ (more if it took a lot of work) someone’s way if they were able to write a solution for this final road block!

Here’s where I’m at…

First animation shows a plane which is “clean,” second animation there’s is a very obvious wobble.
Third and Fourth repeats the previous, but shows what “Anti-Spin” is (Rotating the opposite direction of the path)

With this new code structure, and the questions you asked before, ignore my follow up about controlling the angle. At this point, yes I just need to figure out how to clean up that wobble.

Quaternion.Slerp doesn’t seem to be working as expected at some angles.

I tried to understand your code, but got lost. Instead, I decided to make a new example. It has random points and motion is done between one point and randomly selected another point.

The target point flashes. ‘Hero’ is the name of the moving cylinder. I’ve added an arrow so that it is easier to see whether motion is fluctuating.

The motion is boiled down to just 4 commands (see lines 164-174):

var angle = THREE.MathUtils.mapLinear( t, startTime, endTime, startAngle, endAngle );
hero.position.x = r * Math.cos(angle);
hero.position.y = r * Math.sin(angle);
hero.lookAt(0,0,0);

Live demo:
https://codepen.io/boytchev/full/vYwERaE

image

I’m not sure whether this would be helpful, but nevertheless, it was a good exercise to me.

Just looked again at your code. Could you try these two changes:

Change 1, near line 248, rotatate the geometry:

new THREE.CylinderGeometry( 0.1, 0.1, 3.5, 32 ),
   ↓
new THREE.CylinderGeometry( 0.1, 0.1, 3.5, 32 ).rotateX(Math.PI/2),

Change 2, near line 422, add lookAt before renderer.render:

renderer.render( scene, camera )
   ↓
torus.lookAt(0,0,0);
renderer.render( scene, camera )

That’s a pretty cool demo, but I can’t use lookAt() as it will rarely be looking at the center.

My points and rotations are based from Phi / Theta, and they appear to all be positioned and rotated perfectly. The problem is using Quaternion.Slerp() in between the angles, causes the wobble. When I tried applying percentages to the difference of two sets of Phi / Theta, I had a similar result.

Is there a way to interpolate between two sets of Phi / Theta? I’m guessing the Radius would need to be involved somehow in the math.

I don’t understand. lookAt can look at any direction, not only towards (0,0,0)

Of course, but then I’d need to calculate the X / Y / Z of where its supposed to look, which isn’t out of the question if I could calculate those :smiley:

Did you view the last demo and watch until about 10 seconds in? Notice the “Anti-Spin” that’s going on? You’ll have to pan the camera to the side to understand. I have to apply rotations like that (and in varying ways). Hence, looking at one specific point isn’t going to work.

For anyone stumbling upon this: I finally solved all of the issues, including specifying degrees for rotation. Positive for Pro-Spin, and Negative for Anti-Spin. Zero has the same effect as Center.lookAt()

The answer was Spherical.setFromCartesianCoords in addition to my severe lack of understanding Spherical vs Cartesian coordinates.

Here’s a snippet:

    model.position.copy(vectorStart).applyAxisAngle(normal, perc * angleEnd).add(offset)
    // Animates between points - This uses sphericals, need to view example for full code
    
    // This is where the rotation magic happens
    rot.copy(vectorStart).applyAxisAngle(normal, 
      THREE.MathUtils.degToRad(rotation.current) + 
      perc * angleEnd + 
      THREE.MathUtils.degToRad(rotation.perform) * perc ).add(offset)

    // Convert position to rotation
    sph1.setFromCartesianCoords( rot.x - offset.x, rot.y - offset.y, rot.z - offset.z )
    a1x.setFromAxisAngle(axis1, sph1.phi )
    a1y.setFromAxisAngle(axis2, sph1.theta )
    model.quaternion.copy(a1x).premultiply(a1y)

And a full functional demo where it moves between random points, with an additional -180 rotation. Variables near the top to play with. The code should be much easier to follow along with compared to prior examples.

Oh and I offered to send Pavel a tip over PM for his help since I did find a very hacky way using lookAt() and he got me thinking outside of the box, he said no.

4 Likes

Here’s a “final” demo before I start ripping it up for reusability and working on UI, models, etc. Finally got easing between plane changes cracked.

1 Like