Rotation destination problems
Hey everyone, I'm trying to implement something that has been driving me crazy.
I have an object rotating on the Y-axis at all times, and when I enter a certain part of my application, I want the object to rotate and stop at a certain rotation I have defined in a script file. I have already accomplished this, but the problem I have been having is that I want to find the shortest direction to rotate in and I've tried several different approaches but still come up short because my algorithm still breaks depending on different rotational values for my object.
Currently my algorithm is as follows:
RotationCW = rotationDestination - objectRotation;
RotationCCW = (rotationDestination - 2PI) - objectRotation;
if( ABS(RotationCW) < ABS(RotationCCW) )
turnSign = SIGN(RotationCW);
else
turnSign = SIGN(RotationCCW);
Now in my task that handles rotating to the destination within my task manager is the following:
if( objectRotation != rotationDestination )
{
angleAccel = turnSign * objectSpinSpeed;
objectRotation += angleAccel * deltaTime;
if( turnSign < 0 )
{
if( objectRotation < rotationDestination )
objectRoation = roationDestination;
}
else
{
if( objectRotation > rotationDestination )
objectRotation = rotationDestination;
}
}
else
RemoveTask( STOP_ROTATION );
Please something help me, because my head is really hurting now. One problem I've been seeing over and over again is that my turnSign ends up negative when it shouldn't be.
Hi. One way to test it is to ensure that all the rotational angles are in the 0...2PI range. Then you could do the following test:
Or if your angles take any possible values, for example objectRotation = 27.4663f and rotationDestination = -1204.2879f the while loops would take more time than necessary. In that case you could check the fractional portion.
// make sure rotations are in the 0...2PI rangewhile (rotationDestination < 0.0f) rotationDestination += 2*PI;while (rotationDestination > 2*PI) rotationDestination -= 2*PI;while (objectRotation < 0.0f) objectRotation += 2*PI;while (objectRotation > 2*PI) objectRotation -= 2*PI;float angle = rotationDestination - objectRotation;if (angle < 0.0f) angle += 2*PI;if (angle < PI) turnSign = 1; // rotate CCWelse turnSign = -1; // rotate CW
Or if your angles take any possible values, for example objectRotation = 27.4663f and rotationDestination = -1204.2879f the while loops would take more time than necessary. In that case you could check the fractional portion.
float angle = rotationDestination - objectRotation;float b = angle/2PI;float f = fmodf(b, NULL); // get the fractional partif (f < 0) f += 1.0f;if (f < 0.5f) turnSign = 1;else turnSign = -1;
Hey, thanks for posting, I've been having a huge headache all day with this problem. Several of my co-workers have been at it too. I am working with radians, except we're using fixed-point math, so that's why I've been having so much of a problem. I'll take another whack at it and post again should I have another problem.
Hey again, I just tried it but it still doesn't go down the right path at all times. Our Radians are in the range of 0 - 1 or 0 to 1<<16. We have utilities to convert back and forth as well. What else is strange is that some of my destinations are behaving like their used to going CCW or CW. Whenever it goes in the opposite of what it is used to, the object snaps to the rotation, almost as if my update task wrecks it. If you can suggest how I should update the rotation it would help out a lot.
P.S. Sorry for my typos, it was really in the morning and I've been sick all day at work.
P.S. Sorry for my typos, it was really in the morning and I've been sick all day at work.
Hi
So can you say that the fixed point 0 is equivalent to "0 radians" and for example the fixed point 128 is equivalent to "PI radians"? Also destinationRotation and objectRotation represent a radiant value (coded into a fixed number)?
Do you have sin and cos functions available?
Do I understand this correct that when you assign a Task (START_ROTATION) your object should start the rotation. It gains rotational speed and when it reaches the destination position (destinationRotation) it stops the rotation and no longer moves until you send another START_ROTATION?
Quote:Our Radians are in the range of 0 - 1 or 0 to 1<<16
So can you say that the fixed point 0 is equivalent to "0 radians" and for example the fixed point 128 is equivalent to "PI radians"? Also destinationRotation and objectRotation represent a radiant value (coded into a fixed number)?
Do you have sin and cos functions available?
Do I understand this correct that when you assign a Task (START_ROTATION) your object should start the rotation. It gains rotational speed and when it reaches the destination position (destinationRotation) it stops the rotation and no longer moves until you send another START_ROTATION?
Hey I wrote a small simulation of that rotation and you were right. The code I had provided was not correct, sorry about that.
This is the code that produces the correct behavior in my simulation:
I don't know if it's the opmimal solution, but in my case I needed a new variable "objectRotationOld" that stores the "objectRotation" of the last frame.
Note that the function StartRotation(...) takes the new destination position the object should move to. The Function Rotate() is equivalent to what you do inside your task manager. I hope it will work this time.
This is the code that produces the correct behavior in my simulation:
void StartRotation(float destination){ rotationDestination = destination; float a; if (rotationDestination > objectRotation) { a = rotationDestination - objectRotation; if (a < PI) turnSign = 1; else turnSign = -1; } else { a = objectRotation - rotationDestination; if (a < PI) turnSign = -1; else turnSign = 1; } AddTask(START_ROTATION);}void Rotate(){ if (objectRotation != rotationDestination) { objectRotationOld = objectRotation; angleAccel = turnSign * objectSpinSpeed; objectRotation += angleAccel * deltaTime; if (objectRotation > 2*PI) { objectRotation -= 2*PI; objectRotationOld = 0; } if (objectRotation < 0) { objectRotation += 2*PI; objectRotationOld = 2*PI; } if ((rotationDestination - objectRotation < 0 && rotationDestination - objectRotationOld > 0) || (rotationDestination - objectRotation > 0 && rotationDestination - objectRotationOld < 0)) { RemoveTask( STOP_ROTATION ); } }}
I don't know if it's the opmimal solution, but in my case I needed a new variable "objectRotationOld" that stores the "objectRotation" of the last frame.
Note that the function StartRotation(...) takes the new destination position the object should move to. The Function Rotate() is equivalent to what you do inside your task manager. I hope it will work this time.
The task manager works as an event driven callback that is called every frame for a certain module that has a task manager object defined for it. We have tasks that we define in the usual enum fashion. We define what we want to happen one each task within the callback we make for the task manager.
I have a update rotation task that is called every frame, and when I enter different parts of the application, I will remove the update rotation task, calculate my stop rotation strategy values, then add the task for stopping the rotation. Sorry if the details are a little vague, but I can't give away too many details since I didn't write the task manager. Personally I would've wanted to make a badass FSM, cause I have one, except its in C++, and we're not allowed to use C++ here.
I have a update rotation task that is called every frame, and when I enter different parts of the application, I will remove the update rotation task, calculate my stop rotation strategy values, then add the task for stopping the rotation. Sorry if the details are a little vague, but I can't give away too many details since I didn't write the task manager. Personally I would've wanted to make a badass FSM, cause I have one, except its in C++, and we're not allowed to use C++ here.
Hey I tested it earlier this morning and it worked! Thanks so much. The only thing I don't understand though is that every algorithm I have tried doesn't work with 0 radians at all. But everything is great, I'm still sick, but it doesn't matter. I can finally move on with my life, and keep on working. Again, thank you so much.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement