Sign in to follow this  

Arcball problem

Recommended Posts


I'm trying to add an "arc ball" but I have a strange behaviour.
I surely do something wrong, but what :-P So, if someone has an idea of the problem ?

How to reproduce it :
1 - With my arcball, I do an horizontal rotation of 180 degree (all is fine)
2 - I try to do a vertical rotation and the scene rotate in the INVERSE direction

Here is what I do :

void TrackballOperator::OnMouseMove(MouseEventArgs* e)
if (e->LeftButtonStatus == Down)
Drag(e->x, e->y);

// Update the camera
VNCamera* camera = _surface->GetScene()->GetActiveCamera();
Vector3 at = camera->GetEyeAt();

// eye
Vector3 eye = _startVector - at;
camera->SetEye(eye + at);

// eye up
Vector3 eyeUp = _startVectorUp;

void TrackballOperator::OnMouseButtonDown(MouseButtonEventArgs* e)
if (e->Button == Left)
SetBounds(_surface->GetWidth(), _surface->GetHeight());

//---- Reset some datas...
VNCamera* camera = _surface->GetScene()->GetActiveCamera();
_startVector = camera->GetEye();
_startVectorUp = camera->GetEyeUp();

startMouse.x = e->x;
startMouse.y = e->y;

void TrackballOperator::MapToSphere(const Vector2* NewPt, Vector3* NewVec) const
Vector2 TempPt;
float length;

// Copy paramter into temp point
TempPt = *NewPt;

// Adjust point coords and scale down to range of [-1 ... 1]
TempPt.x = (TempPt.x * this->AdjustWidth) - 1.0f;
TempPt.y = 1.0f - (TempPt.y * this->AdjustHeight);

// Compute the square of the length of the vector to the point from the center
length = (TempPt.x * TempPt.x) + (TempPt.y * TempPt.y);

// If the point is mapped outside of the sphere... (length > radius squared)
if (length > 1.0f)
float norm;

// Compute a normalizing factor (radius / sqrt(length))
norm = 1.0f / sqrtf(length);

// Return the "normalized" vector, a point on the sphere
NewVec->x = TempPt.x * norm;
NewVec->y = TempPt.y * norm;
NewVec->z = 0.0f;
else //Else it's on the inside
//Return a vector to a point mapped inside the sphere sqrt(radius squared - length)
NewVec->x = TempPt.x;
NewVec->y = TempPt.y;
NewVec->z = sqrtf(1.0f - length);

void TrackballOperator::Drag(float newX, float newY)
endMouse.x = newX;
endMouse.y = newY;

// Map the point to the sphere
Vector3 startPoint;
Vector3 endPoint;
MapToSphere(&startMouse, &startPoint);
MapToSphere(&endMouse, &endPoint);

// Return the quaternion equivalent to the rotation
// Compute the vector perpendicular to the begin and end vectors
Vector3 Perp = Cross(endPoint, startPoint);

startMouse = endMouse;

// Compute the length of the perpendicular vector
Quaternion NewRot;
if (Perp.Length() < EPSILON)

// We're ok, so return the perpendicular vector as the transform after all
NewRot.x = Perp.x;
NewRot.y = Perp.y;
NewRot.z = Perp.z;

// In the quaternion values, w is cosine (theta / 2), where theta is rotation angle
NewRot.w = Dot(startPoint, endPoint);

GlobalRotation = GlobalRotation * NewRot;

About the quaternion class :

// Conjugate it
void Conjugate()
x = -x;
y = -y;
z = -z;

// Calculates the effect of this rotation on a point
// the new point is given by = q * P1 * q'
void Rotate(Vector3* point)
//---- Compute the conjugate
Quaternion conj = *this;

//---- q * P * q'
Quaternion qNode(point->x, point->y, point->z, 0.f);
qNode = *this * qNode * conj;

//---- Set the result
point->x = qNode.x;
point->y = qNode.y;
point->z = qNode.z;

Share this post

Link to post
Share on other sites
I think I have found the problem.

I need to set-up my initial quaternion with the camera axis.

So, do you know how to convert 3 Axis (AxisX, AxisY, AxisZ) into a quaternion ?

Thanks for your help

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