📄 d3dutil.cpp
字号:
{
D3DXMATRIX mRotDelta;
D3DXVECTOR3 vAccel = D3DXVECTOR3(0,0,0);
if( m_bEnablePositionMovement )
{
// Update acceleration vector based on keyboard state
if( IsKeyDown(m_aKeys[CAM_MOVE_FORWARD]) )
vAccel.z += 1.0f;
if( IsKeyDown(m_aKeys[CAM_MOVE_BACKWARD]) )
vAccel.z -= 1.0f;
if( m_bEnableYAxisMovement )
{
if( IsKeyDown(m_aKeys[CAM_MOVE_UP]) )
vAccel.y += 1.0f;
if( IsKeyDown(m_aKeys[CAM_MOVE_DOWN]) )
vAccel.y -= 1.0f;
}
if( IsKeyDown(m_aKeys[CAM_STRAFE_RIGHT]) )
vAccel.x += 1.0f;
if( IsKeyDown(m_aKeys[CAM_STRAFE_LEFT]) )
vAccel.x -= 1.0f;
}
// Normalize vector so if moving 2 dirs (left & forward),
// the camera doesn't move faster than if moving in 1 dir
D3DXVec3Normalize( &vAccel, &vAccel );
// Scale the acceleration vector
vAccel *= m_fMoveScaler;
if( m_bMovementDrag )
{
// Is there any acceleration this frame?
if( D3DXVec3LengthSq( &vAccel ) > 0 )
{
// If so, then this means the user has pressed a movement key\
// so change the velocity immediately to acceleration
// upon keyboard input. This isn't normal physics
// but it will give a quick response to keyboard input
m_vVelocity = vAccel;
m_fDragTimer = m_fTotalDragTimeToZero;
m_vVelocityDrag = vAccel / m_fDragTimer;
}
else
{
// If no key being pressed, then slowly decrease velocity to 0
if( m_fDragTimer > 0 )
{
// Drag until timer is <= 0
m_vVelocity -= m_vVelocityDrag * fElapsedTime;
m_fDragTimer -= fElapsedTime;
}
else
{
// Zero velocity
m_vVelocity = D3DXVECTOR3(0,0,0);
}
}
}
else
{
// No drag, so immediatly change the velocity
m_vVelocity = vAccel;
}
}
//-----------------------------------------------------------------------------
// Name: ConstrainToBoundary
// Desc: Clamps pV to lie inside m_vMinBoundary & m_vMaxBoundary
//-----------------------------------------------------------------------------
void CBaseCamera::ConstrainToBoundary( D3DXVECTOR3* pV )
{
// Constrain vector to a bounding box
pV->x = max(pV->x, m_vMinBoundary.x);
pV->y = max(pV->y, m_vMinBoundary.y);
pV->z = max(pV->z, m_vMinBoundary.z);
pV->x = min(pV->x, m_vMaxBoundary.x);
pV->y = min(pV->y, m_vMaxBoundary.y);
pV->z = min(pV->z, m_vMaxBoundary.z);
}
//-----------------------------------------------------------------------------
// Name: MapKey
// Desc: Maps a windows virtual key to an enum
//-----------------------------------------------------------------------------
D3DUtil_CameraKeys CBaseCamera::MapKey( UINT nKey )
{
// This could be upgraded to a method that's user-definable but for
// simplisity, we'll use a hardcoded mapping.
switch( nKey )
{
case VK_LEFT: return CAM_STRAFE_LEFT;
case VK_RIGHT: return CAM_STRAFE_RIGHT;
case VK_UP: return CAM_MOVE_FORWARD;
case VK_DOWN: return CAM_MOVE_BACKWARD;
case VK_PRIOR: return CAM_MOVE_UP; // pgup
case VK_NEXT: return CAM_MOVE_DOWN; // pgdn
case 'A': return CAM_STRAFE_LEFT;
case 'D': return CAM_STRAFE_RIGHT;
case 'W': return CAM_MOVE_FORWARD;
case 'S': return CAM_MOVE_BACKWARD;
case 'Q': return CAM_MOVE_DOWN;
case 'E': return CAM_MOVE_UP;
case VK_NUMPAD4: return CAM_STRAFE_LEFT;
case VK_NUMPAD6: return CAM_STRAFE_RIGHT;
case VK_NUMPAD8: return CAM_MOVE_FORWARD;
case VK_NUMPAD2: return CAM_MOVE_BACKWARD;
case VK_NUMPAD9: return CAM_MOVE_UP;
case VK_NUMPAD3: return CAM_MOVE_DOWN;
case VK_HOME: return CAM_RESET;
}
return CAM_UNKNOWN;
}
//-----------------------------------------------------------------------------
// Name: Reset
// Desc: Reset the camera's position back to the default
//-----------------------------------------------------------------------------
VOID CBaseCamera::Reset()
{
SetViewParams( &m_vDefaultEye, &m_vDefaultLookAt );
}
//-----------------------------------------------------------------------------
// Name: CFirstPersonCamera
// Desc: Constructor
//-----------------------------------------------------------------------------
CFirstPersonCamera::CFirstPersonCamera()
{
}
//-----------------------------------------------------------------------------
// Name: FrameMove
// Desc: Update the view matrix based on user input & elapsed time
//-----------------------------------------------------------------------------
VOID CFirstPersonCamera::FrameMove( FLOAT fElapsedTime )
{
if( IsKeyDown(m_aKeys[CAM_RESET]) )
Reset();
// Get the mouse movement (if any) if the mouse button are down
if( m_bMouseLButtonDown || m_bMouseMButtonDown || m_bMouseRButtonDown )
UpdateMouseDelta( fElapsedTime );
// Get amount of velocity based on the keyboard input and drag (if any)
UpdateVelocity( fElapsedTime );
// Simple euler method to calculate position delta
D3DXVECTOR3 vPosDelta = m_vVelocity * fElapsedTime;
// If rotating the camera
if( m_bMouseLButtonDown || m_bMouseMButtonDown || m_bMouseRButtonDown )
{
// Update the pitch & yaw angle based on mouse movement
float fYawDelta = m_vRotVelocity.x;
float fPitchDelta = m_vRotVelocity.y;
// Invert pitch if requested
if( m_bInvertPitch )
fPitchDelta = -fPitchDelta;
m_fCameraPitchAngle += fPitchDelta;
m_fCameraYawAngle += fYawDelta;
// Limit pitch to straight up or straight down
m_fCameraPitchAngle = max( -D3DX_PI/2.0f, m_fCameraPitchAngle );
m_fCameraPitchAngle = min( +D3DX_PI/2.0f, m_fCameraPitchAngle );
}
// Make a rotation matrix based on the camera's yaw & pitch
D3DXMATRIX mCameraRot;
D3DXMatrixRotationYawPitchRoll( &mCameraRot, m_fCameraYawAngle, m_fCameraPitchAngle, 0 );
// Transform vectors based on camera's rotation matrix
D3DXVECTOR3 vWorldUp, vWorldAhead;
D3DXVECTOR3 vLocalUp = D3DXVECTOR3(0,1,0);
D3DXVECTOR3 vLocalAhead = D3DXVECTOR3(0,0,1);
D3DXVec3TransformCoord( &vWorldUp, &vLocalUp, &mCameraRot );
D3DXVec3TransformCoord( &vWorldAhead, &vLocalAhead, &mCameraRot );
// Transform the position delta by the camera's rotation
D3DXVECTOR3 vPosDeltaWorld;
D3DXVec3TransformCoord( &vPosDeltaWorld, &vPosDelta, &mCameraRot );
if( !m_bEnableYAxisMovement )
vPosDeltaWorld.y = 0.0f;
// Move the eye position
m_vEye += vPosDeltaWorld;
if( m_bClipToBoundary )
ConstrainToBoundary( &m_vEye );
// Update the lookAt position based on the eye position
m_vLookAt = m_vEye + vWorldAhead;
// Update the view matrix
D3DXMatrixLookAtLH( &m_mView, &m_vEye, &m_vLookAt, &vWorldUp );
D3DXMatrixInverse( &m_mCameraWorld, NULL, &m_mView );
}
//-----------------------------------------------------------------------------
// Name: CModelViewerCamera
// Desc: Constructor
//-----------------------------------------------------------------------------
CModelViewerCamera::CModelViewerCamera()
{
D3DXMatrixIdentity( &m_mWorld );
D3DXMatrixIdentity( &m_mModelRot );
D3DXMatrixIdentity( &m_mModelLastRot );
m_vModelCenter = D3DXVECTOR3(0,0,0);
m_fRadius = 5.0f;
m_fDefaultRadius = 5.0f;
m_fMinRadius = 1.0f;
m_fMaxRadius = FLT_MAX;
m_bLimitPitch = false;
m_bEnablePositionMovement = false;
m_nRotateModelButtonMask = MOUSE_LEFT_BUTTON;
m_nZoomButtonMask = MOUSE_WHEEL;
m_nRotateCameraButtonMask = MOUSE_RIGHT_BUTTON;
}
//-----------------------------------------------------------------------------
// Name: FrameMove
// Desc: Update the view matrix & the model's world matrix based
// on user input & elapsed time
//-----------------------------------------------------------------------------
VOID CModelViewerCamera::FrameMove( FLOAT fElapsedTime )
{
if( IsKeyDown(m_aKeys[CAM_RESET]) )
Reset();
// Get the mouse movement (if any) if the mouse button are down
if( m_nCurrentButtonMask != 0 )
UpdateMouseDelta( fElapsedTime );
// Get amount of velocity based on the keyboard input and drag (if any)
UpdateVelocity( fElapsedTime );
// Simple euler method to calculate position delta
D3DXVECTOR3 vPosDelta = m_vVelocity * fElapsedTime;
// Change the radius from the camera to the model based on wheel scrolling
if( m_nMouseWheelDelta && m_nZoomButtonMask == MOUSE_WHEEL )
m_fRadius -= m_nMouseWheelDelta * m_fRadius * 0.1f;
m_fRadius = min( m_fMaxRadius, m_fRadius );
m_fRadius = max( m_fMinRadius, m_fRadius );
m_nMouseWheelDelta = 0;
// Get the inverse of the arcball's rotation matrix
D3DXMATRIX mCameraRot;
D3DXMatrixInverse( &mCameraRot, NULL, m_ViewArcBall.GetRotationMatrix() );
// Transform vectors based on camera's rotation matrix
D3DXVECTOR3 vWorldUp, vWorldAhead;
D3DXVECTOR3 vLocalUp = D3DXVECTOR3(0,1,0);
D3DXVECTOR3 vLocalAhead = D3DXVECTOR3(0,0,1);
D3DXVec3TransformCoord( &vWorldUp, &vLocalUp, &mCameraRot );
D3DXVec3TransformCoord( &vWorldAhead, &vLocalAhead, &mCameraRot );
// Transform the position delta by the camera's rotation
D3DXVECTOR3 vPosDeltaWorld;
D3DXVec3TransformCoord( &vPosDeltaWorld, &vPosDelta, &mCameraRot );
// Move the lookAt position
m_vLookAt += vPosDeltaWorld;
if( m_bClipToBoundary )
ConstrainToBoundary( &m_vLookAt );
// Update the eye point based on a radius away from the lookAt position
m_vEye = m_vLookAt - vWorldAhead * m_fRadius;
// Update the view matrix
D3DXMatrixLookAtLH( &m_mView, &m_vEye, &m_vLookAt, &vWorldUp );
D3DXMATRIX mInvView;
D3DXMatrixInverse( &mInvView, NULL, &m_mView );
mInvView._41 = mInvView._42 = mInvView._43 = 0;
D3DXMATRIX mModelLastRotInv;
D3DXMatrixInverse(&mModelLastRotInv, NULL, &m_mModelLastRot);
// Accumulate the delta of the arcball's rotation in view space.
// Note that per-frame delta rotations could be problematic over long periods of time.
D3DXMATRIX mModelRot;
mModelRot = *m_WorldArcBall.GetRotationMatrix();
m_mModelRot *= m_mView * mModelLastRotInv * mModelRot * mInvView;
m_mModelLastRot = mModelRot;
// Since we're accumulating delta rotations, we need to orthonormalize
// the matrix to prevent eventual matrix skew
D3DXVECTOR3* pXBasis = (D3DXVECTOR3*) &m_mWorld._11;
D3DXVECTOR3* pYBasis = (D3DXVECTOR3*) &m_mWorld._21;
D3DXVECTOR3* pZBasis = (D3DXVECTOR3*) &m_mWorld._31;
D3DXVec3Normalize( pXBasis, pXBasis );
D3DXVec3Cross( pYBasis, pZBasis, pXBasis );
D3DXVec3Normalize( pYBasis, pYBasis );
D3DXVec3Cross( pZBasis, pXBasis, pYBasis );
// Translate the rotation matrix to the same position as the lookAt position
m_mModelRot._41 = m_vLookAt.x;
m_mModelRot._42 = m_vLookAt.y;
m_mModelRot._43 = m_vLookAt.z;
// Translate world matrix so its at the center of the model
D3DXMATRIX mTrans;
D3DXMatrixTranslation( &mTrans, -m_vModelCenter.x, -m_vModelCenter.y, -m_vModelCenter.z );
m_mWorld = mTrans * m_mModelRot;
}
//-----------------------------------------------------------------------------
// Name: Reset
// Desc: Reset the camera's position back to the default
//-----------------------------------------------------------------------------
VOID CModelViewerCamera::Reset()
{
CBaseCamera::Reset();
D3DXMatrixIdentity( &m_mWorld );
m_fRadius = m_fDefaultRadius;
m_WorldArcBall.Reset();
m_ViewArcBall.Reset();
}
//-----------------------------------------------------------------------------
// Name: HandleMessages
// Desc: Call this from your message proc so this class can handle window messages
//-----------------------------------------------------------------------------
LRESULT CModelViewerCamera::HandleMessages( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
CBaseCamera::HandleMessages( hWnd, uMsg, wParam, lParam );
if( (uMsg == WM_LBUTTONDOWN && m_nRotateModelButtonMask == MOUSE_LEFT_BUTTON) ||
(uMsg == WM_MBUTTONDOWN && m_nRotateModelButtonMask == MOUSE_MIDDLE_BUTTON) ||
(uMsg == WM_RBUTTONDOWN && m_nRotateModelButtonMask == MOUSE_RIGHT_BUTTON) )
{
int iMouseX = GET_X_LPARAM(lParam);
int iMouseY = GET_Y_LPARAM(lParam);
m_WorldArcBall.OnBegin( iMouseX, iMouseY );
}
if( (uMsg == WM_LBUTTONDOWN && m_nRotateCameraButtonMask == MOUSE_LEFT_BUTTON) ||
(uMsg == WM_MBUTTONDOWN && m_nRotateCameraButtonMask == MOUSE_MIDDLE_BUTTON) ||
(uMsg == WM_RBUTTONDOWN && m_nRotateCameraButtonMask == MOUSE_RIGHT_BUTTON) )
{
int iMouseX = GET_X_LPARAM(lParam);
int iMouseY = GET_Y_LPARAM(lParam);
m_ViewArcBall.OnBegin( iMouseX, iMouseY );
}
if( uMsg == WM_MOUSEMOVE )
{
int iMouseX = GET_X_LPARAM(lParam);
int iMouseY = GET_Y_LPARAM(lParam);
m_WorldArcBall.OnMove( iMouseX, iMouseY );
m_ViewArcBall.OnMove( iMouseX, iMouseY );
}
if( (uMsg == WM_LBUTTONUP && m_nRotateModelButtonMask == MOUSE_LEFT_BUTTON) ||
(uMsg == WM_MBUTTONUP && m_nRotateModelButtonMask == MOUSE_MIDDLE_BUTTON) ||
(uMsg == WM_RBUTTONUP && m_nRotateModelButtonMask == MOUSE_RIGHT_BUTTON) )
{
m_WorldArcBall.OnEnd();
}
if( (uMsg == WM_LBUTTONUP && m_nRotateCameraButtonMask == MOUSE_LEFT_BUTTON) ||
(uMsg == WM_MBUTTONUP && m_nRotateCameraButtonMask == MOUSE_MIDDLE_BUTTON) ||
(uMsg == WM_RBUTTONUP && m_nRotateCameraButtonMask == MOUSE_RIGHT_BUTTON) )
{
m_ViewArcBall.OnEnd();
}
return FALSE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -