-1

I have been attempting to move an object that I have control over in the forward direction, which I can do just fine, but as soon as I would like to implement having the ability to turn it seems as if any attempt I make can't seem to make the object turn properly. What always ends up happening is it starts to turn, then kind of just turns in on its self and goes into an unpredictable direction. What I would like to do so if I pressed my forward key, and held my right turn key at the same time, it would move in a circle.

What I have tried is the following

Moving Forward (works fine, when I don't do any sort of a turn). _13, _23 and _33 is my forward vector for my matrix.

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); 

I do the same thing for going backwards, but with a backwardmovement variable.

What I have tried to do for turning is just applying a rotation directly on the Y for the object.

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

Would anyone happen to know how I can get my object to be able to as if it was moving in a circle if I were to hold my forward and right turn key?

4

4 回答 4

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 ]

让我知道结果如何。

大编辑

这里有更多信息。

定义(框架)

一个框架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 表示,则称一组顶点相对于框架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

换一种写法,我们可以将其表示为 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}

谁在乎?

框架是实现所需效果的有用工具。假设我们世界中的所有对象都有 a position、 aforward和一个up向量。我们用来观看的相机也是世界上的一个物体。因此它也有 a position、 aforward和一个up向量。一个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
}

如果你注意到,虽然可能有问题。谁保证这一点up并且forward总是正交的?你必须自己处理。例如,您可以强迫自己仅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,因为我们需要从世界 -> 视图空间。

于 2013-06-23T01:31:00.177 回答
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 是添加一次性加速度还是设置恒定的力。我希望你在这里想要一个恒定的力量,除非你正在做小行星式的导航。

于 2013-06-23T19:48:18.033 回答
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() 返回一个矩阵。


当我说没有足够的信息来回答你的问题时,你明白我在说什么吗??? 我不得不假设太多,因为没有足够的上下文。

如果这不是您要找的内容,请在问题中添加更多上下文,否则您会发现没有比这更清楚的答案了。我们不是读心术的人。

于 2013-06-14T14:16:21.340 回答
0

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

于 2013-06-14T07:09:58.200 回答