Nevermind - I have figured it out.. basically just remembering that order of multiplication makes a big difference
Rotation as I described before:
void NSQuaternion::rotate(const NSVec3Df & pAxis, float pAngle)
{
NSQuaternion localRotation;
float halfAngle = sinf(DegreesToRadians((pAngle/2.0f)));
localRotation.x = pAxis.x * halfAngle;
localRotation.y = pAxis.y * halfAngle;
localRotation.z = pAxis.z * halfAngle;
localRotation.w = cosf(DegreesToRadians(pAngle / 2.0f));
(*this) = localRotation * (*this);
normalize();
}
And with the camera working the way that I actually want it to..
void NSQuaternion::rotate(const NSVec3Df & pAxis, float pAngle)
{
NSQuaternion localRotation;
float halfAngle = sinf(DegreesToRadians((pAngle/2.0f)));
localRotation.x = pAxis.x * halfAngle;
localRotation.y = pAxis.y * halfAngle;
localRotation.z = pAxis.z * halfAngle;
localRotation.w = cosf(DegreesToRadians(pAngle / 2.0f));
(*this) = (*this) *localRotation;
normalize();
}
The operator* function for my Quaternion is the following
NSQuaternion NSQuaternion::operator*(const NSQuaternion & pRHSQuat) const
{
NSQuaternion ret;
ret.x = w*pRHSQuat.x + x*pRHSQuat.w + y*pRHSQuat.z - z*pRHSQuat.y;
ret.y = w*pRHSQuat.y - x*pRHSQuat.z + y*pRHSQuat.w + z*pRHSQuat.x;
ret.z = w*pRHSQuat.z + x*pRHSQuat.y - y*pRHSQuat.x + z*pRHSQuat.w;
ret.w = w*pRHSQuat.w - x*pRHSQuat.x - y*pRHSQuat.y - z*pRHSQuat.z;
return ret;
}
I will use the second version of the function as the final version because I can get the Up, Target, or Right vector any time with these:
NSVec3Df NSQuaternion::getTargetVec() const
{
return NSVec3Df(2.0f*x*z - 2.0f*w*y, 2.0f*y*z + 2.0f*w*x, 1.0f - 2.0f*x*x - 2.0f*y*y);
}
NSVec3Df NSQuaternion::getUpVec() const
{
return NSVec3Df(2.0f*x*y + 2.0f*w*z, 1.0f - 2.0f*x*x - 2.0f*z*z, 2.0f*y*z - 2.0f*w*x);
}
NSVec3Df NSQuaternion::getRightVec() const
{
return NSVec3Df(1.0f - 2.0f*y*y - 2.0f*z*z, 2.0f*x*y - 2.0f*w*z, 2.0f*x*z + 2.0f*w*y);
}
And finally.. to get the rotation transform for the quat
NSMatrix4Df NSQuaternion::getRotationMatrix() const
{
NSMatrix4Df retMat;
retMat.setRow(NSVec4Df(getRightVec(), 0.0f), 0);
retMat.setRow(NSVec4Df(getUpVec(), 0.0f), 1);
retMat.setRow(NSVec4Df(getTargetVec(), 0.0f), 2);
return retMat;
}
And just for anyone who cares.. a working interpolation function that I use for animation
NSQuaternion NSQuaternion::getInterpolatedQuaternion(const NSQuaternion & pFirst,
const NSQuaternion & pSecond,
float pScalingFator)
{
NSQuaternion ret;
NSQuaternion second = pSecond;
float cosHalfTheta = getCosHalfAngle(pFirst,pSecond);
if (cosHalfTheta < 0)
{
second = second * -1.0f;
cosHalfTheta = -cosHalfTheta;
}
// make sure we dont go out of acos domain
if ( abs(cosHalfTheta ) >= 1.0)
return pFirst;
// Calculate more expensive values.
float halfTheta = acos(cosHalfTheta);
float sinHalfTheta = sinf(halfTheta);
// if sin of theta = 0 (or something close) then just
// take point exactly between the two quats
if (fabs(sinHalfTheta) < 0.000001)
return pFirst*0.5f + second*0.5f;
float ratioA = sin((1 - pScalingFator) * halfTheta) / sinHalfTheta;
float ratioB = sin(pScalingFator * halfTheta) / sinHalfTheta;
ret = pFirst*ratioA + second*ratioB;
ret.normalize();
return ret;
}
float NSQuaternion::getCosHalfAngle(const NSQuaternion & pFirst, const NSQuaternion & pSecond)
{
return pFirst.x*pSecond.x + pFirst.y*pSecond.y + pFirst.z*pSecond.z + pFirst.w*pSecond.w;
}