I've been trying to get a working arcball system. I've looked at several of the tutorials scattered across the web and compared thousands of lines of source code to my own. I don't know if anyone's familiar with this but if you are any help would be appreciated.

On the mousebuttondown event, Click is called, passing the class's start vector in the second parameter, drag is called on mousemovepassing the class's end vector in the second parameter, and end is called on mousebuttonup.

I believe my problem is within the MapToSphere function. The data that the function is generating to both the start and end points are (cos(45), cos(45), 0) irregardless of where i drag the mouse. Thus, no rotation occurs since there is no difference between the points. I must be missing something because I can't seem to see how this would happen.

All my matrix, quaternion, and vector math is solid so I don't think that's the problem.

Sorry if this is too confusing, but I'll clarify if I can if ther's any confusion. Thanks in advance.

Code:void MArcBall::End(void) { this->m_LastRotMatrix = this->m_CurrentRotMatrix; } void MArcBall::SetBounds(int NewWidth, int NewHeight) { if((NewWidth > 1) && (NewHeight > 1)) { this->AdjustWidth = 1 / (NewWidth / 2); this->AdjustHeight = 1 / (NewHeight / 2); } } void MArcBall::Click(int x, int y) { this->m_RotationAxis.SetIdentity(); this->m_CurrentRotMatrix.SetIdentity(); this->MapToSphere(x, y, &this->m_Start); } void MArcBall::MapToSphere(int mx, int my, MVector* NewVec) { double lengthsquared, x, y; //Adjust point coords and scale down to range of [-1 ... 1] NewVec->SetX((mx * this->AdjustWidth) - 1); NewVec->SetY(1 - (my * this->AdjustHeight)); x = NewVec->GetX(); y = NewVec->GetY(); //Compute the square of the length of the vector to the point from the center lengthsquared = (x * x) + (y * y); //If the point is mapped outside of the sphere... (length > radius squared) if (lengthsquared > 1.0f) { double norm = 1.0f / sqrt(lengthsquared); //Return the "normalized" vector, a point on the sphere //yes, i know, bad coding practice here, but i've been too lazy to write a function for this NewVec->m_matrix.m_quat.m_matrix[0][0] *= norm; NewVec->m_matrix.m_quat.m_matrix[1][0] *= norm; NewVec->m_matrix.m_quat.m_matrix[2][0] = 0.0f; } else //Else it's on the inside { //Return a vector to a point mapped inside the sphere sqrt(radius squared - length) NewVec->m_matrix.m_quat.m_matrix[2][0] = sqrt(1 - lengthsquared); } } void MArcBall::Drag(int mx, int my) { //Map the point to the sphere this->MapToSphere(mx, my, &this->m_End); MVector Axis = this->m_Start.Cross(this->m_End); //Compute the length of the perpendicular vector if (Axis.Length() > 0) //if its non-zero { //We're ok, so return the perpendicular vector as the transform after all this->m_RotationAxis.Set( Axis.GetX(), Axis.GetY(), Axis.GetZ(), this->m_Start.Dot(this->m_End) ); } else //if its zero { //The begin and end vectors coincide, so return an identity transform this->m_RotationAxis.SetIdentity(); } this->MQuatToMMatrix(); this->m_CurrentRotMatrix *= this->m_LastRotMatrix; this->MakeTransformMatrix(); PrintData(); } void MArcBall::MQuatToMMatrix(void) { double w = m_RotationAxis.GetW(); double x = m_RotationAxis.GetX(); double y = m_RotationAxis.GetY(); double z = m_RotationAxis.GetZ(); double Nq = x*x + y*y + z*z + w*w; double s = (Nq > 0.0f) ? (2.0f / Nq) : 0.0f; double xs = x*s, ys = y*s, zs = z*s; double wx = w*xs, wy = w*ys, wz = w*zs; double xx = x*xs, xy = x*ys, xz = x*zs; double yy = y*ys, yz = y*zs, zz = z*zs; m_CurrentRotMatrix.Set(0,0,1.0f - (yy + zz)); m_CurrentRotMatrix.Set(1,0,(xy - wz)); m_CurrentRotMatrix.Set(2,0,(xz + wy)); m_CurrentRotMatrix.Set(0,1,(xy + wz)); m_CurrentRotMatrix.Set(1,1,1.0f - (xx + zz)); m_CurrentRotMatrix.Set(2,1,(yz - wx)); m_CurrentRotMatrix.Set(0,2,(xz - wy)); m_CurrentRotMatrix.Set(1,2,(yz + wx)); m_CurrentRotMatrix.Set(2,2,1.0f - (xx + yy)); } //not this void MArcBall::MakeTransformMatrix(void) { this->m_Rotate[0] = this->m_CurrentRotMatrix.Get(0,0); this->m_Rotate[4] = this->m_CurrentRotMatrix.Get(0,1); this->m_Rotate[8] = this->m_CurrentRotMatrix.Get(0,2); this->m_Rotate[1] = this->m_CurrentRotMatrix.Get(1,0); this->m_Rotate[5] = this->m_CurrentRotMatrix.Get(1,1); this->m_Rotate[9] = this->m_CurrentRotMatrix.Get(1,2); this->m_Rotate[2] = this->m_CurrentRotMatrix.Get(2,0); this->m_Rotate[6] = this->m_CurrentRotMatrix.Get(2,1); this->m_Rotate[10] = this->m_CurrentRotMatrix.Get(2,2); this->m_Rotate[3] = this->m_Rotate[7] = this->m_Rotate[11] = this->m_Rotate[12] = this->m_Rotate[13] = this->m_Rotate[14] = 0; this->m_Rotate[15] = 1; } }