3d координата от точки и углов - PullRequest
0 голосов
/ 17 ноября 2011

Я работаю над простым миром OpenGL - и до сих пор у меня есть случайная куча кубов, и довольно интересно переходить масштабирование. Однако я готов двигаться дальше. Я хотел бы бросить блоки перед моей камерой, но у меня проблемы с углами 3D. Я привык к 2d вещам, где найти конечную точку, мы просто делаем что-то вроде:

endy = y + (sin(theta)*power);
endx = x + (cos(theta)*power);

Однако, когда я добавляю третье измерение, я не уверен, что делать! Мне кажется, что сила плоскости второго измерения будет определяться силой cos (theta) * оси z, но я не уверен. Если это правильно, мне кажется, я бы сделал что-то вроде этого:

endz = z + (sin(xtheta)*power);

power2 = cos(xtheta) * power;

endx = x + (cos(ytheta) * power2);
endy = y + (sin(ytheta) * power2);

(где х тэта - тэта вверх / вниз, а у = левый / правый тета)

Я даже близко к правильному пути? Как найти конечную точку с учетом текущей точки и двух углов?

Ответы [ 2 ]

2 голосов
/ 17 ноября 2011

Работа с углами Эйлера не очень хорошо работает в 3D-средах, есть несколько проблем и случаев, когда они просто не работают. И вам даже не нужно их использовать.

То, что вы должны сделать, это использовать тот факт, что матрицы преобразования - это не что иное, как основы системы координат, записанные в понятной форме. Итак, у вас есть матрица вида модели MV. Это состоит из преобразования пространства модели, за которым следует преобразование вида (основные матрицы столбцов умножаются справа налево):

MV = V * M

Итак, мы хотим знать, каким образом «камера» находится внутри мира. Это дается вам с помощью матрицы обратного просмотра V^-1. Конечно, вы можете инвертировать матрицу вида, используя метод Гаусса-Джордана, но большую часть времени ваша матрица вида будет состоять из матрицы вращения 3 × 3 с добавленным столбцом вектора переноса P.

R P
0 1

Напомним, что

(M * N)^-1 = N^-1 * M^-1

, а также

(M * N)^T = M^T * N^T

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

R^-1 = R^T

аккуратный! Это позволяет нам найти обратную матрицу представления следующим образом (я предлагаю вам попытаться доказать это в качестве примера):

V = / R P \
    \ 0 1 /

V^-1 = / R^T -P \
       \   0  1 /

Так как это поможет нам разместить новый объект на сцене на расстоянии от камеры? Что ж, V - это преобразование из мирового пространства в пространство камеры, поэтому V ^ -1 превращается из камеры в мировое пространство. Итак, учитывая точку в пространстве камеры, вы можете преобразовать ее обратно в мировое пространство. Скажем, вы хотите разместить что-то в центре вида на расстоянии d. В пространстве камеры это будет точка (0, 0, -d, 1). Умножьте это на V ^ -1:

 V^-1 * (0, 0, -d, 1) = (R^T)_z * d - P

Что именно то, что вы хотите. В вашей OpenGL-программе у вас где-то есть матрица представления V, возможно, еще не названная должным образом, но в любом случае она есть. Допустим, вы используете старый OpenGL-1 и GLU's gluLookAt:

void display(void)
{
    /* setup viewport, clear, set projection, etc. */

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(...);
    /* the modelview matrix now holds the View transform */

На данный момент мы можем извлечь матрицу вида модели

    GLfloat view[16];
    glGetFloatv(GL_MODELVIEW_MATRIX, view);

Теперь view в главном порядке столбца. Если бы мы использовали его напрямую, мы могли бы напрямую обратиться к столбцам. Но помните, что transpose является обратным вращению , поэтому мы на самом деле хотим вектор 3-й строки. Итак, давайте предположим, что вы сохраняете view, так что в вашем обработчике событий (внешний дисплей) вы можете сделать следующее:

GLfloat z_row[3];
z_row[0] = view[2];
z_row[1] = view[6];
z_row[2] = view[10];

И нам нужна позиция

GLfloat * const p_column = &view[12];

Теперь мы можем вычислить положение новых объектов на расстоянии d:

GLfloat new_object_pos[3] = {
    z_row[0]*d - p_column[0],
    z_row[1]*d - p_column[1],
    z_row[2]*d - p_column[2],
};

Вот, пожалуйста. Как видите, нигде вам не приходилось работать с углами или тригонометрией, это просто прямая линейная алгебра.

0 голосов
/ 17 ноября 2011

Ну, я был близок, после некоторого тестирования я нашел правильную формулу для моей реализации, она выглядит так:

endy = cam.get_pos().y - (sin(toRad(180-cam.get_rot().x))*power1);
power2 = cos(toRad(180-cam.get_rot().x))*power1;

endx = cam.get_pos().x - (sin(toRad(180-cam.get_rot().y))*power2);
endz = cam.get_pos().z - (cos(toRad(180-cam.get_rot().y))*power2);

Это берет положение моей камеры и углы поворота и получает соответствующие точки. Работает как шарм =]

...