4

我试图弄清楚如何让 Directx 中的相机根据它所面对的方向移动。

现在我移动相机的方式是将相机的当前位置和旋转传递给一个名为 PositionClass 的类。PositionClass 从另一个名为 InputClass 的类中获取键盘输入,然后更新相机的位置和旋转值,然后将其传递回相机类。

我编写了一些似乎对我有用的代码,使用相机俯仰和偏航,我可以让它朝着我指向相机的方向前进。

但是,当相机直视向上(俯仰=90)或直视向下(俯仰=-90)时,它仍然会改变相机的 X 和 Z 位置(取决于偏航)。

预期的行为是在向上或向下直视时,它只会沿 Y 轴移动,而不是沿 X 或 Z 轴移动。

这是计算新相机位置的代码

void PositionClass::MoveForward(bool keydown)
{
float radiansY, radiansX;


// Update the forward speed movement based on the frame time
// and whether the user is holding the key down or not.
if(keydown)
{
    m_forwardSpeed += m_frameTime * m_acceleration;

    if(m_forwardSpeed > (m_frameTime * m_maxSpeed))
    {
        m_forwardSpeed = m_frameTime * m_maxSpeed;
    }
}
else
{
    m_forwardSpeed -= m_frameTime * m_friction;

    if(m_forwardSpeed < 0.0f)                                                               
    {
        m_forwardSpeed = 0.0f;
    }
}

// ToRadians() just multiplies degrees by 0.0174532925f
radiansY = ToRadians(m_rotationY); //yaw
radiansX = ToRadians(m_rotationX); //pitch

// Update the position.
m_positionX += sinf(radiansY) * m_forwardSpeed;
m_positionY += -sinf(radiansX) * m_forwardSpeed;
m_positionZ += cosf(radiansY) * m_forwardSpeed;

return;
 }

重要的部分是最后更新位置的位置。

到目前为止,我只能推断出我的数学技能很糟糕。

那么,任何人都可以帮助我解决这个难题吗?我创建了一个小提琴来帮助测试数学。

编辑:小提琴使用我在 MoveForward 函数中使用的相同数学,如果您将音高设置为 90,您可以看到 Z 轴仍在修改

4

2 回答 2

6

感谢 Chaosed0 的回答,我能够找出正确的公式来计算特定方向的运动。

下面的固定代码与上面基本相同,但现在进行了简化和扩展,使其更易于理解。


首先我们确定相机移动的量,在我的例子中是m_forwardSpeed,但在这里我将它定义为偏移量。

float offset = 1.0f;

接下来,您将需要获取相机的 X 和 Y 旋转值(以度为单位!)

float pitch = camera_rotationX;
float yaw   = camera_rotationY;

然后我们将这些值转换为弧度

float pitchRadian = pitch * (PI / 180); // X rotation
float yawRadian   = yaw   * (PI / 180); // Y rotation

现在这里是我们确定新位置的地方:

float newPosX = offset *  sinf( yawRadian ) * cosf( pitchRadian );
float newPosY = offset * -sinf( pitchRadian );
float newPosZ = offset *  cosf( yawRadian ) * cosf( pitchRadian );

请注意,我们只将 X 和 Z 位置乘以 pitchRadian 的余弦,这是为了抵消相机在直视 (90) 或直视 (-90) 时的偏航方向和偏移量。

最后,你需要告诉你的相机新的位置,我不会介绍,因为它很大程度上取决于你如何实现你的相机。显然这样做是不正常的,而且可能效率低下。然而,正如 Chaosed0 所说,这对我来说是最有意义的!

于 2013-04-25T00:02:13.993 回答
4

老实说,我不完全确定我理解你的代码,所以让我尝试提供不同的观点。

我喜欢考虑这个问题的方式是在球坐标中,基本上只是 3D 中的极坐标。球坐标由三个数字定义:一个半径和两个角度。一个角度是偏航,另一个应该是俯仰,假设你没有滚动(我相信phi如果你有滚动,有一种方法可以得到,但我现在想不出如何)。在传统的数学符号中,theta是你的偏航,phi是你的俯仰,radius是你的移动速度,如下所示。

球坐标

请注意,phi 和 theta 的定义不同,具体取决于您查看的位置。

基本上,问题是获得一个m_forwardSpeed远离相机的点,具有正确的俯仰和偏航。为此,我们将“原点”设置为您的相机位置,获取球坐标,将其转换为笛卡尔坐标,然后将其添加到您的相机位置:

float radius = m_forwardSpeed;
float theta = m_rotationY;
float phi = m_rotationX

//These equations are from the wikipedia page, linked above
float xMove = radius*sinf(phi)*cosf(theta);
float yMove = radius*sinf(phi)*sinf(theta);
float zMove = radius*cosf(phi);

m_positionX += xMove;
m_positionY += yMove;
m_positionZ += zMove;

当然,您可以压缩很多这样的代码,但为了清楚起见,我对其进行了扩展。

你可以把它想象成在你的相机周围画一个球体。球体上的每个点都是下一个时间步长的潜在位置,具体取决于相机的旋转。

这可能不是最有效的方法,但在我看来,这肯定是最简单的考虑方法。实际上看起来这几乎正是您在代码中尝试执行的操作,但角度上的操作只是有点偏离。

于 2013-04-24T22:08:45.350 回答