📄 chmazcam.cpp
字号:
}
void ChMazeCameraControl::MoveRight( float fUnits, bool boolDraw )
{
QvPerspectiveCamera* pNode;
if (pNode = GetCameraNode())
{
float fX = fUnits;
float fY = 0;
float fZ = 0;
ComputeRelativeCameraShift( fX, fY, fZ );
if(m_pMazeWnd->GetRenderContext()->GetViewerMode() == walk)
{
fY = 0;
}
else
{
// Because of 3dr bug, our axis is -never- exactly vertical
// If it's -almost- vertical, then zero the y delta
// Additionally, we have round-off error.
if( (fY*fY) / (fX * fX + fZ * fZ) <= 1e-3)
{
fY = 0.;
}
}
Shift(fX, fY, fZ, boolDraw);
}
}
void ChMazeCameraControl::MoveUp( float fUnits, bool boolDraw )
{
QvPerspectiveCamera* pNode;
// This is -relative-
if (pNode = GetCameraNode())
{
float fX = 0;
float fY = fUnits;
float fZ = 0;
ComputeRelativeCameraShift( fX, fY, fZ );
Shift(fX, fY, fZ, boolDraw);
}
}
void ChMazeCameraControl::MoveDown( float fUnits, bool boolDraw )
{
QvPerspectiveCamera* pNode;
// This is always relative
if (pNode = GetCameraNode())
{
float fX = 0;
float fY = -fUnits;
float fZ = 0;
ComputeRelativeCameraShift( fX, fY, fZ );
Shift(fX, fY, fZ, boolDraw);
}
}
void ChMazeCameraControl::Yaw( float fDegrees, bool boolDraw )
{
// Positive degrees is left
QvPerspectiveCamera* pNode;
if (pNode = GetCameraNode())
{
float fDeltaRadians;
fDeltaRadians = (fDegrees / 180.0) * PI;
ChQvPCameraRenderData *pRenderData = (ChQvPCameraRenderData *)(GetCameraNode()->GetRenderData());
GxVec3f dir = pRenderData->GetDir();
GxVec3f up = pRenderData->GetUp();
GxVec3f axis = up;
GxTransform3Wf mat(axis, fDeltaRadians);
dir = mat * dir;
up = mat * up;
pRenderData->SetDir(dir);
pRenderData->SetUp(up);
pRenderData->SynchCamera();
if (boolDraw)
{
InvalidateCamera( pNode );
}
}
}
void ChMazeCameraControl::Turn( float fDegrees, bool boolDraw )
{
// Positive degrees is left
QvPerspectiveCamera* pNode;
if (pNode = GetCameraNode())
{
float fDeltaRadians;
fDeltaRadians = (fDegrees / 180.0) * PI;
ChQvPCameraRenderData *pRenderData = (ChQvPCameraRenderData *)(GetCameraNode()->GetRenderData());
GxVec3f dir = pRenderData->GetDir();
GxVec3f up = pRenderData->GetUp();
GxVec3f axis(0., 1., 0);
GxTransform3Wf mat(axis, fDeltaRadians);
dir = mat * dir;
up = mat * up;
#if 0
// Now straighten your head if walking
if(m_pMazeWnd->GetRenderContext()->GetViewerMode() == walk)
{
HeadsUp(dir, up);
}
#endif
pRenderData->SetDir(dir);
pRenderData->SetUp(up);
pRenderData->SynchCamera();
if (boolDraw)
{
InvalidateCamera( pNode );
}
}
}
void ChMazeCameraControl::Pitch( float fDegrees, bool boolDraw )
{
// Positive degrees is up
QvPerspectiveCamera* pNode;
if (pNode = GetCameraNode())
{
float fDeltaRadians;
fDeltaRadians = (fDegrees / 180.0) * PI;
ChQvPCameraRenderData *pRenderData = (ChQvPCameraRenderData *)(GetCameraNode()->GetRenderData());
GxVec3f dir = pRenderData->GetDir();
GxVec3f up = pRenderData->GetUp();
GxVec3f axis = dir.cross(up);
GxTransform3Wf mat(axis, fDeltaRadians);
dir = mat * dir;
up = mat * up;
pRenderData->SetDir(dir);
pRenderData->SetUp(up);
pRenderData->SynchCamera();
if (boolDraw)
{
InvalidateCamera( pNode );
}
}
}
void ChMazeCameraControl::Roll( float fDegrees, bool boolDraw )
{
/* Positive degrees is counter-
clockwise */
// Does nothing if walking
if(m_pMazeWnd->GetRenderContext()->GetViewerMode() == walk)
{
return;
}
QvPerspectiveCamera* pNode;
if (pNode = GetCameraNode())
{
float fDeltaRadians;
fDeltaRadians = (fDegrees / 180.0) * PI;
ChQvPCameraRenderData *pRenderData = (ChQvPCameraRenderData *)(GetCameraNode()->GetRenderData());
GxVec3f dir = pRenderData->GetDir();
GxVec3f up = pRenderData->GetUp();
GxVec3f axis = dir;
GxTransform3Wf mat(axis, fDeltaRadians);
dir = mat * dir;
up = mat * up;
pRenderData->SetDir(dir);
pRenderData->SetUp(up);
pRenderData->SynchCamera();
if (boolDraw)
{
InvalidateCamera( pNode );
}
}
}
void ChMazeCameraControl::LookAt( GxVec3f &target, bool boolDraw )
{
QvPerspectiveCamera* pNode;
if (pNode = GetCameraNode())
{
ChQvPCameraRenderData *pRenderData = (ChQvPCameraRenderData *)(GetCameraNode()->GetRenderData());
GxVec3f dir = target;
GxVec3f loc = pRenderData->GetLoc();
dir -= loc;
dir .normalize;
pRenderData->SetDir(dir);
pRenderData->SynchCamera();
if (boolDraw)
{
InvalidateCamera( pNode );
}
}
}
void ChMazeCameraControl::SetLookDir( GxVec3f &lookDir, bool boolDraw )
{
QvPerspectiveCamera* pNode;
if (pNode = GetCameraNode())
{
ChQvPCameraRenderData *pRenderData = (ChQvPCameraRenderData *)(GetCameraNode()->GetRenderData());
GxVec3f dir = lookDir;
dir .normalize;
pRenderData->SetDir(dir);
pRenderData->SynchCamera();
if (boolDraw)
{
InvalidateCamera( pNode );
}
}
}
void ChMazeCameraControl::RotateBallHorz(float fDegrees, bool boolDraw /*= true */)
{
GxVec3f axis (0., 1., 0);
RotateBall( axis, PI * fDegrees / 180., boolDraw);
}
void ChMazeCameraControl::RotateBallVert(float fDegrees, bool boolDraw /*= true */)
{
GxVec3f axis (1., 0., 0);
RotateBall( axis, PI * fDegrees / 180., boolDraw);
}
void ChMazeCameraControl::RotateBall(const ChPoint &ptLastMouse, const ChPoint &ptMouse, int iDiameter, bool boolDraw)
{
// Rotate the camera location as if on the surface of a trackball
// the 'finger' on the ball has moved from ptLastMouse to ptMouse.
// the 'diameter' of the ball determines how sensitive it is
// for now, we'll just use the relative offset from one pt to the other
if(ptMouse.x == ptLastMouse.x && ptMouse.y == ptLastMouse.y) return; // No move!
GxVec3f delta(ptMouse.x - ptLastMouse.x, ptMouse.y - ptLastMouse.y, 0.);
delta.x() /= iDiameter;
delta.y() /= -iDiameter; // flip coords in y
float angle = -PI * delta.magnitude();
GxVec3f axis, zaxis(0., 0., 1.);
axis = zaxis.cross(delta);
RotateBall(axis, angle, boolDraw);
}
/*----------------------------------------------------------------------------
ChMazeCameraControl protected methods
----------------------------------------------------------------------------*/
void ChMazeCameraControl::RotateBall(GxVec3f axis, float fRadians, bool boolDraw /*= true */)
{
QvPerspectiveCamera* pNode = GetCameraNode();
if(!pNode) return; // nothing to rotate!
ComputeRelativeCameraShift(axis.x(), axis.y(), axis.z());
axis.normalize();
// Get the bounding cube center, and use this as the center of rotation
GxVec3f lower, upper;
GetMazeWnd()->GetBounds()->GetWorldBounds(lower, upper);
GxVec3f center = upper;
center += lower; center *= .5; // avg
ChQvPCameraRenderData *pRenderData = (ChQvPCameraRenderData *)(GetCameraNode()->GetRenderData());
GxVec3f dir = pRenderData->GetDir();
GxVec3f up = pRenderData->GetUp();
GxVec3f loc = pRenderData->GetLoc();
GxTransform3Wf mat;
#if defined(CH_USE_3DR)
mat.Translate(center);
GxTransform3Wf rotMat(axis, fRadians);
mat = rotMat.Compose(mat);
mat.Translate(GxVec3f(-center.x(), -center.y(), -center.z()));
loc = mat * loc;
#elif (defined(CH_USE_RLAB) || defined(CH_USE_D3D))
GxTransform3Wf rotMat(axis, fRadians); // ??????????????????
loc -= center;
loc = rotMat * loc;
loc += center;
#else
#pragma message("camera motion not defined")
#endif
GxVec3f toMove = loc;
toMove -= pRenderData->GetLoc(); // This is so we can use Shift,
// which does collision testing for us
dir = rotMat * dir;
up = rotMat * up;
//pRenderData->SetLoc(loc);
if(Shift(toMove.x(), toMove.y(), toMove.z(), false, true, false))
{
// Don't do rotates if the shift collided
pRenderData->SetDir(dir);
pRenderData->SetUp(up);
pRenderData->SynchCamera();
}
if (boolDraw)
{
InvalidateCamera( GetCameraNode() );
}
}
QvPerspectiveCamera* ChMazeCameraControl::GetCameraNode()
{
return (QvPerspectiveCamera*)(m_pMazeWnd->GetRenderContext()->GetCurrentCamera());
}
void ChMazeCameraControl::InvalidateCamera( QvPerspectiveCamera* pCameraNode )
{
GetMazeWnd()->GetRenderContext()->SetDirty();
pCameraNode->Invalidate( GetMazeWnd()->GetRenderContext() );
}
void ChMazeCameraControl::
ComputeRelativeCameraShift( float &fX, float &fY, float &fZ )
{
/* This method transforms from camera to world-like space for use in
camera motion relative to camera orientation. No translations, just
adjusts x,y,z from the camera node's orientation to world. */
GxVec3f tmp;
#if 0 && OLD_NAVIGATION
if(m_pMazeWnd->GetRenderContext()->GetViewerMode() == walk)
{
ChQvPCameraRenderData *pRenderData = (ChQvPCameraRenderData *)(GetCameraNode()->GetRenderData());
GxVec3f dir = pRenderData->GetDir();
GxVec3f up = pRenderData->GetUp();
GxVec3f n = dir.cross(up);
tmp.x() = fZ * dir.x() + fX * n.x();
tmp.y() = fY;
tmp.z() = fZ * dir.z() + fX * n.z();
}
else
#endif
{
ChQvPCameraRenderData *pRenderData = (ChQvPCameraRenderData *)(GetCameraNode()->GetRenderData());
GxVec3f dir = pRenderData->GetDir();
GxVec3f up = pRenderData->GetUp();
GxVec3f n = dir.cross(up);
tmp.x() = fZ * dir.x() + fY * up.x() + fX * n.x();
tmp.y() = fZ * dir.y() + fY * up.y() + fX * n.y();
tmp.z() = fZ * dir.z() + fY * up.z() + fX * n.z();
}
fX = tmp.x();
fY = tmp.y();
fZ = tmp.z();
}
void ChMazeCameraControl::
ComputeRelativeCameraShift( GxVec3f &vec, const GxVec3f &dir, const GxVec3f &up )
{
/* This method transforms from camera to world-like space for use in
camera motion relative to camera orientation. No translations, just
adjusts x,y,z from the camera node's orientation to world. */
GxVec3f tmp;
GxVec3f n = dir.cross(up);
tmp.x() = vec.z() * dir.x() + vec.y() * up.x() + vec.x() * n.x();
tmp.y() = vec.z() * dir.y() + vec.y() * up.y() + vec.x() * n.y();
tmp.z() = vec.z() * dir.z() + vec.y() * up.z() + vec.x() * n.z();
vec = tmp;
}
const float EPS = 1.e-12; // nigh unto zero
void ChMazeCameraControl::HeadsUp(GxVec3f &dir, GxVec3f &up, bool boolAllowInverted)
{
GxVec3f yAxis(0., 1., 0.);
float prod = up.dot(yAxis);
if(fabs(prod) < EPS) return; // horizontal, let it be
GxVec3f n = yAxis.cross(dir); // normal to plane defined by (dir, yaxis)
if (n.dot(n) > EPS)
{
up = dir.cross(n);
}
else
{
// special case; looking straight up or down
// we should have trapped this if dir and up were really perps, buy
// maybe they weren't
return;
}
if (up.dot(up) < EPS)
{
up.set( 0, 1, 0);
}
up.normalize();
if(boolAllowInverted && prod < 0)
{
// use up-down sense of original
up.x() = -up.x();
up.y() = -up.y();
up.z() = -up.z();
}
}
void ChMazeCameraControl::HeadsUp(bool boolDraw)
{
QvPerspectiveCamera* pNode;
if (pNode = GetCameraNode())
{
ChQvPCameraRenderData *pRenderData = (ChQvPCameraRenderData *)(GetCameraNode()->GetRenderData());
GxVec3f dir = pRenderData->GetDir();
GxVec3f up = pRenderData->GetUp();
// Now straighten your head
HeadsUp(dir, up);
pRenderData->SetDir(dir);
pRenderData->SetUp(up);
pRenderData->SynchCamera();
if (boolDraw)
{
InvalidateCamera( pNode );
}
}
}
// end of file
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -