Search code examples
3ddirectxquaternions

What's the geometry meaning of Quaternion multiplicatioin?


I am currently writing an Arcball(used in model view camera), I am looking into the MS DXUT codes, they have an Arcball implementation as below

#include "ArcBall.h"

ArcBall::ArcBall(void)
{
        Reset() ;
        m_vDownPt = D3DXVECTOR3( 0, 0, 0 ) ;
        m_vCurrentPt = D3DXVECTOR3( 0, 0, 0 ) ;
        m_Offset.x = 0 ;
        m_Offset.y = 0 ;
}

ArcBall::~ArcBall(void)
{
}

void ArcBall::Reset()
{
        D3DXQuaternionIdentity( &m_qDown );
        D3DXQuaternionIdentity( &m_qNow );
        D3DXMatrixIdentity( &m_mRotation );
        m_bDrag = FALSE;
        m_fRadius = 1.0f;

        RECT rc ;
        GetClientRect(GetForegroundWindow(), &rc) ;
        SetWindow(rc.right, rc.bottom) ;
}

void ArcBall::OnBegin(int nX, int nY)
{
        // enter drag state only if user click the window's client area
        if( nX >= m_Offset.x && 
                nX <= m_Offset.x + m_nWidth &&
                nY >= m_Offset.y &&
                nY < m_Offset.y + m_nHeight )
        {
                m_bDrag = true ; // begin drag state
                m_qDown = m_qNow ;
                m_vDownPt = ScreenToVector((float)nX, (float)nY) ;
        }
}

void ArcBall::OnMove(int nX, int nY)
{
        if(m_bDrag)
        {
                m_vCurrentPt = ScreenToVector((float)nX, (float)nY) ;
                m_qNow = m_qDown * QuatFromBallPoints( m_vDownPt, m_vCurrentPt ) ;
        }
}

void ArcBall::OnEnd()
{
        m_bDrag = false ;
}

void ArcBall::SetOffset( INT nX, INT nY )
{
        m_Offset.x = nX ; 
        m_Offset.y = nY ;
}

void ArcBall::SetWindow( int nWidth, int nHeight, float fRadius)
{
         m_nWidth = nWidth; 
         m_nHeight = nHeight; 
         m_fRadius = fRadius; 
         m_vCenter = D3DXVECTOR2(m_nWidth / 2.0f, m_nHeight / 2.0f);
}

const D3DXMATRIX* ArcBall::GetRotationMatrix()
{
        return D3DXMatrixRotationQuaternion(&m_mRotation, &m_qNow) ;
}

D3DXQUATERNION ArcBall::QuatFromBallPoints(const D3DXVECTOR3 &vFrom, const D3DXVECTOR3 &vTo)
{
        D3DXVECTOR3 vPart;
        float fDot = D3DXVec3Dot( &vFrom, &vTo );       // rotation angle
        D3DXVec3Cross( &vPart, &vFrom, &vTo );          // rotation axis

        return D3DXQUATERNION( vPart.x, vPart.y, vPart.z, fDot );
}

D3DXVECTOR3 ArcBall::ScreenToVector(float fScreenPtX, float fScreenPtY)
{
        // Scale to screen
        // xֵΪ¸º£¬ÊÇÒòΪDirectXʹÓÃ×óÊÖϵ
        FLOAT x = -( fScreenPtX - m_Offset.x - m_nWidth / 2 ) / ( m_fRadius * m_nWidth / 2 );
        FLOAT y = ( fScreenPtY - m_Offset.y - m_nHeight / 2 ) / ( m_fRadius * m_nHeight / 2 );

        FLOAT z = 0.0f;
        FLOAT mag = x * x + y * y;

        if( mag > 1.0f )
        {
                FLOAT scale = 1.0f / sqrtf( mag );
                x *= scale;
                y *= scale;
        }
        else
                z = sqrtf( 1.0f - mag );

        // Return vector
        return D3DXVECTOR3( x, y, z );
}

in function Move, we can see the multiplication of two Quaternions

m_qNow = m_qDown * QuatFromBallPoints( m_vDownPt, m_vCurrentPt ) ; 

function QuatFromBallPoints calculates the Quaternion bases on two points. I want to know what's the product mean?

code explanation: The arcball works when user draging the mouse, when the mouse button was down(suppose left button), the OnBegin function was called. when the mouse button was up, the OnEnd function was called, when user dragging the mouse, the OnMove function was called.


Solution

  • The multiplication means the composition of rotations. QuatFromBallPoints returns the rotation that maps m_vDownPt to m_vCurrentPt. This new rotation has to be combined with the arcball's current rotation (the rotation when dragging began).