How can you get an exact rotation of 90 degrees?

I know there are many posts about the direction of a spatial but I found something new that i think is not mentioned in previeous posts. The problem is that when you rotate a vector you cannot have accurate results. for example I tried to rotate (0,0,1) 90 degrees in axe Y but the result was not (1,0,0) but something like (0.9999996,0,0). Heres a part of my code:

[java]
public class Robot extends AbstractControl{

private Vector3f direction = new Vector3f(0, 0, 1);
public void turnLeft(){
Quaternion rotateLeft = new Quaternion().fromAngleAxis(FastMath.HALF_PI, Vector3f.UNIT_Y);
spatial.rotate(rotateLeft);
rotateLeft.mult(direction, direction);
//system
System.out.println("direction: " + direction);
}
}
[/java]

My explanation is that FastMath.HALF_PI does not give you exactly half a pi so you cant have exactly 90 degrees rotation. So what we do for this? note that in my game is very important for my spatial to rotate exactly 90 degrees so it can have one of the following 4 directions: “north, east, south, west”.

Try:


90*FastMath.DEG_TO_RAD;

EDIT:

You're other option is to set rotation using:


Node.lookAt();

And set the direction to 1,0,0 for instance

EDIT: It's worth mentioning that you will have to adjust the direction based on the node's current local translation… but it would work. Probably something like:


node.lookAt(node.getLocalTranslation().add(1,0,0));
node.lookAt(node.getLocalTranslation().add(-1,0,0));
node.lookAt(node.getLocalTranslation().add(0,0,1));
node.lookAt(node.getLocalTranslation().add(0,0,-1));

didn’t work. the difference is that now its (0.99999998, 0, 0) instead of (0.99999994, 0, 0)

EDIT: sorry my answer was before your edit. I ll try your other suggestion. I believe that lookAt() will work!

1 Like
@SeriousGamer said: didn't work. the difference is that now its (0.99999998, 0, 0) instead of (0.99999994, 0, 0)

It didn’t work for 90*DEG_TO_RAD?

Or lookAt?

Or both?

Game mathematics is never clean, you will never get exact results.
(just give up on that, right now)

Only thing you can do is make sure that calculations errors cannot add up to much.

2 Likes

My brain’s not working this morning, sorry.

1 Like
@sgold said: My brain's not working this morning, sorry.

Me too =( Got a bunch of sickies running around the house… or in bed is more like it… and lucky me, I’m starting to feel quite lovely myself =(>

If you only move in 4 directions you can just set the correct value instead of rotating.

My bet is that if you had never output the axes in the log you would have never noticed this in your game.
This result can be due to computation approx (PI is an approx already), and to float imprecision…and probably both.

Do you realize how much the difference between (0.99999994, 0, 0) and (1.0,0,0) is negligible?
Let’s say you have a spatial that goes along that axis and start at 0,0,0, its trajectory will be diverted by 6 world unit when it reaches (100 000 000, 0, 0). as in hundred million world units.

Even if you consider that the approximation is linear (and it’s most probably not since you never had the same value), if the errors adds up you’ll lose 0.00000006 radians on each rotation. So for one complete turn that’s 0.00000024 rad. that’s 0.0000137496 degrees, so your character would have to make 72729 complete turn to have a 1 degree difference…
…and still… I bet you wouldn’t notice since it’s a facing rotation.

IMO you’re pretty safe with that approximation.

1 Like

In my maze game, all rotations are 90 degrees. To avoid accumulating roundoff errors, I have a method which clamps the player’s direction to one of the four cardinal directions after each rotation.

3 Likes

hint: you can do different thing…
you can have hiearchy something like this
rootNode

  • playerNode
    • geometry

you can move playerNode in 4 directions and still have 0 rotation (so you move it to the left, so NOT rotate left and then forward)
then you can rotate geometry only to trick player to looks like rotation

next thing you can do, each step get spatial’s local translation and then round it, it wont be visible and you can correct rotation error

I read your posts and they are really usefull. The problem with the rotation is not just in the degrees but in the translation too. So I ll try to round the translation for each step and I ll post my solution when it’s ready. I hope it will work. Thank you!

Here’s a part of my code as I promised:

[java]
public class Robot extends AbstractControl{
private boolean isTurning = false;
private float tpf;
private Vector3f direction;

private Vector3f targetRotation;

public void turnLeft(){
if(direction.distance(targetRotation) < .10){
spatial.lookAt(spatial.getLocalTranslation().add(targetRotation.normalize()), Vector3f.UNIT_Y);
direction = targetRotation.normalize();
isTurning = false;
}
else{
Quaternion rotation = new Quaternion().fromAngleAxis(tpf, Vector3f.UNIT_Y);
spatial.rotate(rotation);
calculateDirection();

    }
}

protected void controlUpdate(float tpf) {
this.tpf = tpf;
if(spatial != null){
if(isMove){
move();
}
if(isTurning){
turnLeft();
}
}
}

public void setTargetRotation(){
targetRotation = new Quaternion().fromAngleAxis(FastMath.HALF_PI, Vector3f.UNIT_Y).mult(direction);
}

public void calculateDirection(){
direction = spatial.getLocalRotation().mult( new Vector3f(0,0,1) );
System.out.println("direction = " + direction);
}
}
[/java]
Notes: the field isTurning is set to true through a set method in simpleInitApp(). As I tested this code works fine. If there is a better way please tell me.

Hmmm… it seems like you do math that you then just have to undo again.

What is the actual affect you are trying to achieve? You will probably be happier not translating rotations from quaternions and to quaternions and from quaterions and to quaterions again. Just use quaternions really.

@pspeed said: Hmmm... it seems like you do math that you then just have to undo again.

What is the actual affect you are trying to achieve? You will probably be happier not translating rotations from quaternions and to quaternions and from quaterions and to quaterions again. Just use quaternions really.

Is there a way to compare Quaternions to each other?

well there is equals,

anyway please try to explain what you want to do, like the bigger picture, cause I have the feeling that you might not just take a slight detour here, but are driving in the opposite direction of your target

I want to rotate the spatial smoothly exactcly 90 degrees to the left and for each frame i want to have the direction of the spatial so i can move it to this direction. It works but I have the feeling that something is not right.

Ah ok,

Since I assume you need exactl results I would do this.

Create quaternions that represent 0,90,180,270 ect degree
Then you can simple use the slerp method of quaternions to interpolate between 90 and 180 for example (quaternions are interpolateable, thats the main benefit against rotation matrices)

to get the forward dir you can then simply
new Vector (0,0,1 ) //forward in local space
worlddir = currentRotation.mult(localdir)
// and you have the vector in global space after this.

Since this would use predefined rotations no errors would add up in the rotation.
-> Of course you could also determine the next rotation by
currentrot mult rotation90degree
-> this would give you the current rotation with additiona 90 degree rotation applied to it.

2 Likes

Yeah, what he said. :slight_smile: