我目前正在编写一个Arcball(用于模型视图相机),我正在查看MS DXUT代码,他们有一个Arcball实现如下
#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 );
}
在函数Move中,我们可以看到两个四元数的乘法
m_qNow = m_qDown * QuatFromBallPoints( m_vDownPt, m_vCurrentPt ) ;
函数QuatFromBallPoints在两点上计算四元数基数。我想知道这个产品意味着什么?
代码说明: 当用户拖动鼠标时,弧形球起作用,当鼠标按钮停止时(假设为左键),调用OnBegin函数。当鼠标按钮启动时,调用OnEnd函数,当用户拖动鼠标时,调用了OnMove函数。
答案 0 :(得分:2)
乘法意味着旋转的组成。 QuatFromBallPoints
会返回将m_vDownPt
映射到m_vCurrentPt
的轮播。这个新的旋转必须与弧球的当前旋转(拖动开始时的旋转)相结合。