1

我正在使用 WinSock 连接来获取加速度计信息和 iPhone 并进入 Direct3D 应用程序。我已经修改了 Apples GLGravity 的示例代码,让我的直升机相对于重力移动,但是我需要“限制”移动,这样直升机就不能倒飞!我试图像这样限制加速度计的输出

if (y < -0.38f) {
  y = -0.38f;
}

除了这似乎不起作用!?我唯一能想到的是我需要修改自定义矩阵,但我似乎无法理解我需要更改的内容。矩阵代码如下。

    _x = acceleration.x;
_y = acceleration.y;
_z = acceleration.z;

float length;
D3DXMATRIX matrix, t;

memset(matrix, '\0', sizeof(matrix));

D3DXMatrixIdentity(&matrix);

// Make sure acceleration value is big enough.
length = sqrtf(_x * _x + _y * _y + _z * _z);

if (length >= 0.1f && kInFlight == TRUE) { // We have a acceleration value good enough to work with.
    matrix._44 = 1.0f; // 

    // First matrix column is a gravity vector.
    matrix._11 = _x / length;
    matrix._12 = _y / length;
    matrix._13 = _z / length;

    // Second matrix is arbitrary vector in the plane perpendicular to the gravity vector {Gx, Gy, Gz}.
    // defined by the equation Gx * x + Gy * y + Gz * z = 0 in which we set x = 0 and y = 1.
    matrix._21 = 0.0f;
    matrix._22 = 1.0f;
    matrix._23 = -_y / _z;
    length = sqrtf(matrix._21 * matrix._21 + matrix._22 * matrix._22 + matrix._23 * matrix._23);
    matrix._21 /= length;
    matrix._22 /= length;
    matrix._23 /= length;

    // Set third matrix column as a cross product of the first two.
    matrix._31 = matrix._12 * matrix._23 - matrix._13 * matrix._22;
    matrix._32 = matrix._21 * matrix._13 - matrix._23 * matrix._11;
    matrix._33 = matrix._11 * matrix._22 - matrix._12 * matrix._21;
}

如果有人可以提供帮助,将不胜感激!

4

4 回答 4

1

我认为双重整合可能过于复杂了。如果我正确理解了这个问题,iPhone 会给你一个加速度计的值向量。假设用户没有挥动它,该向量将具有大致恒定的长度,并在重力作用下直接指向下方。

这样做有一个主要问题,那就是您无法判断用户何时围绕水平旋转手机。想象一下,您将手机放在桌子上,当您坐在它前面时,底部朝向您;重力矢量将是 (0, -1, 0)。现在将手机旋转 90 度左右,使底部朝向您的左侧,但仍平放在桌子上。重力矢量仍然是 (0, -1, 0)。但你真的希望你的直升机随手机转动。这是 iPhone 只有一个 2D 加速度计这一事实的基本限制,并且它正在从中推断出一个 3D 重力矢量。

所以让我们假设你已经告诉用户他们不允许像那样旋转他们的手机,他们必须把它和你的底点放在一起。没关系,您仍然可以从中获得很多控制权。

接下来,您需要限制输入,以使直升机在其一侧不会超过 90 度。想象一下,你得到的向量是一根附在你手机上的棍子,并在重力的作用下晃来晃去。您拥有的矢量描述了相对于手机平面的重力方向。如果是 (0, -1, 0),则摇杆直接指向下方 (-y)。如果是 (1, 0, 0),则摇杆指向手机的右侧 (+x),并暗示手机已顺时针旋转 90 度(远离您看手机)。

在这个比喻中假设棍子具有完全的旋转自由度。它可以指向手机的任何方向。所以移动棍子描述了一个球体的表面。但至关重要的是,您只希望摇杆能够在该球体的下半部分移动。如果用户扭动手机使摇杆位于球体的上半部分,您希望它盖上盖子,使其指向球体赤道附近的某个地方。

您可以通过使用极坐标非常干净地实现这一点。3D 矢量和极坐标是可互换的 - 您可以相互转换而不会丢失任何信息。

将您拥有的向量(当然是标准化的)转换为一组 3D 极坐标(您应该能够很容易地在网络上找到这个逻辑)。这将为您提供围绕水平面的角度,以及垂直面的角度(以及与原点的距离 - 对于归一化向量,这应该是 1.0)。如果垂直角为正,则向量在球体的上半部分,负值在球体的下半部分。然后,限制垂直角,使其始终为零或更小(球体的下半部分也是如此)。然后,您可以获取水平和封顶垂直角度,并将其转换回矢量。

如果将这个新向量插入您已有的矩阵代码中,它将为您提供正确的方向,仅限于您需要的运动范围。如果用户将手机转动稍微超过 90 度标记,它也会保持稳定 - 此逻辑将使您的方向矢量尽可能接近用户当前的方向,而不会超出您设置的限制。

于 2009-08-28T21:26:16.753 回答
0

看起来您正在使用来自手机的加速度矢量来定义正交参考系的一个轴。我想 +Y 是指向地面的,所以你会担心向量指向天空的情况。

考虑 iphone 报告 {0, -6.0, 0} 的情况。您将此向量更改为 {0, -.38, 0}。但它们都归一化为 {0, -1.0, 0}。因此,将 y 钳位在 -.38 处的效果受向量的其他两个分量大小的影响。

您真正想要的是在 Y 为负时限制矢量与 XZ 平面的角度。

假设当 Y 为负时,您希望将其限制为与 XZ 平面的夹角不超过 30 度。首先对向量进行归一化,然后:

const float limitAngle = 30.f * PI/180.f; // angle in radians
const float sinLimitAngle = sinf(limitAngle);
const float XZLimitLength = sqrtf(1-sinLimitAngle*sinLimitAngle);

if (_y < -sinLimitAngle)
{
    _y = -sinLimitAngle;
    float XZlengthScale = XZLimitLength / sqrtf(_x*_x + _z*_z);
    _x *= XZlengthScale;
    _z *= XZlengthScale;
}
于 2009-08-16T14:02:58.717 回答
0

首先尝试归一化加速度矢量。(编辑:检查长度后)(编辑编辑:我想我需要学习如何阅读......如何删除我的答案?)

于 2009-06-25T17:01:42.557 回答
0

因此,如果我理解正确,iPhone 正在为您提供加速度计数据,说明您在 3 轴上移动 iPhone 的难度。

我不熟悉那个苹果样品,所以我不知道它在做什么。但是,听起来您将加速度直接映射到方向,但我认为您想要做的是双重整合加速度以获得位置并查看位置变化以定位直升机。基本上,这更像是一个物理问题而不是 Direct3D 问题。

于 2009-07-17T02:09:18.483 回答