Как да подравним лице към позиция в световното пространство?

Имам математически проблем. Да кажем, че имам лице (с 3 или 4 върха) на някаква световна позиция. Искам да преместя/завъртя мрежата, така че лицето да е "обърнато" нагоре и да е центрирано (0,y,0). Каква е формулата(ите), необходима(и) за осъществяване на това?

Лице в първоначална позицияЛице в желаната позиция

Мога да направя това с графичен интерфейс (този пример беше просто x ротация от appx -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, или v.x*p.x+v.y*p.y+v.z*p.z==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) и ми е трудно да конвертирам това, което сте публикували във функция. Случайно попаднах на angle = acos(dot(v1,v2)). Това изглежда работи понякога. Получавам правилния ъгъл от (0,-1,0) и (0,1,0) =› 180, но когато направя (0,-2,0) и (0,2,0), функцията acos прекъсва тъй като в този случай dot(v1,v2) вече не е 0 - 1. Eck, толкова съм объркан. Трябваше да направя отказ от отговорност, че изобщо не съм добър в този тип математика =[ - 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