Direct3D 与 iPhone 加速度计矩阵
我正在使用 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;
}
如果有人可以提供帮助,将不胜感激!
I am using a WinSock connection to get the accelerometer info off and iPhone and into a Direct3D application. I have modified Apples GLGravity's sample code to get my helicopter moving in relation to gravity, however I need to "cap" the movement so the helicopter can't fly upside down! I have tried to limit the output of the accelerometer like so
if (y < -0.38f) {
y = -0.38f;
}
Except this doesn't seem to work!? The only thing I can think of is I need to modify the custom matrix, but I can't seem to get my head around what I need to be changing. The matrix is code is below.
_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;
}
If anyone can help it would be much appreciated!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我认为双重集成可能使事情变得过于复杂。 如果我对问题的理解正确的话,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 度标记,它也会保持稳定 - 这种逻辑将使您的方向矢量尽可能接近用户当前的方向,而不会超出您设置的限制。
I think double integration is probably over-complicating things. If I understand the problem correctly, the iPhone is giving you a vector of values from the accelerometers. Assuming the user isn't waving it around, that vector will be of roughly constant length, and pointing directly downwards with gravity.
There is one major problem with this, and that is that you can't tell when the user rotates the phone around the horizontal. Imagine you lie your phone on the table, with the bottom facing you as you're sitting in front of it; the gravity vector would be (0, -1, 0). Now rotate your phone around 90 degrees so the bottom is facing off to your left, but is still flat on the table. The gravity vector is still going to be (0, -1, 0). But you'd really want your helicopter to have turned with the phone. It's a basic limitation of the fact that the iPhone only has a 2D accelerometer, and it's extrapolating a 3D gravity vector from that.
So let's assume that you've told the user they're not allowed to rotate their phone like that, and they have to keep it with the bottom point to you. That's fine, you can still get a lot of control from that.
Next, you need to cap the input such that the helicopter never goes more than 90 degrees over on it's side. Imagine the vector that you're given as being a stick attached to your phone, and dangling with gravity. The vector you have is describing the direction of gravity, relative to the phone's flat surface. If it were (0, -1, 0) the stick is pointing directly downwards (-y). if it were (1, 0, 0), the stick is pointing to the right of the phone (+x), and implies that the phone has been twisted 90 degrees clockwise (looking away from you at the phone).
Assume in this metaphor that the stick has full rotational freedom. It can be pointing in any direction from the phone. So moving the stick around describes the surface of a sphere. But crucially, you only want the stick to be able to move around the lower half of that sphere. If the user twists the phone so that the stick would be in the upper half of the sphere, you want it to cap such that it's pointing somewhere around the equator of the sphere.
You can achieve this quite cleanly by using polar co-ordinates. 3D vectors and polar co-ordinates are interchangeable - you can convert to and from without losing any information.
Convert the vector you have (normalised of course) into a set of 3D polar co-ordinates (you should be able to find this logic on the web quite easily). This will give you an angle around the horizontal plane, and an angle for vertical plane (and a distance from the origin - for a normalised vector, this should be 1.0). If the vertical angle is positive, the vector is in the upper half of the sphere, negative it's in the lower half. Then, cap the vertical angle so that it is always zero or less (and so in the lower half of the sphere). Then you can take the horizontal and capped vertical angle, and convert it back into a vector.
This new vector, if plugged into the matrix code you already have, will give you the correct orientation, limited to the range of motion you need. It will also be stable if the user turns their phone slightly beyond the 90 degree mark - this logic will keep your directional vector as close to the user's current orientation as possible, without going beyond the limit you set.
首先尝试标准化加速度矢量。 (编辑:检查长度后)(编辑编辑:我想我需要学习如何阅读......我如何删除我的答案?)
Try normalizing the acceleration vector first. (edit: after you check the length) (edit edit: I guess I need to learn how to read... how do I delete my answer?)
因此,如果我理解正确的话,iPhone 正在向您提供加速计数据,说明您在 3 个轴上移动 iPhone 的力度。
我对那个苹果样品不熟悉,所以我不知道它在做什么。 然而,听起来您正在将加速度直接映射到方向,但我认为您想要做的是对加速度进行双重积分以获得位置并查看位置的变化以便确定直升机的方向。 基本上,这更像是一个物理问题,而不是 Direct3D 问题。
So if I understand this correctly, the iPhone is feeding you accelerometer data, saying how hard you're moving the iPhone in 3 axes.
I'm not familiar with that apple sample, so I don't know what its doing. However, it sounds like you're mapping acceleration directly to orientation, but I think what you want to do is doubly integrate the acceleration in order to obtain a position and look at changes in position in order to orient the helicopter. Basically, this is more of a physics problem than a Direct3D problem.
看起来您正在使用手机的加速度矢量来定义正交参考系的一个轴。 我认为 +Y 指向地面,所以您担心矢量指向天空的情况。
考虑 iPhone 报告 {0, -6.0, 0} 的情况。 您需要将此向量更改为 {0, -.38, 0}。 但它们都标准化为 {0, -1.0, 0}。 因此,将 y 钳位在 -0.38 的效果受到矢量其他两个分量大小的影响。
你真正想要的是当 Y 为负时限制向量与 XZ 平面的角度。
假设当 Y 为负时,您希望将其与 XZ 平面的夹角限制为不超过 30 度。 首先对向量进行归一化:
It looks like you are using the acceleration vector from the phone to define one axis of a orthogonal frame of reference. And I suppose +Y is points towards the ground so you are concerned about the case when the vector points towards the sky.
Consider the case when the iphone reports {0, -6.0, 0}. You will change this vector to {0, -.38, 0}. But they both normalize to {0, -1.0, 0}. So, the effect of clamping y at -.38 is influenced by magnitude of the other two components of the vector.
What you really want is to limit the angle of the vector to the XZ plane when Y is negative.
Say you want to limit it to be no more than 30 degrees to the XZ plane when Y is negative. First normalize the vector then: