Page 1 of 1

Toolbox GetAxisAngleFromQuaternion

Posted: Fri Jun 17, 2011 9:33 pm
by JanWH
Hello,
i tried to reuse youre code from the EntityRotator and there is something i dont understand about the function

Code: Select all

public static Vector3 GetAngularVelocity(Quaternion start, Quaternion end, float dt);
it should return the the angular velocity between start and end so:

Code: Select all

var direction = Vector3.Normalize( Vector3.Backward*10 + Vector3.Left + Vector3.Down ); // backwards and slightly left down

// get Target direction as Quaternion
var left = Vector3.Cross( direction, Vector3.Up );
var up = Vector3.Cross( left, direction );
var dir = Quaternion.CreateFromRotationMatrix( Matrix.CreateWorld( Vector3.Zero, direction, up ) ); 

// get Faceing direction as Quaternion
left = Vector3.Cross( facingDir, Vector3.Up );
up = Vector3.Cross( left, facingDir );
var face = Quaternion.CreateFromRotationMatrix( Matrix.CreateWorld( Vector3.Zero, facingDir, up ) ); 

 // get Velocity
var axis = BEPUphysics.Paths.PathFollowing.EntityRotator.GetAngularVelocity( face, dir, 1 );

var rot = Quaternion.CreateFromYawPitchRoll( axis.Y, axis.X, axis.Z ); // convert back to Quaternion
Now "rot" should be equal "dir" if face was Vector3.Forward, but thats only true if they point in the same direction if they get to far apart it begins to shake or turns upside down.
And even for short Distances the result may be wrong but i cant figure out why.

btw, thx for the great work so far it rocks.

Re: Toolbox GetAxisAngleFromQuaternion

Posted: Fri Jun 17, 2011 10:00 pm
by Norbo
Assuming facingDir is Vector3.Forward, the resulting bases are:

direction: {X:-0.09901476 Y:-0.09901476 Z:0.9901476} (0,0,1)
left: {X:-0.9901476 Y:0 Z:-0.09901476} (-1,0,0)
up: {X:-0.009803923 Y:0.9901962 Z:0.09803922} (0, 1, 0)

facingDir: {X:0 Y:0 Z:-1}
left: {X:1 Y:0 Z:0}
up: {X:0 Y:1 Z:0}

Note that these two configurations are around 180 degrees offset from each other. That's around pi radians around the Y axis (with a little x and z rotation due to the slightly off-grid initial direction).

The GetAngularVelocity method is provided these two orientations, offset by around pi radians, and given a time of 1 unit to get there. How many radians/time unit must it rotate? Well, about pi radians/time unit. If you look at the length of the result of the GetAngularVelocity function, you get the speed- which is close to pi. If you look at the components of the result, the Y component is most of that result. That means it rotates about pi radians per time unit around the Y axis, as expected.

Near 180 degrees, the shortest angular velocity between two orientations can flip around. Think about a circle- if you are on a point on the circle and want to get to the furthest opposite point, you could go either direction and get there in the same amount of time.

Re: Toolbox GetAxisAngleFromQuaternion

Posted: Fri Jun 17, 2011 10:27 pm
by JanWH
I knew that i get 2 results on the opposite side, but i thought i was in a reasonable distance to that point.
I see difference at angles > Pi/2 they are small but noticable, could be something else.
The point i used in my example will not flip 180 but the Z axis rotation will alternate between 0 and 5 degrees.

Anyway thx for the fast answer, i havent figured it out but i see some ways around it (at least i hope so ).

Re: Toolbox GetAxisAngleFromQuaternion

Posted: Fri Jun 17, 2011 10:31 pm
by Norbo
If you're looking for a quaternion which acts as a rotation from one orientation to another, it's much simpler and direct to do the first part of the GetAngularVelocity method:
//Compute the relative orientation R' between R and the target relative orientation.
Quaternion errorOrientation;
Quaternion.Conjugate(ref start, out errorOrientation);
Quaternion.Multiply(ref end, ref errorOrientation, out errorOrientation);
If you start with matrices, a similar operation can still be performed without converting to quaternions.

The rest of the GetAngularVelocity method is spent converting that to an angular velocity that could be assigned to an Entity's AngularVelocity field to reach goal states.

Re: Toolbox GetAxisAngleFromQuaternion

Posted: Fri Jun 17, 2011 10:47 pm
by JanWH
Jep i copied that already ;)

What i try to make is a less "bouncie" rotator.
I have a ship i want to turn and it needs to stop at a given position.
But it can only accelerate or decelerate its angular velocity to achieve that,
so it needs to "break" befor it hits the target direction.
In order to find the deacceleration point i need to know the distance left to rotate and my speed.

Code: Select all

distanceLeft = GetAngularVelocity( currentFacing , targetFacing).Length()
speed = AngularVelocity.Length()
if( speed > distanceLeft ){
accelerate in opposit direction of angular velocity
} else { 
accelerate in target direction
}
thats the idea but i cant get it to work.

Re: Toolbox GetAxisAngleFromQuaternion

Posted: Fri Jun 17, 2011 11:27 pm
by Norbo
It sounds like you want a critically damped or over damped (http://en.wikipedia.org/wiki/Damping_ratio) angular spring. The SingleEntityAngularMotor is an easy way to accomplish this if you have a physical entity being moved. When in servo mode, it targets a specific orientation and has a spring constant and damping constant. A high relative damping constant will result in an over damped behavior, so it converges slowly to the goal and doesn't oscillate around it. Tuning those constants can it get closer to critical damping so it converges faster but still without oscillating.

The same thing can be done easily externally by using the spring-damper concept, although you'd have to do the math manually :) An external solution that isn't an iteratively solved constraint also technically won't be as stable as the SingleEntityAngularMotor option, but the difference should be unnoticeable in most situations.

Re: Toolbox GetAxisAngleFromQuaternion

Posted: Fri Jun 17, 2011 11:41 pm
by JanWH
Yes youre right and i had some fun with the Servo/Spring constants but it didnt work the way i wanted, i need
the user to tune those values and i dont think they can figure that out.

Just one more Quesition, i just copied youre Rotator code and it didnt work outside of
void IDuringForcesUpdateable.Update(float dt);
I set my ship to kinematic and did this:

Code: Select all

Entity.AngularVelocity = BEPUphysics.Paths.PathFollowing.EntityRotator.GetAngularVelocity( Entity.Orientation, direction , 1 );
it only moves a little part of the rotation, am i totaly wrong with dt=1 or does it need to be in that interface methode to work?

Re: Toolbox GetAxisAngleFromQuaternion

Posted: Fri Jun 17, 2011 11:52 pm
by Norbo
'dt' needs to be the time in which the goal must be reached. In the EntityRotator, it's the Space.TimeStepSettings.TimeStepDuration (defaults to 1/60f). If you're calling it external to space updates, then you should use the time between frames or whatever is appropriate.

Passing in 1 is telling it that it needs to get to the goal in 1 time unit, so it lollygags.

Re: Toolbox GetAxisAngleFromQuaternion

Posted: Sat Jun 18, 2011 12:37 am
by JanWH
*googles:lollygags* *wonders*

Ah interesting, now i know whats going wrong, my distance was just 1/60 of the actual distance.
I thought AngularVelocity.x = PI should be a 180 in 1 tick but 1 tick = 1/60 .... could have guesd it ;)
thx