Arcball system

This is a discussion on Arcball system within the Game Programming forums, part of the General Programming Boards category; I've been trying to get a working arcball system. I've looked at several of the tutorials scattered across the web ...

  1. #1
    Registered User
    Join Date
    Oct 2005
    Posts
    2

    Arcball system

    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;
    }
    }

  2. #2
    Registered User
    Join Date
    Oct 2005
    Posts
    2
    I found the problem. It was a rounding error with my SetBounds function. It kept rounding the value down to zero, so i got rid of "1 / " and in my maptosphere function replaced

    NewVec->SetX((mx / this->AdjustWidth) - 1);
    NewVec->SetY(1 - (my / this->AdjustHeight));

    with

    NewVec->SetX((mx * this->AdjustWidth) - 1);
    NewVec->SetY(1 - (my * this->AdjustHeight));

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. File System Implementation
    By dodgeviper in forum C Programming
    Replies: 9
    Last Post: 11-16-2007, 12:04 PM
  2. Using system icons
    By @nthony in forum Windows Programming
    Replies: 1
    Last Post: 01-13-2007, 06:56 PM
  3. Linux database system needed
    By BobS0327 in forum Tech Board
    Replies: 7
    Last Post: 06-11-2006, 03:56 PM
  4. measuring system resources used by a function
    By Aran in forum C Programming
    Replies: 1
    Last Post: 03-13-2006, 04:35 PM
  5. BIOS system and memory allocation problem
    By beely in forum Tech Board
    Replies: 9
    Last Post: 11-25-2003, 06:12 AM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21