Jump to content
  • Advertisement
Sign in to follow this  
EarthBanana

Quaternion with Camera

This topic is 2109 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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
Advertisement

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
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!