Как выровнять лицо по положению в мировом пространстве?

У меня есть математическая проблема. Допустим, у меня есть грань (с 3 или 4 вершинами) в некоторой мировой позиции. Я хочу перевести/повернуть сетку так, чтобы лицо было «лицом» вверх и располагалось по центру (0, y, 0). Какая формула(ы) необходима для этого?

Лицо в исходном положенииПосмотрите в нужное положение

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

РЕДАКТИРОВАТЬ: я также должен отметить, что эти векторы являются частью сетки, которую я хочу вращать (начало в (0,0,0)) до тех пор, пока v1 не окажется в позиции v2.

Вот псевдокод, который не работает:

v1 = vector(0,10,0)
v2 = vector(0,-10,0)

v1 = normalize(v1)
v2 = normalize(v2)

cross = normalize( v2.cross(v1) )  // (0,0,0)
angle = acos( v2.dot(v1) )  // 180

quat  = quaternion(cross,angle) // {w:1,x:0,y:0,z:0}

Я бы подумал, что кватернион будет выглядеть примерно так: {w:?,x:3.14159,y:0,z:0} или {w:?,x:0,y:0,z:3.14159}


person Hobbes    schedule 27.04.2013    source источник
comment
Вы просто пытаетесь выровнять по оси? Если вам все равно, сохранится ли он точно такого же размера, просто усредните вершины по оси y и установите значение y для вершин на это значение. Затем очистите x и z до 0.   -  person Captain Skyhawk    schedule 27.04.2013
comment
Я хочу, чтобы вершина в позиции a перемещалась в позицию b путем вращения/перемещения сетки.   -  person Hobbes    schedule 29.04.2013
comment
Точно, я уверен, что приведенная ниже математика верна, но превратить это в функцию... о боже.   -  person Hobbes    schedule 30.04.2013
comment
Кватернион представлен как ‹w,x,y,z›, где ‹w› представляет собой угол (в данном случае PI), а ‹x,y,z› — это ось, вокруг которой вы вращаетесь. Ожидаемый кватернион выглядит примерно так: ‹PI,?,?,?›, однако это будет не совсем так, потому что он не нормализован.   -  person Suedocode    schedule 30.04.2013
comment
Ах было интересно, что w было хе-хе, спасибо.   -  person Hobbes    schedule 30.04.2013


Ответы (1)


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

Матрица вращения: если вы знаете, на какой угол Эйлера вы хотите повернуться, то Матрица вращения — это то, что нужно. Чтобы сформировать матрицу вращения, см. раздел «Основные вращения» по ссылке. Вместо того, чтобы знать, что такое «вверх», вам нужно знать, насколько сильно вы хотите повернуть свой объект. В этом случае (судя по предоставленным фотографиям) вы хотите повернуть на 90 градусов вокруг глобальной оси x (если вы хотите сделать это вокруг локальной оси, вы должны знать текущую ориентацию объекта. Я могу уточнить в редактировании, если вам нужны локальные повороты). Ваша глобальная матрица ротации будет выглядеть так:

[1  0  0]
[0  0  1]
[0 -1  0]

Я рассчитал это, используя матрицу Rx(90) в разделе «Основные вращения». Теперь сформируйте свои 3D-точки в векторах-столбцах. Допустим, одна точка находится в (0,0,1). Эта точка находится прямо там, где должен быть нос, поэтому мы ожидаем, что преобразованная точка будет (0,1,0). Просто умножьте матрицу вращения, чтобы получить результат:

[1  0  0] [0] [0]
[0  0  1]*[0]=[1]
[0 -1  0] [1] [0]

Обратите внимание, что в этом случае преобразование довольно тривиально; мы просто сдвигаем координаты (x остается прежним, y инвертируется, z и y меняются местами). Вы можете одновременно преобразовать большой набор точек, соединив по горизонтали все начальные координаты, чтобы сформировать матрицу 3xN, а затем умножив матрицу поворота влево. Например, преобразуем точки { (0,0,1), (0,1,0), (1,0,1), (0,0,-1)}:

[1  0  0] [0  0  1  0] [0  0  1  0]
[0  0  1]*[0  1  0  0]=[1  0  1  0]
[0 -1  0] [1  0  1 -1] [0 -1  0  1]

Напоминаем, что это преобразование вращается вокруг глобального начала координат (как показано точкой (1,0,1)). Вам нужно будет вычесть центроид ваших координат, повернуть, а затем добавить окончательные координаты перевода.

Кватернион: здесь я могу дать руководство, но это часто называют нотацией «ось-угол»; вы можете использовать его для создания матрицы вращения, которая будет поворачивать ваши точки вокруг произвольной единичной оси на заданный угол. Вот отличное руководство по этому вопросу. Дайте мне знать, если я должен уточнить в редактировании.

РЕДАКТИРОВАТЬ: в ответ на добавленный псевдокод

Если векторное произведение равно 0, то прямые параллельны. Ось вращения может быть ЛЮБЫМ вектором, перпендикулярным ЛЮБОМ входу (что делает его перпендикулярным обоим по определению). Вектор p определяется как перпендикулярный, если dot(v,p)==0 или vx*p.x+vy*p.y+vz*pz==0 и length(p)>0, поэтому мы можем произвольно выбрать любое решение, удовлетворяющее этим уравнениям.

v1 = vector(0,10,0)
v2 = vector(0,-10,0)

//Not necessary, since you will normalize the cross product result
//v1 = normalize(v1)
//v2 = normalize(v2)

cross = v2.cross(v1)  // (0,0,0) and possible divide by 0 if normalized here
if(length(cross)==0){ //either "==0" or "<thresh" where thresh is some very small number
   if(v.z!=0)
        cross = vector(1,1,-(v1.x+v1.y)/v1.z);
   else if(v.y!=0) //is z==0?  well here's an identical solution as long as y isn't 0
        cross = vector(1,-(v1.x+v1.z)/v.y,1);
   else //by this point, v1.x must be the only nonzero remaining point, otherwise it's a null vector
        cross = vector(-(v1.y+v1.z)/v.x,1,1);
}
cross=normalize(cross);
angle = acos( normalize(v2.dot(v1)) )  // 180

quat  = quaternion(cross,angle)

Я не знаком с кодом Python, поэтому добавил эквивалент C++. Если бы кто-то мог отредактировать этот пост, чтобы исправить его, это было бы превосходно.

Редактировать: я не видел вашего комментария об acos, извините за это. Соответственно изменил код.

person Suedocode    schedule 27.04.2013
comment
Я действительно хотел бы понять это больше. Я все еще борюсь с этим. Я делаю это на языке программирования (python), и мне трудно преобразовать то, что вы опубликовали, в функцию. Я наткнулся на угол = acos (точка (v1, v2)). Это, кажется, работает несколько раз. Я получаю правильный угол из (0,-1,0) и (0,1,0) => 180, но когда я делаю (0,-2,0) и (0,2,0), функция acos ломается поскольку в этом случае точка (v1, v2) больше не равна 0 - 1. Черт, я так запутался. Я должен был сделать отказ от ответственности, что я совсем не силен в этой математике =[ - person Hobbes; 30.04.2013
comment
Мне удалось заставить функцию acos(dot(v1,v2)) прекратить поломку, предварительно нормализовав векторы. Но по какой-то причине я не понимаю, что кватернион между v1 (0,1,0) и v2 (0,-1,0) равен {w:1, x:0, y:0, z:0}, хотя arcos(dot(v1,v2)) возвращает PI. Я бы подумал, что вращение по оси x или z будет PI. - person Hobbes; 30.04.2013
comment
Если вы находите ось, по которой нужно вращаться с помощью перекрестного произведения, вы должны убедиться, что ваше перекрестное произведение не приводит к (0,0,0) (в приведенном вами примере это так!). Кроме того, дважды проверьте, чтобы убедиться, что вы опускаете угол на 2 при вычислении кватерниона (в данном случае PI/2). Если это не правильное исправление, попробуйте опубликовать код в редактировании OP. - person Suedocode; 30.04.2013
comment
Верно! Перекрестное произведение в этой ситуации равно (0,0,0), что меня смущает. - person Hobbes; 30.04.2013
comment
Отредактировал ответ, чтобы уловить случай с параллельным вектором, но он не проверен, поэтому может быть не совсем правильным, лол. - person Suedocode; 30.04.2013
comment
Это совершенно произвольно, так что да, если вы хотите, чтобы это было ^.^ - person Suedocode; 30.04.2013