Quaternion math is not the easiest thing. You shouldn't think of them as a fancy vector as quaternions "kinda" have 4 dimensions (direction and a rotation in that direction). They're a transformation so the up vector is defined by something like "Quat.mul(0,0,1)".

Well, just let me share the code I used when I was playing with the "mOrient-resource". Feel free to ask anything if the comments are not enough.

In the .h file inside the class (I used it in "public:") add:

Code: Select all

```
void doLocalRotateX(const F32& rotX , QuatF* qchanged );
void doLocalRotateZ(const F32& rotZ , QuatF* qchanged );
void doQuatOrientation( const Point3F &neworient );
```

In the .cpp file add at the end (for example):

Code: Select all

```
void Player::doLocalRotateX(const F32& rotX, QuatF* qchanged )
{
QuatF tempq(qchanged->x,qchanged->y,qchanged->z,qchanged->w);
if(!mIsZero(rotX))
{
Point3F localX;
tempq.mulP(Point3F(1.0,0.0,0.0),&localX);
QuatF qx(localX,rotX);
tempq *= qx;
}
tempq.normalize();
qchanged->set(tempq.x,tempq.y,tempq.z,tempq.w);
}
void Player::doLocalRotateZ(const F32& rotZ, QuatF* qchanged )
{
QuatF tempq(qchanged->x,qchanged->y,qchanged->z,qchanged->w);
if(!mIsZero(rotZ))
{
Point3F localZ;
tempq.mulP(Point3F(0.0,0.0,1.0),&localZ);
QuatF qz(localZ,rotZ);
tempq *= qz;
}
tempq.normalize();
qchanged->set(tempq.x,tempq.y,tempq.z,tempq.w);
}
void Player::doQuatOrientation( const Point3F &neworient )
{
//we will not modify mOrient untill the end
QuatF tempmOrient = mOrient;
tempmOrient.normalize();
tempmOrient.inverse(); //we're going global->local so we need the inverse of mOrient
Point3F vect=neworient; //we need to normalize neworient
vect.normalize();
Point3F localvect;
tempmOrient.mulP(vect,&localvect);
localvect.normalize(); //this normalize may not be needed... but just in case
tempmOrient = mOrient; //we need back normalized mOrient to do the transformations
tempmOrient.normalize();
//localvect is our wanted neworient in local coordinates
//x and y values are the projections of localvect in the z=0 plane
//to know that angle (that is the rotation on the z axis) we can use then the arctangent
F32 rotZ = mAtan2(localvect.x,localvect.y);
doLocalRotateZ(rotZ,&tempmOrient);
//we rotate around our local z axis so we face our destination (y axis aligned)
//so we only need a final rotation with our local x axis
//rotation on x axis is similar to z but the plane is x=0
F32 rotX = mAtan2(mSqrt(localvect.x*localvect.x + localvect.y*localvect.y),localvect.z);
doLocalRotateX(rotX,&tempmOrient);
//now we undo the initial rotZ
//This way the initial local-z rotation is similar... I think
doLocalRotateZ((-1)*rotZ,&tempmOrient);
//finally we transform mOrient
mOrient.set(tempmOrient.x,tempmOrient.y,tempmOrient.z,tempmOrient.w);
}
```

(Change "Player::" with the name of your particular class, of course.)

Then in order to align the mOrient to a "vectorUp" you just do in the c++ code:

where vectorUp is the new orientation.

You can see I normalize() a lot... maybe too much. Feel free to remove all of the normalize() you think are not needed.

Note I use up as vector. If you're using gravity(going down) then remember to use gravity.neg() or you'll "walk" on your head.

As final note let me share that using the normal as up vector is not a very good idea if you use the default camera of player. Well, it's all right if the terrain is a plane but if it's kind of bumpy like the terrain of the full template then the camera movements are unpleasant when you run.