ThreeJS oribital camera short rotation

独自空忆成欢 提交于 2019-12-07 23:06:49

问题


I have an orbital camera that orbits are a globe. There are several markers on the globe that the user can click on, and the camera will move to that point.

Using TweenMax for the animation like this -

 TweenMax.to(currentPos, 3, {
     theta:targetPos.theta, 
     phi:targetPos.phi, 
     radius:targetPos.radius, 
     ease:Circ.easeIn, 
     onComplete:btnZoomComplete,
     onUpdateParams:["{self}"], 
     onComplete:SataliteTweenComplete, 
     onUpdate: function(tween) {
       controls.setThetaPhi(tween.target.theta, tween.target.phi, tween.target.radius);
     }
});

This works great, however is doesn't take into consideration the shortest route to get there. So it can quite often go 'round the back' of the globe.

ThreeJS seems to measure the angle in a really strange unit system: 0, 1.57 (equivalent to 90 degrees), 3.14 (eq 180dg), then after 3.14 is jumps to -3.14, -1.57 (eq to 270dg), then back to 0... So this blowing my mind on how to work it out.

For example, say the camera is at 2.6 and it needs to go over to -2.61, at the moment the camera will animate CCW (2.6 to -2.16), where as visual it needs to animate CW, which would move from 2.6 to 3.14, -3.14 then to -2.61.

Any help on this would be really appreciated.

I guess there are two problems, how to work out which way to go round, but then how to actually animate across from 2.6 -> 3.14, jump to -3.14 seamlessly -> -2.61


回答1:


So that "strange unit-system" is just radians and it's quite common to measure theta/phi values in a range from -180° to 180° and -90° to 90° (think latitude/longitude, same thing). The conversion is simple:

angleDegrees = radians / Math.PI * 180;
radians = angleDegrees / 180 * Math.PI;

Now the tweening-library will just interpolate from one value to the other and doesn't know what these values represent. So it simply can't know how to handle the shortest path when it comes to rotations. However, you can do this before starting the tween.

Say we animate from 2.6 to -2.6 (or 149° to -149°).

var from = 2.6, to = -2.6;

The direction and angular distance for the animation can be calculated as

var distance = to - from; 
// === -5.2

A negative value here means counterclockwise, and 5.2 (~298°) is the "distance" the camera will travel. Now keep in mind that any angle plus or minus 360° (2 * Math.PI) will essentially land you at the same position. So lets try:

var distance = (to + 2 * Math.PI) - from; 
// === 1.083185307179586 (~62°)

So, if you rotate from your position at 2.6 to -2.6 + 2 * Math.PI (or, from 149° to -149° + 360° = 211°), you will get a clockwise animation with a shorter path.

To make sure that all values stay in their allowed range, we change the onUpdate-function a little bit to wrap around properly:

controls.setThetaPhi(
    tween.target.theta % Math.PI, 
    tween.target.phi % Math.PI, 
    tween.target.radius);

You will probably also want to update the currentPos value with the actual values before the animation starts and below computation happens.

What's left to do is solving this for the general case, so to find out when to do the clockwise and counterclockwise rotation. To see if the other way around would be shorter, we just need to see if the distance would be greater than 180°:

if (Math.abs(to - from) > Math.PI) {
  if (to > 0) { // if to is positive we remove a full-circle, add it otherwise
    to = to - 2 * Math.PI;
  } else {
    to = to + 2 * Math.PI;
  }
}


来源:https://stackoverflow.com/questions/39786475/threejs-oribital-camera-short-rotation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!