Матрица акселерометра Direct3D и iPhone - PullRequest
1 голос
/ 29 марта 2009

Я использую соединение WinSock, чтобы получить информацию об акселерометре и iPhone в приложении Direct3D. Я изменил пример кода Apple's 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 ]

1 голос
/ 29 августа 2009

Я думаю, что двойная интеграция, вероятно, усложняет ситуацию. Если я правильно понимаю проблему, iPhone дает вам вектор значений от акселерометров. Предполагая, что пользователь не размахивает им, этот вектор будет иметь приблизительно постоянную длину и направлен прямо вниз под действием силы тяжести.

Существует одна серьезная проблема с этим, это то, что вы не можете сказать, когда пользователь поворачивает телефон вокруг горизонтали. Представьте, что вы лежите на столе, положив телефон лицом к себе, когда сидите перед ним; вектор гравитации будет (0, -1, 0). Теперь поверните телефон на 90 градусов, чтобы дно было повернуто влево, но на столе все еще ровно. Вектор гравитации по-прежнему будет (0, -1, 0). Но вы бы действительно хотели, чтобы ваш вертолет поворачивался вместе с телефоном. Это основное ограничение того факта, что iPhone имеет только 2D-акселерометр, и он экстраполирует 3D-гравитационный вектор из этого.

Итак, давайте предположим, что вы сказали пользователю, что ему не разрешается поворачивать свой телефон таким образом, и он должен держать его с нижней точкой для вас. Это нормально, вы все равно можете получить от этого большой контроль.

Далее вам нужно ограничить входное значение таким образом, чтобы вертолет никогда не отклонялся более чем на 90 градусов по бокам. Представьте себе вектор, который вы дали как палку, прикрепленную к вашему телефону, и болтающуюся гравитацией. Вектор, который у вас есть, описывает направление силы тяжести относительно плоской поверхности телефона. Если бы это было (0, -1, 0), палка направлена ​​прямо вниз (-y). если бы это было (1, 0, 0), ручка указывает на правую часть телефона (+ x) и подразумевает, что телефон был повернут на 90 градусов по часовой стрелке (глядя на вас на телефон).

Предположим, что в этой метафоре палка имеет полную свободу вращения. Он может указывать в любом направлении от телефона. Таким образом, перемещение палки описывает поверхность сферы. Но самое главное, вы хотите, чтобы палка могла перемещаться по нижней половине этой сферы. Если пользователь поворачивает телефон так, чтобы палка находилась в верхней половине сферы, вы хотите, чтобы он был ограничен таким образом, чтобы он указывал куда-то вокруг экватора сферы.

Вы можете достичь этого довольно чисто, используя полярные координаты. Трехмерные векторы и полярные координаты взаимозаменяемы - вы можете конвертировать в и из нее без потери какой-либо информации.

Преобразуйте ваш вектор (нормализованный, конечно) в набор трехмерных полярных координат (вы должны легко найти эту логику в сети). Это даст вам угол вокруг горизонтальной плоскости и угол для вертикальной плоскости (и расстояние от начала координат - для нормализованного вектора, это должно быть 1,0). Если вертикальный угол положительный, вектор находится в верхней половине сферы, отрицательный - в нижней половине. Затем закройте вертикальный угол так, чтобы он всегда был равен нулю или меньше (и так в нижней половине сферы). Затем вы можете взять горизонтальный и ограниченный вертикальный угол и преобразовать его обратно в вектор.

Этот новый вектор, если он подключен к уже имеющемуся матричному коду, даст вам правильную ориентацию, ограниченную диапазоном движения, который вам нужен. Также будет стабильно, если пользователь повернет свой телефон немного за отметку 90 градусов - эта логика будет держать ваш вектор направления как можно ближе к текущей ориентации пользователя, не выходя за установленные пределы.

0 голосов
/ 17 июля 2009

Так что, если я правильно понимаю, iPhone передает вам данные акселерометра, говоря, как сильно вы перемещаете iPhone по 3 осям.

Я не знаком с этим образцом яблока, поэтому я не знаю, что он делает. Тем не менее, звучит так, будто вы отображаете ускорение непосредственно на ориентацию, но я думаю, что вы хотите вдвойне интегрировать ускорение, чтобы получить положение и посмотреть на изменения положения, чтобы ориентировать вертолет. По сути, это больше физическая проблема, чем проблема Direct3D.

0 голосов
/ 16 августа 2009

Похоже, вы используете вектор ускорения от телефона, чтобы определить одну ось ортогональной системы отсчета. И я полагаю, что + Y указывает на землю, поэтому вас беспокоит случай, когда вектор указывает на небо.

Рассмотрим случай, когда iphone сообщает {0, -6.0, 0}. Вы измените этот вектор на {0, -.38, 0}. Но они оба нормализуются до {0, -1.0, 0}. Таким образом, эффект ограничения y при -.38 зависит от величины двух других компонентов вектора.

Что вам действительно нужно, так это ограничить угол вектора плоскостью XZ, если Y отрицателен.

Скажем, вы хотите ограничить его не более 30 градусов относительно плоскости XZ, когда Y отрицательно. Сначала нормализуйте вектор, затем:

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;
}
0 голосов
/ 25 июня 2009

Попробуйте сначала нормализовать вектор ускорения. (редактировать: после того, как вы проверите длину) (редактировать: думаю, мне нужно научиться читать ... как удалить мой ответ?)

...