[Solved] Rotation: Interpolate From currentViewDirection to desiredViewDirection

Lets say i have a fat character, he cant instantly look at “commanded” direction,

he can only rotate 60 degrees per second.



Input:

A = unit vector currentViewDirection : where character current looks at.

B = unit vector destinationViewDirection : final destination the character wants to look at.

float rotateSpeed : 60 degrees per second ;

boolean direction : will rotate to the left or right direction



so i want to find :



I = unit vector nextFrameInterpolatedViewDirection



attempt :

Theta = degreeBetweenCurrent/DestinationViewDirection = acos( A * B )



Phi = degrees until we reach theta based on rotate speed.



phi = acos ( a * i )

I = cos(phi) / a



is this the way to go?

I think the easiest would be making two quaternions and then using the slerp method to interpolate between them.

1 Like

Normens solution is of course easier but if you want to use the angles/second method. Then I would do this:



1 - Use dot product to find the angle between the 2 vectors

2 - Find the angle per frame that needs to be moved, by doing this:



degrees/second * second/frame = degrees/frame



i.e

60 * tpf;



3 - Turn that angle into a Quaternion around the axis of rotation



4 - Multiply that Quaternion by the initial vector, this gives the new direction vector.



5 - Once this vector is almost parallel to the destination vector then you can lock it to the destination and stop rotating. You can probably just do another dot product, and when the angle is very small you know you are there. You can also use the cross product if you want.



There may be a better way, I haven’t looked into it that much

2 Likes

yeah i did that :



[java]

public void rotateTowardsSlowly(Vector3f nextDirection, float tpf)

{

float rotateAmount = tpf * (FastMath.DEG_TO_RAD * 360); //360 deg per sec.

float leftRotationDistanceFromDestination = nextDirection.angleBetween(NodeUtilities.getForward(p2).normalizeLocal());



rotateAmount = Math.min(leftRotationDistanceFromDestination, rotateAmount);

rotatePlayerQuaternion = new Quaternion().fromAngleAxis(rotateAmount, NodeUtilities.getUp(p2));

p2.rotate(rotatePlayerQuaternion);

}

[/java]



It works correctly however the player now rotates only LEFT to reach the target destination.

If i press Up, Left, Down, Right it rotates correctly doing a 90 degree turn at each command.



If i press Up, Right, Down, Left it will rotate (left) doing a 270 degree turn, this is really slow since the player will have to do 4 turns to carry out those 4 commands instead of 1 turn.



So the problem is i cant find the direction i should turn, should i turn “Left” or turn “Right” to reach the the target direction faster.



angleBetween doesn’t tell us if it a “positive angle” so turn left, or a “negative angle” so turn right.

you can find if a vector is located to the left/right of another vector by doing a cross product and comparing the signs (+ve and -ve of the direction from the axis).



Note: a x b and b x a



2 Likes

ok done :



if (currentDirection.cross(nextDirection).y < 0) rotateAmount = -rotateAmount;

New problem:

I cant apply the quaternion to a character control. I tried :



Vector3f newViewDirection = rotatePlayerQuaternion.mult(playerPhysics.getViewDirection());

playerPhysics.setViewDirection( newViewDirection );



However it doesn’t work, it rotates endlessly.



Before in my working example i applied the quaternion to the spatial p2.



p2.rotate(rotatePlayerQuaternion);



Quaternions work but only with spatials. why cant i apply them to a vector with a simple multiplication like “Math for dummies” says.

Well effectively what you are doing is the same as if you constantly add a vector to another vector. In that case you get constant movement, in this case you get constant rotation.

1 Like

i think it was my fault in the code, instead of playerPhysics.getViewDirection() i tried using

currentDirection and it works.



[java]

Vector3f newViewDirection = rotatePlayerQuaternion.mult(currentDirection);

playerPhysics.setViewDirection( newViewDirection );

[/java]