Sign in to follow this  
EarthBanana

Quaternion with Camera

Recommended Posts

EarthBanana    1794

I have switched everything over to using quaternions.. The only problem I'm having now is with the camera - if you just rotate a quaternion about the x axis so that you are pointed towards the sky, and then about y axis (assuming z is in to the screen) to look to the right (and using delta mouse pos to determine rotation amount) you end up with a rolled camera. I get why and I understand that is how the math works (I programmed the math after all) - the quaternion, after the first rotation about the x axis, has a new local y axis that is different than the world's y axis

 

My question is this.. Is there any way to rotate the camera about the world's y axis and not it's local y axis while using only one quaternion to store rotation information within the camera?

Share this post


Link to post
Share on other sites
EarthBanana    1794

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;
}
Edited by EarthBanana

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this