I've run into a perplexing problem with some quaternion math that I'm trying to perform, as I've never quite understood what certain operations between quaternions return ( quat1.inverse() * quat2 = quatDiff ?!).
I have this code:
Code: Select all
#define CHARACTER_SCALE_FACTOR .0275f
/* ...snip... */
void NPCCharacter::_actionLook(const Ogre::Vector3& target)
{
Ogre::Bone* headBone;
std::string n = _node->getName();
Ogre::Skeleton* skel = static_cast<Ogre::Entity*>(_movableObject)->getSkeleton();
headBone = skel->getBone("Bip01_Head");
headBone->setManuallyControlled(true);
headBone->setInheritOrientation(true);
int nAnim = skel->getNumAnimations();
//have to do this to allow the head to turn properly.
for(int i = 0; i < nAnim; ++i)
{
skel->getAnimation(i)->destroyNodeTrack(headBone->getHandle());
}
Ogre::Vector3 test = headBone->_getDerivedPosition() * CHARACTER_SCALE_FACTOR + _node->getPosition();
Ogre::Vector3 dir = target - test;
Ogre::Quaternion nodeRot,boneRot;
boneRot = _node->convertLocalToWorldOrientation(_node->getOrientation()) * headBone->_getDerivedOrientation();
Ogre::Vector3 boneTest = boneRot * Ogre::Vector3::UNIT_Z;
//turns the direction vector into a 2D normalized vector on the X/Z axis.
dir.y = 0;
dir.normalise();
//All of this ray query stuff is to make sure that the AI can "see" the target before attempting to look at it.
Ogre::SceneManager* scene = _node->getCreator();
Ogre::Ray ray(headBone->_getDerivedPosition() * CHARACTER_SCALE_FACTOR + _node->getPosition(),dir);
Ogre::RaySceneQuery* query = scene->createRayQuery(ray);
query->setSortByDistance(true);
query->setQueryMask(CHARACTER_MASK | SCENERY_MASK);
Ogre::RaySceneQueryResult results = query->execute();
bool withinView = false;
if(results.size() == 0)
{
withinView = true;
}
else
{
if(results.begin()->movable->getParentNode()->getName() == getName())
{
if(results.size() == 1)
{
withinView = true;
}
}
if(!withinView && results.size() > 1 && std::next(results.begin())->distance > test.distance(target))
{
withinView = true;
}
}
scene->destroyQuery(query);
if(withinView)
{
//need to restrict this rotation, so I don't get an exorcist-type head look.
headBone->rotate(boneTest.getRotationTo(dir),Ogre::Node::TS_WORLD);
Ogre::Quaternion boneRotation = _node->convertLocalToWorldOrientation(_node->getOrientation()) * headBone->_getDerivedOrientation() * (Ogre::Quaternion(Ogre::Degree(180),Ogre::Vector3::UNIT_Y));
Ogre::Quaternion nodeRotation = _node->_getDerivedOrientation();
Ogre::Quaternion diff = nodeRotation.Inverse() * boneRotation;
if(abs(diff.getYaw().valueDegrees()) > 90.0f)
{
std::cout << boneRotation.getYaw().valueDegrees() << std::endl;
}
//now to figure out how to restrict this orientation(shouldn't be too hard now).
//famous last words lol.
if(abs(diff.getYaw().valueDegrees()) > 180.0f)
{
//headBone->_setDerivedOrientation(
}
}
_isActFinished = true;
}
My problem is trying to rotate this headbone properly (always faces the player regardless of how the node is facing), and then restricting that rotation (so that it's a human head rather than a horror movie freak show. For some reason, whenever the node is facing on the negative Z-axis the head is always 180 degrees rotated on the Y-axis away from the player. But when the node is facing the positive Z-axis, it faces the player just fine.
I'm totally stumped, and desperately need some help.
Thank you in advance!