物体如何能够向前移动并具有转向能力?

时间:2013-06-14 01:17:37

标签: c++ math physics game-physics

我一直试图向前移动一个我控制过的物体,我可以做得很好,但是一旦我想实现有能力转动它就好像我做的任何尝试一样似乎无法使对象正常转动。总是最终发生的事情是它开始转向,然后只是转向自我并进入一个不可预测的方向。如果我按下前进键并同时按住右转键,我想这样做,它会移动一圈。

我试过的是以下

向前移动(当我不做任何转弯时工作正常)。 _13,_23和_33是我矩阵的前向矢量。

float x = transform->getLocalTransform()._13 * (fowardmovement * elapsedtime);
float y = transform->getLocalTransform()._23 * (fowardmovement * elapsedtime);
float z = transform->getLocalTransform()._33 * (fowardmovement * elapsedtime);

// apply the movement as an impulse to the rigid body for the object
objectrigidbody->addImpulseForce(x, y, z); 

我向后退做同样的事情,但是有一个向后移动变量。

我试图进行转弯只是直接在Y上为对象应用旋转。

// the function rotate applies the rotation directly to the object, with no return value
objectrigidbody->rotate(0.0, turnmovement * elapsedtime, 0.0); 

如果我要按住前进和右转键,是否有人碰巧知道如何让我的物体能够如同移动一样?

4 个答案:

答案 0 :(得分:1)

我猜你正在处理表格

的矩阵
[ side_x up_x forward_x position_x ]
[ side_y up_y forward_y position_y ]
[ side_z up_z forward_z position_z ]
[      0    0         0          1 ]

因此,围绕局部向上矢量a弧度旋转,将局部变换矩阵乘以围绕Y向量旋转的旋转矩阵,即

[ side_x up_x forward_x position_x ]     [ cos(a) 0 -sin(a) 0 ]
[ side_y up_y forward_y position_y ] *=  [      0 1       0 0 ]
[ side_z up_z forward_z position_z ]     [ sin(a) 0  cos(a) 0 ]
[      0    0         0          1 ]     [      0 0       0 1 ]

让我知道结果如何。

BIG EDIT

以下是更多信息。

定义(框架)

frame F是四个齐次坐标x_F,y_F,z_F,o_F的集合,使得x_F,y_F,z_F的第四坐标为零,并且o_F的第四个坐标为1,并且x_F,y_F,z_F是成对正交的(正交性不是真正必要,但我只是在这里定义它)。 o_F称为帧的原点。如果顶点的集合的坐标是相对于F表示的,则称它们相对于框架

示例1

在Blender或Maya中制作的网格的顶点相对于模型的框架表示。

定义(帧变换矩阵)

给定两个帧F和G,帧变换矩阵 M是一个4x4矩阵M,这样

  1. M * x_F = x_G
  2. M * y_F = y_G
  3. M * z_F = z_G
  4. M * o_F = o_G
  5. 另外,我们可以将其表示为M * [x_F,y_F,z_F,o_F] = [x_G,y_G,z_G,o_G],其中[...]分别表示由列跨越的矩阵。再次以不同的方式编写,并假设可逆性无关紧要,我们可以写

    M = [x_G y_G z_G o_G] * [x_F y_F z_F o_F]^{-1}
    

    示例2

    假设我们需要从世界空间转换到视图(或眼睛)空间。我们假设世界空间坐标只是标准的基础向量,我们假设我们在视图空间中的相机以o_V为中心,并对其应用了一些旋转,以便得到向量x_V,y_V和z_V。那么M就等于

    M = [x_V y_V z_V o_V] * I^{-1} = [x_V y_V z_V o_V]
    

    示例3

    现在假设我们在模型中有一个批处理顶点,顶点的坐标在模型空间中表示。该模型位于世界空间的某个位置,具有一定的方向。因此,模型具有原点o_M和一些旋转x_M,y_m,z_M。将顶点从模型空间转换为世界空间的矩阵等于

    M = I * [x_M y_M z_M o_M]^{-1} = [x_M y_M z_M o_M]^{-1}
    

    注意必须注意矩阵必须反转。

    示例4

    现在假设我们想直接从模型空间到视图空间。这很容易,因为我们已经推导出了模型的矩阵 - >世界与世界 - >视图。因此

    M = [x_V y_V z_V o_V] * [x_M y_M z_M o_M]^{-1}
    

    谁在乎?

    框架是实现所需效果的有用工具。假设我们世界中的对象都有positionforwardup向量。我们所看到的相机也是世界上的一个对象。因此,它还有positionforwardup向量。 Frame类的第一个版本可能是

    struct Frame { // version 1
        vec3 position;
        vec3 forward;
        vec3 up;
    };
    

    但是我们想让Frame做有用的事情。所以我们可以添加成员函数。

    struct Frame { // version 2
        vec3 position;
        vec3 forward;
        vec3 up;
        mat4 getLocalToWorldTransform() const;
        mat4 getWorldToLocalTransform() const;
    }
    

    mat4 Frame::getWorldToLocalTransform() const成员函数可能如下所示:

    mat4 Frame::getWorldToLocalTransform() const {
        vec3 side = crossProduct(forward, up);
        //          [x_F  y_F    z_F       o_F  ] (!!)
        return mat4(side, up, -forward, position); // +forward or -forward depending on the graphics API
    }
    

    如果您注意到可能存在问题。谁保证upforward始终正交?你必须自己照顾好自己。例如,您可以强制自己仅围绕forward向量旋转up方向,以便它们始终保持正交。 我会将mat4 Frame::getLocalToWorldTransform() const的实施细节留给您。

    现在我们希望我们的Frame能够在世界各地活动。我们可以添加更多成员函数

    struct Frame { // version 3
        vec3 position;
        vec3 forward;
        vec3 up;
        mat4 getLocalToWorldTransform() const;
        mat4 getWorldToLocalTransform() const;
        void moveForward(const float steps);
        void moveBackward(const float steps);
        void rotateClockwiseAroundUp(const float radians);
        void rotateCounterClockwiseAroundUp(const float radians);
    }
    

    void Frame::rotateCounterClockwiseAroundUp(const float radians)的实现可能如下所示:

    void Frame::rotateCounterClockwiseAroundUp(const float radians) {
        direction = mat3::rotationFromAngleAndAxis(radians, up) * direction;
    }
    

    因此,您的相机应该保留自己的Frame课程。要旋转相机,请使用成员函数rotateCounterClockwiseAroundUprotateClockwiseAroundUp。要向后和向前移动相机,请使用成员函数moveForwardmoveBackward。要获得转换矩阵,请使用成员函数getWorldToLocalTransform,因为我们需要从世界 - >查看空间。

答案 1 :(得分:1)

正如其他评论所提到的那样,只需将移动值戳入矩阵即可进入世界空间。这意味着您必须完成修改移动值的工作,使它们尊重对象的局部方向。你想要一些像这样工作的东西(方法名称组成,因为每个人都注意到我不知道你的api是什么)

// apply the rotation.
// I'm assuming this is in local space, if there were a 'rotateLocal' function you should
// use that
objectrigidbody->rotate(0.0, turnmovement * elapsedtime, 0.0); 

// with made-up but probably available function
Vec3 forward = objectrigidbody.getForwardVector();
// most api's give you a method or property to get the worldspace vector that
// corresponds to 'forward' in your coordinate system.  Use that.


// scale that vector (I'm assuming it's a unit vector: they usually are)
// by speed:
forward *= fowardmovement * elapsedtime;

// apply the impulse:
objectrigidbody->addImpulseForce(forward.x, forward.y, forward.z);

请注意,即使在这里,我也不确定你是否得到了你想要的东西:addImpulseForce是否会增加一次加速度,或者它是否设置了恒定的力量。除非你做小行星式导航,否则我希望你能在这里不断发力。

答案 2 :(得分:0)

您的旋转必须是向前移动量的函数。尝试通过所需圆的向前移动划分半径旋转。

答案 3 :(得分:0)

这个问题目前还不清楚,但我会捅一下。

听起来你的向前和向后都在工作,但是旋转只会导致物体旋转,同时仍然沿着你正在向前和向后移动的轴移动。

原因是你的前进方向与你的轮换之间似乎没有明显的联系。换句话说,物体的加速度矢量没有考虑到脉冲矢量在旋转。

由于你的变量transform似乎是指向某个矩阵的指针,->getLocalTranform()应用了一些变换矩阵而._x3是一种取出某些加速度矢量的方法,我会觉得您没有在加速度矩阵上应用旋转矩阵。

假设objectrigidbody是另一个矩阵(由于名称没有描述,这个不清楚),也许你可以这样做:

float x = transform->rotate(0.0, turnmovement * elapsedtime, 0.0)
                   ->getLocalTransform()._13 * (fowardmovement * elapsedtime);
float y = transform->rotate(0.0, turnmovement * elapsedtime, 0.0)
                   ->getLocalTransform()._23 * (fowardmovement * elapsedtime);
float z = transform->rotate(0.0, turnmovement * elapsedtime, 0.0)
                   ->getLocalTransform()._33 * (fowardmovement * elapsedtime);
objectrigidbody->addImpulseForce(x, y, z); // to apply the movement

还假设rotate()返回一个矩阵。


当我说 没有足够的信息来回答你的问题时,你看到了我的目标吗? 我必须假设太多,因为有足够的背景。

如果这不是您想要的,请在问题中添加更多上下文,否则您会发现除此之外您不会得到任何答案。我们不介意读者。