[SOLVED] Solving for rotation difference with quaternions

Problems building or running the engine, queries about how to use features etc.
Post Reply
Van
Hobgoblin
Posts: 512
Joined: Fri Nov 19, 2004 3:56 am
Contact:

[SOLVED] Solving for rotation difference with quaternions

Post by Van »

I'm trying to match an agents orientation to the targets orientation but I seem to missing something. As the agent turns (vectors/seeks towards the target) the orientation doesn't match. The agent is doing something but not what I want. It's as if I need to include the current vector of the agent in the equation but I'm not sure how I would do that in this case.

Code: Select all


Ogre::Quaternion mAgentOrientation, mTargetOrientation;

...

// Find rotation difference between agent and target.
mAgentOrientation.normalize();
mTargetOrientation.normalize();
Ogre::Radian mRotationScalar = ( mAgentOrientation - mTargetOrientation ).getRoll(); // A-B = B->A

...

// set roll force to physics engine
setRoll( mRotationScalar );

I thought that mRotationScalar would represent the difference in roll required to obtain an orientation match.

What am I missing here?
Last edited by Van on Sun May 24, 2009 1:36 am, edited 1 time in total.
Stop Global Whining.
User avatar
fassihi
Goblin
Posts: 215
Joined: Sat Sep 16, 2006 6:51 am
x 8
Contact:

Re: Solving for rotation difference with quaternions

Post by fassihi »

I don't think subtracting quaternions has the meaning you are looking for.
If you have the target orientation, can't you set that directly on the agent? Make the agent have the same orientation as the target. If the target has some orientation offset initially, you can account for that too.
Van
Hobgoblin
Posts: 512
Joined: Fri Nov 19, 2004 3:56 am
Contact:

Re: Solving for rotation difference with quaternions

Post by Van »

fassihi wrote:I don't think subtracting quaternions has the meaning you are looking for.
If you have the target orientation, can't you set that directly on the agent? Make the agent have the same orientation as the target. If the target has some orientation offset initially, you can account for that too.
According to the Ogre Wiki Quaternion and Rotation Primer adding and subtracting quaternions is exactly like adding and subtracting vectors. Now, the primer could be wrong - I'm not an expert in 3D math.
Quaternion and Rotation Primer wrote: Vector3::getRotationTo(Vector3) returns a quaternion describing a relative rotation from one vector to the next. Remember that quaternions can be thought of as vectors with an angle attached? Remember that Vector A minus Vector B gives Vector C, a relative vector from B to A? Same thing with quaternions. Think of orientations as absolute, relative to the identity. Think of rotations as relative, usually relative to the current orientation.
Just setting the orientation is no good. We are using a physics engine. Just setting the orientation will cause the agent to "snap" to the orientation and by pass the physics engine.
Stop Global Whining.
User avatar
fassihi
Goblin
Posts: 215
Joined: Sat Sep 16, 2006 6:51 am
x 8
Contact:

Re: Solving for rotation difference with quaternions

Post by fassihi »

Van,

If you check the same page on OGRE wiki about Quaternions, there is a table which shows the equivalent quaternions for different rotations. From the table you can see very well that adding quaternion values or subtracting the values does not work. The quaternions work with Cosine values and can not be numerically added if we are looking for concatenating rotations.

If you want to add two rotations using quaternions, you would need to multiply them together.

In your case, one thing you can do is have the front vector of the two objects and then call : Quaternion orientation_difference = VecA.getRotationTo(VecB);
This would give you the orientation which would rotate VecA towards VecB.

The Slerp function of quaternions can be used too, that would give you a part of the difference in their orientations, could be used if you are looking for a smooth turn.
Lax
Hobgoblin
Posts: 583
Joined: Mon Aug 06, 2007 12:53 pm
Location: Saarland, Germany
x 50

Re: Solving for rotation difference with quaternions

Post by Lax »

Your agent and targets have an origin direction. Maybe this code may help you:

Code: Select all

//agent.x --> x position of the agent...
Ogre::Vector3 directionXY = Ogre::Vector3(agent.x - target.x, agent.y - target.y, 0.0);

directionXY.normalise();

//origin direction
Ogre::Vector3 vec = Ogre::Vector3::UNIT_Y;
//rotate from the origin direction to the target
Ogre::Quaternion quat = vec.getRotationTo(directionXY);
Ogre::Radian mRotationScalar = quat.getRoll();

http://www.lukas-kalinowski.com/Homepage/?page_id=1631
Please support Second Earth Technic Base built of Lego bricks for Lego ideas: https://ideas.lego.com/projects/81b9bd1 ... b97b79be62

Van
Hobgoblin
Posts: 512
Joined: Fri Nov 19, 2004 3:56 am
Contact:

Re: Solving for rotation difference with quaternions

Post by Van »

Also see: Wiki AI Agent Control

Thank you all for your assistance. I finally got it to work. Here is the code for those who visit this thread later.
Realize that we are using a physics engine (newton) and are trying to utilize the same input controls that humans use. We use a scalar, -1.0 to +1.0 for torque and 0.0 to +1.0 for thrust, to determine how much of the "engine controls" to apply. Therefore it doesn't matter if the the input is keyboard, mouse, joystick or computed (i.e. AI) the input to our physics system is always a scalar that represents the amount power/torque to apply. For example:

Code: Select all

void SetThrust(float Scalar)
{
  float mMaxEngineThrust = 400.00; 
  float mThrustToUse = mScalar * mMaxEngineThrust;
  ..// make call to physics engine
} // SetThrust
Here is the agent Seek() and Flee() functions that we use.

Code: Select all


//------------------------------- Seek -----------------------------------
//
//  Given a target, this behavior returns a steering force which will
//  direct the agent towards the target
//------------------------------------------------------------------------
void clsScripting::Seek(Ogre::Vector3 TargetPosition, Ogre::Quaternion TargetOrientation)
{
	Ogre::Vector3 mAgentPosition		= mGlobalResource->LocalPlayerObjectScene->getInventoryPosition();
	Ogre::Quaternion mAgentOrientation	= mGlobalResource->LocalPlayerObjectScene->getInventoryOrientation();
	Ogre::Vector3 mVectorToTarget		= TargetPosition - mAgentPosition; // A-B = B->A
	mAgentPosition.normalise();
	mAgentOrientation.normalise();

	Ogre::Vector3 mAgentHeading		= mAgentOrientation * mAgentPosition;
	Ogre::Vector3 mTargetHeading		= TargetOrientation * TargetPosition;
	mAgentHeading.normalise();
	mTargetHeading.normalise();

	// Orientation control - Ogre::Vector3::UNIT_Y is common up vector.
	Ogre::Vector3 mAgentVO		= mAgentOrientation.Inverse() * Ogre::Vector3::UNIT_Y;
	Ogre::Vector3 mTargetVO		= TargetOrientation * Ogre::Vector3::UNIT_Y;

	// Compute new torque scalar (-1.0 to 1.0) based on heading vector to target.
	Ogre::Vector3 mSteeringForce = mAgentOrientation.Inverse() * mVectorToTarget;
	mSteeringForce.normalise();

	float mYaw		= mSteeringForce.x;
	float mPitch	= mSteeringForce.y;
	float mRoll		= mTargetVO.getRotationTo( mAgentVO ).getRoll().valueRadians();

	clsSystemControls::getSingleton().setPitchControl( mPitch );
	clsSystemControls::getSingleton().setYawControl( mYaw );
	clsSystemControls::getSingleton().setRollControl( mRoll );

} // Seek


//----------------------------- Flee -------------------------------------
//
//  Does the opposite of Seek
//------------------------------------------------------------------------
void clsScripting::Flee(Ogre::Vector3 TargetPosition, Ogre::Quaternion TargetOrientation)
{
	Ogre::Vector3 mAgentPosition		= mGlobalResource->LocalPlayerObjectScene->getInventoryPosition();
	Ogre::Quaternion mAgentOrientation	= mGlobalResource->LocalPlayerObjectScene->getInventoryOrientation();
	Ogre::Vector3 mVectorToTarget		= TargetPosition - mAgentPosition; // A-B = B->A
	mAgentPosition.normalise();
	mAgentOrientation.normalise();

	Ogre::Vector3 mAgentHeading		= mAgentOrientation * mAgentPosition;
	Ogre::Vector3 mTargetHeading		= TargetOrientation * TargetPosition;
	mAgentHeading.normalise();
	mTargetHeading.normalise();

	// Orientation control - Ogre::Vector3::UNIT_Y is common up vector.
	Ogre::Vector3 mAgentVO		= mAgentOrientation.Inverse() * Ogre::Vector3::UNIT_Y;
	Ogre::Vector3 mTargetVO		= TargetOrientation * Ogre::Vector3::UNIT_Y;

	// Compute new torque scalar (-1.0 to 1.0) based on heading vector to target.
	Ogre::Vector3 mSteeringForce = mAgentOrientation * mVectorToTarget;
	mSteeringForce.normalise();

	float mYaw		= mSteeringForce.x;
	float mPitch	= mSteeringForce.y;
	float mRoll		= mTargetVO.getRotationTo( mAgentVO ).getRoll().valueRadians();

	clsSystemControls::getSingleton().setPitchControl( mPitch );
	clsSystemControls::getSingleton().setYawControl( mYaw );
	clsSystemControls::getSingleton().setRollControl( mRoll );

} // Flee

Stop Global Whining.
User avatar
jacmoe
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 20570
Joined: Thu Jan 22, 2004 10:13 am
Location: Denmark
x 179
Contact:

Re: [SOLVED] Solving for rotation difference with quaternions

Post by jacmoe »

Thanks a lot Van! for wikiing it. :)
/* Less noise. More signal. */
Ogitor Scenebuilder - powered by Ogre, presented by Qt, fueled by Passion.
OgreAddons - the Ogre code suppository.
Post Reply