我正在试图弄清楚如何根据相机朝向的方向使相机直接移动。
现在我移动相机的方法是将相机的当前位置和旋转传递给名为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;
}
重要部分是最后更新位置的位置。
到目前为止,我只能推断出我有可怕的数学技能。
那么,任何人都能帮助我解决这个难题吗?我创建了一个fiddle来帮助测试数学。
编辑:小提琴使用我在MoveForward函数中使用的相同数学运算,如果将音高设置为90,则可以看到Z轴仍在被修改
答案 0 :(得分:5)
感谢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所说,这对我来说是最有意义的!
答案 1 :(得分:3)
说实话,我并不完全确定我理解你的代码,所以让我试着提供一个不同的视角。
我喜欢考虑这个问题的方式是spherical coordinates,基本上只是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;
当然,您可以压缩很多代码,但为了清晰起见,我对其进行了扩展。
您可以考虑在相机周围画一个球体。球体上的每个点都是下一个时间步的潜在位置,具体取决于相机的旋转。
这可能不是最有效的方法,但在我看来,这当然是最简单的思考方式。实际上看起来这几乎就是你在代码中尝试做的事情,但角度上的操作只是一个小位。