Как перевести камеру после поворота сцены?

В настоящее время я пытаюсь визуализировать здание в OpenGL ES 2 на Android. Когда я прокручиваю влево, вся сцена должна двигаться влево (то же самое с правым, нижним и верхним). Теперь, когда я поворачиваю модель на 90°, оси меняются местами. Когда я прокручиваю вправо, модель перемещается вверх, а не вправо (то же самое с другой осью).

Как я могу перевести камеру, не имея проблемы с текущим поворотом сцены? Когда я работаю с телефоном, я всегда хочу переместить объект в том направлении, в котором я смахиваю. Когда я сначала вызываю перевод, перевод работает нормально, но вращение имеет некоторые ошибки.

Обновление: я создал большую часть класса камеры (предложено в ответах):

private Vector3D c = new Vector3D(eye); // copy of eye
private Vector3D l = Vector3D.getNormalized
        (Vector3D.subtract(center, eye)); // normalized center-eye
private Vector3D u = new Vector3D(up); // up (normalized)

public void rotateX(float angle) {
    // Now you can rotate L vector left and
    // right by rotating it around U by any angle. ??
}

public void rotateY(float angle) {
    // If you also need to look up and down
    // (rotate) you need to rotate both L and U around S ??
}

public void rotateZ(float angle) {
    // to tilt left and right you need to rotate U around L. ??
}

// move left and right
// C = C+S * inputfactor
public void translateX(float inputFactor) {
    Vector3D s = Vector3D.cross(l, u);
    Vector3D sTimesInput = mul(s, inputFactor);
    c = new Vector3D(c).add(sTimesInput);
}

// move forward and backward
// C = C+L*inputfactor
public void translateY(float inputFactor) {
    Vector3D lTimesInput = mul(l, inputFactor);
    c = new Vector3D(c).add(lTimesInput);
}

// move up and down
// C = C+U * inputfactor
public void translateZ(float inputFactor) {
    Vector3D uTimesInput = mul(u, inputFactor);
    c = new Vector3D(c).add(uTimesInput);
}

// reconstruct lookAt - eye,center,up

public Vector3D getEye() {
    return new Vector3D(c);
}

public Vector3D getCenter() {
    return new Vector3D(c).add(new Vector3D(l));
}

public Vector3D getUp() {
    return new Vector3D(u);
}

public float[] createLookAt() {
    Vector3D eye = getEye();
    Vector3D center = getCenter();
    Vector3D up = getUp();
    return new float[] { eye.getX(), eye.getY(), eye.getZ(), center.getX(),
            center.getY(), center.getZ(), up.getX(), up.getY(), up.getZ() };
}

// helper-function
public Vector3D mul(Vector3D vec, float factor) {
    return new Vector3D(vec.getX() * factor, vec.getY() * factor,
            vec.getZ() * factor);
}

Как я могу повернуть вектор вокруг другого вектора на угол?


person Frame91    schedule 08.01.2014    source источник
comment
Я предлагаю вам написать класс, который содержит параметры камеры, описанные в моем ответе (C, L, U). Реализуйте методы для перемещения и вращения в классе, как описано. Обратите внимание, что L и U всегда имеют длину 1 . inputFactor является скаляром (чтобы переместиться на 5 точек в сторону, используйте centerVector.add(sVector*5)). Чтобы установить равные начальные параметры, глядя на ваш первый пост, сделайте: C = глаз, L = нормализовано (центр-глаз), U = нормализовано (вверху). Чтобы преобразовать его обратно в setLookAtM, используйте уравнения, опубликованные в разделе «Реконструкция векторов lookAt»:   -  person Matic Oblak    schedule 09.01.2014
comment
Я рад, что вы снова ответили! Я обновил свой вопрос с большей частью класса камеры. Не могли бы вы рассказать мне, как повернуть вектор вокруг другого вектора на угол? Единственными ответами, которые я нашел в Google, были кватернионы. Спасибо!   -  person Frame91    schedule 10.01.2014
comment
Вращение вектора вокруг некоторой точки аналогично вращению сцены (где вращается каждая вершина). Вы можете использовать матрицы или кватернионы, если у вас есть библиотека. Или вы можете просто найти некоторые из них. Также вы можете использовать матрицу openGL (установить идентичность, а затем повернуть ее) и получить ее как массив 4x4 и выполнить умножение вручную. Использование некоторых библиотек кватернионов должно быть таким простым: Vector3 rotatedVector = Quaternion.AngleAxis(angle, vector) * originalVector;   -  person Matic Oblak    schedule 10.01.2014


Ответы (2)


Я думаю, вы смешиваете концепцию перемещения камеры и вращения объекта. Сначала вам нужно отделить действие по вращению вашего объекта от любого взаимодействия с камерой. Вы должны иметь возможность делать что угодно с объектом, вообще не меняя камеру. Для этого просто используйте матрицу модели, чтобы описать перемещение/вращение/масштабирование вашего объекта. Затем вы управляете своей камерой отдельно, используя Matrix.setLookAtM с eyeX, eyeY, eyeZ, которые не зависят от положения вашей модели. И точка, на которую нужно обратить внимание, в вашем случае зависит от eyeX, eyeY, eyeZ, поскольку вы хотите все время смотреть в одном и том же направлении.

Например, если вы хотите повернуть объект на 90 градусов вокруг оси Y, используйте:

Matrix.rotateM(mModelMatrix, 0, 90, 0.0f, 1.0f, 0.0f);

Также помните, что все матричные операции после Matrix.setIdentityM будут выполняться в обратном порядке, т.е. если вы сначала повернете, а затем переведете, как вы делаете первое действие в своем коде, вы сначала переместите свой объект из его исходного положения, а затем поверните вокруг источника, заставляя ваш объект вращаться вокруг первого источника вместо центра вашего объекта.

Затем, скажем, вы переместили камеру на 100 единиц влево и, глядя в направлении -Z, используйте:

Matrix.setLookAtM(mViewMatrix, offset, -100.0f+camX, camY, camZ, -100.0f+camX, camY, -1.0f+camZ, upX, upY, upZ);
person Mattias F    schedule 08.01.2014
comment
Спасибо за Ваш ответ. Я уже использовал функции, которые вы рекомендовали для вращения. Мой класс MatrixHelper вращает X, Y и Z (сначала переводите в центр, затем вращение, а затем перевод обратно в исходное положение -> так что модель вращается вокруг собственного центра). Моя проблема в том, что перевод неверен, когда модель вращается. Когда я поворачиваю модель на 90°, оси перевода меняются местами. - person Frame91; 08.01.2014

Если вы зададите базовые векторы камеры C-центр, L-смотреть, U-вверх так, что C — это центр камеры, L — нормализованный вектор от центра к точке, на которую вы смотрите, а U — нормализован вверх. Теперь вы можете вращать вектор L влево и вправо, поворачивая его вокруг U на любой угол.

Что касается перемещения влево и вправо, вам придется реконструировать боковой вектор S: векторное произведение между L и U (S=LxU). Теперь все, что вам нужно сделать, это переместить центр: C = C+S*inputFactor.

Чтобы восстановить lookAt векторов:

eye = C
center = C+L
up = U

Просто в качестве примечания: если вам также нужно смотреть вверх и вниз (вращать), вам нужно повернуть L и U вокруг S, чтобы наклонить влево и вправо, вам нужно повернуть U вокруг L. Для перемещения вперед или назад C = C+L*inputFactor и для перемещения вверх и вниз C = C+U*inputFactor.

Это должно решить все логические движения и повороты камеры.

person Matic Oblak    schedule 08.01.2014
comment
Большое спасибо за ответ! К сожалению, я немного запутался. Мне не нужно переводить/вращать саму модель? Кажется очень логичным изменить глаз и направление движения камеры. Но что вы подразумеваете под входным фактором? И как я могу комбинировать каждое движение/вращение? В основном мне нужно вращать по осям x, y, z и перемещать камеру по осям x, y, z. - Кроме того: что вы подразумеваете под взглядом на вектор? Это, я думаю, мой глазВектор? Большое спасибо еще раз! - person Frame91; 08.01.2014
comment
Я обновил свой ответ. Пожалуйста, посмотрите! Я бы добавил награду к этому вопросу, если он решит мою проблему. - person Frame91; 08.01.2014
comment
look-at-vectors — это все 3 из них (глаз, центр, вверх). Вам не нужно перемещать саму модель, но если вы это делаете и хотите сделать это в зависимости от камеры, вы должны снова использовать параметры камеры: Используйте S-вектор для перемещения влево и вправо. Если вы вращаете и перемещаете объект, вам нужно сначала перевести его, чтобы сохранить эти параметры (угол и перемещение). input-factor — это длина перевода в данном случае, обычно какой-то параметр, который вы получаете от пользователя (например, длина свайпа). Обратите внимание, что оно также может быть отрицательным. - person Matic Oblak; 08.01.2014