【问题标题】:Direct3D9 game: Spaceship cameraDirect3D9 游戏:宇宙飞船相机
【发布时间】:2014-09-13 15:55:58
【问题描述】:

我正在开发一个 Direct3D9 空间模拟器游戏,在该游戏中我需要创建一个摄像机来保持玩家飞船的位置和视角。目前,我将代码限制为前后移动、上下移动以及扫射。下面是我的代码,它有问题。一切都包装在一个类中,所有向量都在构造函数中初始化为 D3DXVECTOR3(0.0f, 0.0f, 0.0f),除了 LocalUp( D3DXVECTOR3(0.0f, 1.0f, 0.0f) ) 和 LocalAhead( D3DXVECTOR3(0.0f) , 0.0f, 1.0f) ) 并且浮点数设置为 0.0f;

D3DXVECTOR3 Position, LookAt ,PosDelta, PosDeltaWorld, WorldAhead, WorldUp, LocalUp, 
LocalAhead, Velocity;
D3DXMATRIX View, CameraRotation;
float SpeedX, SpeedY, SpeedZ;

void Update(float ElapsedTime)
{
    SpeedX = 0.0f;
    SpeedY = 0.0f;

    if(IsKeyDown('A'))
    {
        SpeedX = -0.02f;
        Velocity.x -= SpeedX;
    }
    if(IsKeyDown('D'))
    {
        SpeedX = 0.02f;
        Velocity.x += SpeedX;
    }
    if(IsKeyDown('X'))
    {
        SpeedZ += 0.01f;
        Velocity.z += SpeedZ;
    }
    if(IsKeyDown('Z'))
    {
        SpeedZ -= 0.01f;
        Velocity.z -= SpeedZ;
    }
    if(IsKeyDown('W'))
    {
        SpeedY = 0.02f;
        Velocity.y += SpeedY;
    }
    if(IsKeyDown('S'))
    {
        SpeedY = -0.02f;
        Velocity.y -= SpeedY;
    }

    D3DXVec3Normalize(&Velocity, &Velocity);

    PosDelta.x = Velocity.x * SpeedX;
    PosDelta.y = Velocity.y * SpeedY;
    PosDelta.z = Velocity.z * SpeedZ;

    D3DXMatrixRotationYawPitchRoll(&CameraRotation, 0, 0, 0);
    D3DXVec3TransformCoord(&WorldUp, &LocalUp, &CameraRotation);
    D3DXVec3TransformCoord(&WorldAhead, &LocalAhead, &CameraRotation);
    D3DXVec3TransformCoord(&PosDeltaWorld, &PosDelta, &CameraRotation);

    Position += PosDeltaWorld;
    LookAt = Position + WorldAhead;

    D3DXMatrixLookAtLH(&View, &Position, &LookAt, &WorldUp);
}

在应用程序的另一部分调用“D3DXMatrixPerspectiveFovLH”和“IDirect3DDevice9::SetTransform”函数。由于它们工作正常,我将不再谈论它们。

问题是,每当Z轴速度很大时,我单独或同时扫射和横向移动,相机的Z轴速度就会降低。而且,当速度几乎为0后,再按一下加速键,矢量的感觉就反转了,然后又恢复正常了。当以相当高的速度改变矢量的感觉时也会发生这种情况(例如,按下 X 然后立即按下“Z”)。谁能解释一下为什么会发生这种情况以及我该如何解决这个问题?

我还要问另一个问题:如果不按任何键,如何才能慢慢降低扫射和 Y 轴速度?我想在游戏中实现惯性效果。

如果有人可以帮助我,请回复!

编辑:新代码:

void NewFrontiers3DEntityPlayer::OnFrameUpdate(float ElapsedTime)
{
State.SpeedX = 0.0f;
State.SpeedY = 0.0f;
if(IsKeyDown(State.Keys[CAM_STRAFE_LEFT]))
    State.SpeedX = -0.02f;
if(IsKeyDown(State.Keys[CAM_STRAFE_RIGHT]))
    State.SpeedX = 0.02f;
if(IsKeyDown(State.Keys[CAM_MOVE_FORWARD]))
{
    State.SpeedZ += 0.01f;
}
if(IsKeyDown(State.Keys[CAM_MOVE_BACKWARD]))
{
    State.SpeedZ -= 0.01f;
}
if(IsKeyDown(State.Keys[CAM_MOVE_UP]))
    State.SpeedY = 0.02f;
if(IsKeyDown(State.Keys[CAM_MOVE_DOWN]))
    State.SpeedY = -0.02f;

State.Velocity.x = State.SpeedX;
State.Velocity.y = State.SpeedY;
State.Velocity.z = State.SpeedZ;

D3DXVec3Normalize(&State.Velocity, &State.Velocity);

State.PosDelta.x = State.Velocity.x * ElapsedTime;
State.PosDelta.y = State.Velocity.y * ElapsedTime;
State.PosDelta.z = State.Velocity.z * ElapsedTime;

D3DXMatrixRotationYawPitchRoll(&State.CameraRotation, 0, 0, 0);
D3DXVec3TransformCoord(&State.WorldUp, &State.LocalUp, &State.CameraRotation);
D3DXVec3TransformCoord(&State.WorldAhead, &State.LocalAhead, &State.CameraRotation);
D3DXVec3TransformCoord(&State.PosDeltaWorld, &State.PosDelta, &State.CameraRotation);

State.Position += State.PosDeltaWorld;
State.LookAt = State.Position + State.WorldAhead;

D3DXMatrixLookAtLH(&State.View, &State.Position, &State.LookAt, &State.WorldUp);

return;
}

“状态”是一个包含有关相机的所有信息的结构。

【问题讨论】:

  • 由于您使用的是 c++,我建议您使用类而不是全局变量
  • 我正在使用类,我使用了全局变量,因为在这里发布要容易得多。

标签: c++ vector camera directx direct3d9


【解决方案1】:

我猜你的速度会在你一次向多个方向移动时发生变化,因为你标准化了你的速度。

例如,在 Z 方向移动:

Velocity = (0, 0, 0.01)
Speed = (0,0, 0.01)
Normalized Velocity = (0, 0, 1)
PosDelta = (0, 0, 0.01)

并沿 X+Z 方向移动:

Velocity = (0.02, 0, 0.01)
Speed = (0.02, 0, 0.01)
Normalized Velocity = (0.897, 0, 0.435)
PosDelta = (0.018, 0, 0.0044)    

关于你的方向反转,我猜它可能部分与你使用速度/速度的相对奇怪的方法有关(见下文),并且可能是由于浮点数的不精确。关于最后一点,您认为以下代码输出如何(忽略潜在的编译器优化):

float test1 = 0f;

test1 += 0.1f;
test1 += 0.1f;
test1 += 0.1f;
test1 += 0.1f;
test1 += 0.1f;

test1 -= 0.1f;
test1 -= 0.1f;
test1 -= 0.1f;
test1 -= 0.1f;
test1 -= 0.1f;

printf("%g\n", test1);

它(可能?)不会输出0 的明显答案,因为0.1 不能在base-2 中精确表示。它在我的系统上打印1.49012e-008。可能发生的情况是您可能接近 0 但不完全是可能导致出现坐标反转的情况。您可以通过将速度四舍五入到一定的精度来消除这种情况。

您处理速度/速度/位置的整体方法有点奇怪,可能是您遇到困难的根源。例如,我希望Velocity 是一个表示玩家速度的向量,而不是你所拥有的标准化向量。我会做类似的事情:

SpeedX = 0.0f;
SpeedY = 0.0f;
SpeedZ = 0.0f

if(IsKeyDown('A')) SpeedX += -0.02f;
if(IsKeyDown('D')) SpeedX += 0.02f;
...

Velocity.x += SpeedX;
Velocity.y += SpeedY;
Velocity.z += SpeedZ;

D3DXVECTOR3 NormVelocity;
D3DXVec3Normalize(&NormVelocity, &Velocity);

//Round velocity here if you need to
Velocity.x = floor(Velocity.x * 10000) / 10000.0f;
...

float FrameTime = 1;  //Use last frame time here

PosDelta.x = Velocity.x * FrameTime;
PosDelta.y = Velocity.y * FrameTime;
PosDelta.z = Velocity.z * FrameTime;

当您在多个方向上移动时,您的速度会发生变化。如果您将FrameTime 设置为最后一帧的时间(或从它派生的值),它还可以让您正确补偿帧速率的变化。当玩家尝试同时朝两个相反的方向移动时,它还能正确地阻止玩家移动。

关于你关于 Y 速度衰减的最后一个问题,有几种方法可以解决。您可以简单地执行以下操作:

Velocity.y *= 0.7f;

每一帧(调整常数以满足您的需要)。更准确的模型是执行以下操作:

if (Velocity.y > 0) {
    Velocity.y -= 0.001f;    //Pick constant to suit
    if (Velocity.y < 0) Velocity.y = 0;
}

更好的方法是使用最后一帧时间来解释不同的帧速率,例如:

Velocity.y -= FrameTime * 0.2f;    //Pick constant to suit

【讨论】:

  • 感谢您的回复和帮助,但我还是有问题。我现在有一个代码,我将很快通过编辑将其发布在原始问题上。问题是无论我按什么键,可见速度都将保持不变(我说的是X轴速度)。你能帮帮我吗?
  • 没关系,我在编写新代码时忘记添加“+”号...感谢您解决我的问题!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-06-06
  • 2011-01-30
  • 1970-01-01
  • 1970-01-01
  • 2012-12-14
  • 2021-07-27
  • 1970-01-01
相关资源
最近更新 更多