Sign in to follow this  
G-Man9566

Rotating Camera around a fixed point (arc rotate - like 3dsMax)

Recommended Posts

Could anyone give me some pointers, or point me to an article or tutorial, to rotate a camera around a fixed point as is done in 3dsMax with the arc rotate and specifically using Quarternions. I know the basics of Quarternions and the math behind them, but want to know how to implement it. I assume you will rotate the Position of your camera and keep your View fixed.

Share this post


Link to post
Share on other sites
What I can say is that you are basically correct. I'm doing it with euler rather than quaternions, but basically I have a normalised direction vector which I multiply by the 3d euler matrix to rotate the camera. I then use gluLookAt (opengl function) to make the scene sit on the camera's position vector and face towards the look vector.

To move the camera, I take a vector representing the motion in local coordinates, then multiply it by the view matrix of the camera. I then add the result to the position of the camera.

Share this post


Link to post
Share on other sites
Here, have some source code. It's a bit old (doesn't use fancy overloaded operator and such), but it should do the job or give you an idea of how to do it. Note how it takes the old position and direction to allow continuation where it could otherwise be ambiguous (causing camera to flip upside down).
I've included some dependant support functions whos implementation may not be obvious.

/// Calculate orbit style camera values
/// \param a_worldUp World up direction to align to
/// \param a_worldForward World forward direction to align to
/// \param a_focusPosition Target position to aim at
/// \param a_focusDistance Distance back from target
/// \param a_horizAngleRad Horizontal angle in radians, relative to the world forward direction
/// \param a_vertAngleRad Vertical angle in radians, relative to the forward direction as ground plane
/// \param a_lastUp Last up direction, to resolve ambiguity when camera is parallel with world up
/// \param a_camPos Output camera position
/// \param a_camDir Output camera forward direction
/// \param a_camUp Output camera up direction
void Geom::CalcOrbitCam(const Vector3& a_worldUp, const Vector3& a_worldForward,
const Vector3& a_focusPosition, const Float32 a_focusDistance,
const Float32 a_horizAngleRad, const Float32 a_vertAngleRad,
const Vector3& a_lastUp,
Vector3& a_camPos, Vector3& a_camDir, Vector3& a_camUp)
{
// These are constant vecs describing logical world space
const Vector3& upAxis = a_worldUp;
const Vector3& fixedForwardAxis = a_worldForward;

Vector3 right;
Vector3 camDir;
Vector3 camPos;
Vector3 camUp;

// Calc direction based on two rotations
right.SetCross(upAxis, fixedForwardAxis);
camDir = fixedForwardAxis;
camDir.RotateAxisAngle(right, a_vertAngleRad);
camDir.RotateAxisAngle(upAxis, a_horizAngleRad);
camDir.Normalize();

// Draw camera back from focus to calc position
camPos = a_focusPosition - (camDir * a_focusDistance);

// Calc restriction plane (perpendicular axis)
Vector3 restrictVec;
Vector3 tempDir = fixedForwardAxis;
tempDir.RotateAxisAngle(upAxis, a_horizAngleRad);
restrictVec.SetCross(upAxis, tempDir);

// Use last up as world up is not preserved in this case
camUp.SetRestrictPerpendicular(a_lastUp, restrictVec);

// Tests for degenerate view vecs
Vector3 testRight;
testRight.SetCross(camUp, camDir);
if( testRight.LengthSquared() <= 0.0f )
{
camDir = fixedForwardAxis;
camUp = upAxis;
}

// Use to calc camera matrix
a_camPos = camPos;
a_camDir = camDir;
a_camUp = camUp;
}


// Set this to Parallel component of vector with axis
// Does not normalize
void Vector3::SetRestrictParallel(const Vector3& a_vec, const Vector3& a_axis)
{
// axis * (axis . vec)
SetScale(a_axis, a_axis.Dot(a_vec));
}


// Set this to Perpendicular component of vector with axis
// Does not normalize
void Vector3::SetRestrictPerpendicular(const Vector3& a_vec, const Vector3& a_axis)
{
Vector3 parallelVec;

// vec - (axis * (axis . vec))
parallelVec.SetRestrictParallel(a_vec, a_axis);
SetSub(a_vec, parallelVec);
}


// Set to Vector rotated by AxisAngle rotation
//
// Rotate a vector by a axis (unit vector) and angle (radians)
// Only useful if you want to do this once off, otherwise, create a matrix and rotate multiple vectors more efficiently
void Vector3::SetRotateAxisAngle(const Vector3& a_point, const Vector3& a_axis, Float32 a_angle)
{
//cos(t) V + (1 - cos(t)) (A dot V) A + sin(t) (A cross V).

Float32 sinAng, cosAng;
Vector3 temp1, temp2;

Math::SinCos(a_angle, sinAng, cosAng);

temp1.SetScale(a_point, cosAng);
temp2.SetScale(a_axis, (1 - cosAng) * a_axis.Dot(a_point));
SetCross(a_axis, a_point);
Scale(sinAng);
Add(temp1);
Add(temp2);
}


// Rotate vector by axis angle
void Vector3::RotateAxisAngle(const Vector3& a_axis, Float32 a_angle)
{
Vector3 temp;

temp.SetRotateAxisAngle(*this, a_axis, a_angle);
*this = temp;
}

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