Weird offset get added to rotation calculation

hi there, using this code i have weird offset getting added,

each time i turn the same direction, it turns a bit more than 90deg,

so if one keep rotating the same direction again and again, the angle gets wrong…



it can be tested here

(set rotate speed higher, and keep rotating right for ex… (W,A,S,D keys))

(Q and E keys are there for debug (strafe left/right) they shouldn’t be used)



private final float ROTATION_STEP = 90;
private float rotationSpeed = 100f;
private float[] tmpAngles = new float[3];

if (KeyBindingManager.getKeyBindingManager().isValidCommand("rotateLeft", false))  {
   isMoving = true;
   toRotate = ROTATION_STEP;
   dir = Direction.LEFT;
}

if (dir == Direction.LEFT) {
  float value = 0;
  value = rotationSpeed*tpf;
  toRotate -= value;
  tmpAngles[0] = 0;                            // X
  tmpAngles[1] = value * FastMath.DEG_TO_RAD;  // Y
  tmpAngles[2] = 0;                            // Z
  tmpRotationQuat.fromAngles(tmpAngles);
  playerNode.getLocalRotation().multLocal(tmpRotationQuat);
  if (toRotate <= 0) {
  isMoving = false;
}



full code and be seen from here

any idea what could cause this ?
i'm just trying to rotate 90deg here.. animated.

tnx

I didn't run it but it looks like it would overrun slightly on the last rotation because it doesn't check if you have gone past toRotate until after it has done it.

Maybe try this


if(value >= toRotate) {
  value = toRotate;
  toRotate = 0;}
else {
  toRotate -= value;
}


in place of


toRotate -= value;



Also you might find that you need to normalize the localRotation once in a while, but I doubt that is your problem right now.

tnx !

it work well for rotating left, no  more problem there, but curiously,

it doesn't work with rotate right ?

what am i missing there ? :wink:

it's almost the same code…


if (dir == Direction.RIGHT) {  // rotate 90deg right
   float value = 0;
   value = rotationSpeed*tpf*-1;
   //toRotate += value;
   if (value >= toRotate) {
      value = toRotate;
      toRotate = 0;}
   else {
   toRotate += value;
   }
   tmpAngles[0] = 0;                            // X
   tmpAngles[1] = value * FastMath.DEG_TO_RAD;  // Y
   tmpAngles[2] = 0;                            // Z
   tmpRotationQuat.fromAngles(tmpAngles);
   playerNode.getLocalRotation().multLocal(tmpRotationQuat);
   oldData = results.getCollisionData(0);
   if (toRotate <= 0) {
      isMoving = false;
   }

It looks like value is negative when you're rotating right but toRotate is still positive…so

if (value >= toRotate)


is always false. IMO it would be easier to keep it positive and subtract:


if (dir == Direction.RIGHT) {  // rotate 90deg right
   float value = 0;
   value = rotationSpeed*tpf;

   if (value >= toRotate) {
      value = toRotate;
      toRotate = 0;}
   else {
   toRotate -= value;
   }
   tmpAngles[0] = 0;                            // X
   tmpAngles[1] = -value * FastMath.DEG_TO_RAD;  // Y
   tmpAngles[2] = 0;                            // Z
   tmpRotationQuat.fromAngles(tmpAngles);



Probably you could combine those left and right sections into one, might simplify it a bit.

too strong :slight_smile:

thanks a lot!

works like a charm now, and i can understand what was wrong… just great :slight_smile:

@alric,

there's one more tricky thing i can't figure…

if you could explain this one too that'd be great…

i noticed when i walk forward until i reach the wall, then u-turn and repeat this again and again,

Z axis get offset and little by little i get out of the center.

sorry about my english, i'm trying to figure how i could say this best …



when i walk straight forward, only X axis should change… (+ or -)… but here i see Z getting strange offset too…

here's the code i use:


toMove = 2.45f
playerSpeed = 4f

if (dir == Direction.FORWARD) {
   float value = 0;                   
   value = playerSpeed*tpf*-1;                     
   toMove += value;
   playerNode.getLocalTranslation().x += cam.getDirection().x * toMove*-value;     
   playerNode.getLocalTranslation().z += cam.getDirection().z * toMove*-value;
   if (toMove <= 0) {
   isMoving = false;
}



any idea what could cause this?
is this the same kind of problem ? "value" would get > than "toMove" ?
i tryed similar workaround as for rotations but that didn't seem to help?
or would that be because of initial rotation/position is wrong, and movement code while being ok just move along incorrect initial position thus resulting in getting the player out of the center ?

.. i can see the Z axis getting offset (when it shouldn't), but i don't have any clues as to why :/

So it starts off about right, but gets less straight the more you turn?

If so that sounds like your camera is never coming exactly back to true at the end of a turn.

Going off this code I'd guess that's a build up of tiny rounding errors. This is kinda inevitable when you are not referencing any fixed value.



In a turn, each frame you apply a small rotation to an unknown quaternion (we're never sure exactly what localRotation is after you first turn). Since the operations are not perfectly accurate, you will end up with vectors like (0.99999, 0, 0.00002) where you should have (1, 0 0). It gets worse over time as each rotation adds another tiny error.



There are a few options to combat this, but I'd say if you are only ever rotating about a single axis, then by far the easiest way is just to store the current angle. That way you know that at the end of each turn you have rotated by the exact angle you wanted to. So just add a new variable currentAngle, and do your rotations something like this:


   tmpAngles[0] = 0;                            // X
   tmpAngles[1] = currentAngle;  // Y
   tmpAngles[2] = 0;                            // Z
   tmpRotationQuat.fromAngles(tmpAngles);
   playerNode.setLocalRotation(tmpRotationQuat);

Also unless you're sure you want to move in the direction of the camera, I would change your move code to use the playerNode's direction. Even though they are attached it just seems clearer and less error prone (and it means you can do things with the camera if you want to):



playerNode.getLocalTranslation().x += playerNode.getWorldRotation().getRotationColumn(2).x * toMove*-value;     
playerNode.getLocalTranslation().z += playerNode.getWorldRotation().getRotationColumn(2).z * toMove*-value;

thanks, i tried your method with playerNode.getWorldRotation().getRotationColumn(2).x

but i’m still getting weird offset to Z axis when i move forward.

i made a new webstart with printf() of player posititon each new move.

if you can activate java console and test it you will see that.

the new webstart: here

code: here

why moving forward (toward X) would push my player to the side by a small amount (toward Z) in same time each new move ?





maybe i should start a new thread? because all rotation problem are solved, this is about moving forward…

but since it seems it’s the same kind of problem where i’m getting weird offset getting added each new move,

i thought i could try to ask here. if needed someone tell me, i’m make a new thread.