这是一个使用 OpenGL 而不是 Direct X 的旧游戏引擎的片段。您可能需要调整坐标系的惯用手,但基本原则仍然适用。在 3D 环境中处理运动时;摄像机、玩家或世界对象所经历的运动应该通过一个switch
语句而不是一堆if else
语句来完成。
看看这个片段,了解在 OpenGL 游戏引擎中完成的旋转运动。
void Player::move( Action action, float fDeltaTime ) {
v3LookDirection = m_v3LookCenter - m_v3Position;
switch( action ) {
case MOVING_FORWARD: {
// ... code here ...
}
case MOVING_BACK: {
// ... code here ...
}
case MOVING_RIGHT: {
// ... code here ...
}
case MOVING_LEFT: {
// ... code here ...
}
case LOOKING_LEFT: {
/*float fSin = -sin( fDeltaTime * m_fAngularSpeed );
float fCos = cos( fDeltaTime * m_fAngularSpeed );
m_v3LookCenter.m_fX = m_v3Position.m_fX + (-fSin * v3LookDirection.m_fZ + fCos * v3LookDirection.m_fX );
m_v3LookCenter.m_fZ = m_v3Position.m_fZ + ( fCos * v3LookDirection.m_fZ + fSin * v3LookDirection.m_fX );
break;*/
// Third Person
float fSin = sin( fDeltaTime * m_fAngularSpeed );
float fCos = -cos( fDeltaTime * m_fAngularSpeed );
m_v3Position.m_fX = m_v3LookCenter.m_fX + (-fSin * v3LookDirection.m_fZ + fCos * v3LookDirection.m_fX );
m_v3Position.m_fZ = m_v3LookCenter.m_fZ + ( fCos * v3LookDirection.m_fZ + fSin * v3LookDirection.m_fX );
break;
}
case LOOKING_RIGHT: {
/*float fSin = sin( fDeltaTime * m_fAngularSpeed );
float fCos = cos( fDeltaTime * m_fAngularSpeed );
m_v3LookCenter.m_fX = m_v3Position.m_fX + (-fSin * v3LookDirection.m_fZ + fCos * v3LookDirection.m_fX );
m_v3LookCenter.m_fZ = m_v3Position.m_fZ + ( fCos * v3LookDirection.m_fZ + fSin * v3LookDirection.m_fX );
break;*/
// Third Person
float fSin = -sin( fDeltaTime * m_fAngularSpeed );
float fCos = -cos( fDeltaTime * m_fAngularSpeed );
m_v3Position.m_fX = m_v3LookCenter.m_fX + (-fSin * v3LookDirection.m_fZ + fCos * v3LookDirection.m_fX );
m_v3Position.m_fZ = m_v3LookCenter.m_fZ + ( fCos * v3LookDirection.m_fZ + fSin * v3LookDirection.m_fX );
break;
}
case LOOKING_UP: {
m_v3LookCenter.m_fY -= fDeltaTime * m_fAngularSpeed * m_MouseLookState;
// Check Maximum Values
if ( m_v3LookCenter.m_fY > (m_v3Position.m_fY + m_fMaxUp ) ) {
m_v3LookCenter.m_fY = m_v3Position.m_fY + m_fMaxUp;
} else if ( m_v3LookCenter.m_fY < (m_v3Position.m_fY - m_fMaxDown) ) {
m_v3LookCenter.m_fY = m_v3Position.m_fY - m_fMaxDown;
}
break;
}
} // switch
}
其中所有声明的局部变量和成员变量m_v3...
都是 Vector3 对象。Vector3 对象有一个x,y,z
组件和可以对向量进行的所有可用数学运算,而 Action 是一种枚举类型。
这个函数在我的Scene
课堂上被调用。
void Scene::playerAction( float fMouseXDelta, float fMouseYDelta ) {
if ( fMouseXDelta != 0.0f ) {
m_player.move( LOOKING_RIGHT, fMouseXDelta );
}
if ( fMouseYDelta != 0.0f ) {
m_player.move( LOOKING_UP, fMouseYDelta );
}
}
而且还在Scene::update()
void Scene::update() {
UserSettings* pUserSettings = UserSettings::get();
AudioManager* pAudio = AudioManager::getAudio();
bool bPlayerMoving = false;
// Movement
if ( pUserSettings->isAction( MOVING_FORWARD ) ) {
m_player.move( MOVING_FORWARD, GameOGL::getPhysicsTimeStep() );
bPlayerMoving = true;
}
if ( pUserSettings->isAction( MOVING_BACK ) ) {
m_player.move( MOVING_BACK, GameOGL::getPhysicsTimeStep() );
bPlayerMoving = true;
}
if ( pUserSettings->isAction( MOVING_LEFT ) ) {
m_player.move( MOVING_LEFT, GameOGL::getPhysicsTimeStep() );
bPlayerMoving = true;
}
if ( pUserSettings->isAction( MOVING_RIGHT ) ) {
m_player.move( MOVING_RIGHT, GameOGL::getPhysicsTimeStep() );
bPlayerMoving = true;
}
if ( bPlayerMoving && !m_bPlayerWalking ) {
pAudio->setLooping( AUDIO_FOOTSTEPS, true );
pAudio->play( AUDIO_FOOTSTEPS );
m_bPlayerWalking = true;
}
else if ( !bPlayerMoving && m_bPlayerWalking ) {
pAudio->stop( AUDIO_FOOTSTEPS );
m_bPlayerWalking = false;
}
// Bunch more code here.
}
这也与我不打算在这里展示的GameOGL
类相关联。messageHandler()
这来自一个由近 50k 行代码组成的中型到大型项目。在这里展示每一个工件都太大了,所以请不要问,因为这个引擎中的所有东西都是集成在一起的。我只是展示了用于进行旋转运动的基本数学运算,无论是通过按键还是鼠标移动来调用。
现在你必须记住这一点,因为它很重要。您看到的实际计算来自Player
执行旋转的类,您可能无法直接使用。如果坐标系的手性与此处使用的不同;您必须对具有适当符号的适当坐标轴成员使用适当的三角函数才能使计算正确。当惯用手改变时,所暗示的旋转轴以及旋转的初始方向也会改变。3D 数学不是很有趣吗?
编辑
哦,我还注意到您正在使用DirectX's
::CreateFromYawPitchRoll()
创建旋转矩阵;这没关系,但您需要小心使用标准欧拉角的旋转。如果您开始同时进行超过一个度数的旋转;您最终会遇到 Gimbal Lock。避免在 3D 旋转中使用 Gimbal Lock Problems;最好使用Quaternions
数学对他们来说有点难以理解,它们的概念并不难理解,但使用它们实际上很容易并且在计算上也非常有效。许多数学库都包含它们;DirectX 的数学库应该如此,开源也应该如此GLM
广泛用于 OpenGL 和 GLSL 的数学库。如果您不确定 Gimbal Lock 和 Quaternions,您可以进行 Google 搜索以查找这些主题;有很多关于他们的信息。高级 3D... 嗯哼... 4D 数学不是很有趣吗?