Вращение и направление вектора в трехмерном пространстве - обратный порядок

1

У меня два вектора в 3D-пространстве, S (Пуск) и T (Target), и я хочу найти матрицу вращения (RM), которая допускает такое преобразование.

Я знаю, что, вычисляя поперечное произведение S × T я получаю ось вращения. Угол между S и T задается tan⁻¹(||S × T||, S·T), где S·T - точечное произведение между S и T.

Это дает мне вектор вращения rotvec = [S x T; angle] rotvec = [S x T; angle] (поперечное произведение нормировано). Затем, используя функцию vrrotvec2mat (в MATLAB) или transforms3d.axangles.axangle2mat (в Python), я могу получить матрицу вращения, соответствующую преобразованию из S в T

В моем приложении T задается точечным произведением RM·D, где D - вектор 3x1. Моя цель - найти RM. Я знаю S, T и D, но мне трудно понять математику за этим.

На практике я хочу найти RM между S и T', где T' - целевой вектор до D (направление).

Еще немного контекста: я хочу получить углы сустава тела из трехмерных точек в системе координат камеры.

  • 0
    Существует бесчисленное множество легко доступных примеров кода для этого в Интернете; даже сами формулы легко конвертировать в код без необходимости понимать, как они работают.
  • 0
    @meowgoesthedog не могли бы вы указать мне пример? Я изо всех сил пытался найти это в Интернете ... Возможно, я не использую правильные ключевые слова.
Показать ещё 4 комментария
Теги:
opengl
geometry
rotational-matrices

1 ответ

2
Лучший ответ

Для выполнения этой работы вам также нужен центр вращения (точка, которая остается неизменной после вращения). Теперь нам нужны две матрицы преобразования, представляющие систему координат до и одну после преобразования.

Чтобы построить вашу матрицу 3D-преобразования, вам понадобятся 3 перпендикулярных базисных вектора и исходная позиция:

теперь ось вращения будет одним из базовых векторов, и мы можем использовать S,T как вторую, так что третье мы можем вычислить с помощью поперечного произведения, а начало координат будет центром вращения:

X = cross(S,T);                      // rotation axis
X /= |X|;                            // unit vector
Y = S;                               // start vector
Y /= |Y|;                            // unit vector
Z = cross(X,Y);                      // Z perpendicular to X,Y
Z /= |Z|;                            // unit vector
O = center_of_rotation;

Изображение 174551

Так постройте матрицу преобразования 4x4 A из них. И сделайте то же самое для B но используйте T вместо S Теперь мы хотим вычислить разностное преобразование, так что если p=(x,y,z,1) - любая точка преобразования, то:

p' = Inverse(A)*p 
p' = B*p'         

Итак, ваша матрица преобразования M:

M = Inverse(A)*B;

Помните, что это будет работать со стандартными соглашениями OpenGL, если вы используете разные (порядок умножения, ориентацию матрицы и т.д.), Уравнение может измениться.

Вы также можете использовать полную псевдо-обратную матрицу для более эффективного и точного вычисления инверсии Inverse(A).

Как вы можете видеть, вам не нужны никакие гониометрия или угол, чтобы сделать это (векторная математика хороша в этом)

Пример [Edit1] C++

Его использование VCL (AnsiString и mm_log, которые вы можете игнорировать) и моя векторная математика (используемые функции находятся в первой ссылке).

//---------------------------------------------------------------------------
AnsiString matrix_prn(double *a)
    {
    int i; AnsiString s;
    for (s ="(",i=0;i<16;i+=4) { if (a[i]>=0.0) s+=" "; s+=AnsiString().sprintf("%2.3lf,",a[i]); } s[s.Length()]=')'; s+="\r\n";
    for (s+="(",i=1;i<16;i+=4) { if (a[i]>=0.0) s+=" "; s+=AnsiString().sprintf("%2.3lf,",a[i]); } s[s.Length()]=')'; s+="\r\n";
    for (s+="(",i=2;i<16;i+=4) { if (a[i]>=0.0) s+=" "; s+=AnsiString().sprintf("%2.3lf,",a[i]); } s[s.Length()]=')'; s+="\r\n";
    for (s+="(",i=3;i<16;i+=4) { if (a[i]>=0.0) s+=" "; s+=AnsiString().sprintf("%2.3lf,",a[i]); } s[s.Length()]=')';
    return s;
    }
//---------------------------------------------------------------------------
AnsiString vector_prn(double *a)
    {
    int i; AnsiString s;
    for (s ="(",i=0;i<3;i++) { if (a[i]>=0.0) s+=" "; s+=AnsiString().sprintf("%2.3lf,",a[i]); } s[s.Length()]=')';
    return s;
    }
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner)
    {
    int i;
    double O[3]={0.00, 0.00,0.00};  // center ofrotation
    double S[3]={4.10,-9.44,0.54};  // start vector
    double T[3]={1.40,-9.08,4.10};  // end vector
    double A[16],_A[16],B[16],M[16],X[3],Y[3],Z[3];

    // A
    vector_mul(X,S,T);  // rotation axis
    vector_one(X,X);    // unit vector
    vector_one(Y,S);    // unit start vector
    vector_mul(Z,X,Y);  // Z perpendicular to X,Y
    vector_one(Z,Z);    // unit vector
    for (i=0;i<3;i++)
        {
        A[ 0+i]=X[i];
        A[ 4+i]=Y[i];
        A[ 8+i]=Z[i];
        A[12+i]=O[i];
        A[(i<<2)+3]=0.0;
        } A[15]=1.0;
    // B
    vector_one(Y,T);    // unit end vector
    vector_mul(Z,X,Y);  // Z perpendicular to X,Y
    vector_one(Z,Z);    // unit vector
    for (i=0;i<3;i++)
        {
        B[ 0+i]=X[i];
        B[ 4+i]=Y[i];
        B[ 8+i]=Z[i];
        B[12+i]=O[i];
        B[(i<<2)+3]=0.0;
        } B[15]=1.0;
    // M = B*Inverse(A)
    matrix_inv(_A,A);
    matrix_mul(M,_A,B);

    mm_log->Lines->Add("A");
    mm_log->Lines->Add(matrix_prn(A));
    mm_log->Lines->Add("B");
    mm_log->Lines->Add(matrix_prn(B));
    mm_log->Lines->Add("M");
    mm_log->Lines->Add(matrix_prn(M));
    mm_log->Lines->Add("");

    vector_one(S,S);    // unit start vector
    vector_one(T,T);    // unit end vector
    mm_log->Lines->Add("S = "+vector_prn(S));
    matrix_mul_vector(X,M,S);
    mm_log->Lines->Add("X = "+vector_prn(X));
    mm_log->Lines->Add("T = "+vector_prn(T));
    }
//-------------------------------------------------------------------------

Вот результат:

A
(-0.760, 0.398,-0.514, 0.000)
(-0.361,-0.916,-0.175, 0.000)
(-0.540, 0.052, 0.840, 0.000)
( 0.000, 0.000, 0.000, 1.000)
B
(-0.760, 0.139,-0.635, 0.000)
(-0.361,-0.903, 0.235, 0.000)
(-0.540, 0.408, 0.736, 0.000)
( 0.000, 0.000, 0.000, 1.000)
M
( 0.959, 0.258,-0.115, 0.000)
(-0.205, 0.916, 0.345, 0.000)
( 0.194,-0.307, 0.932, 0.000)
( 0.000, 0.000, 0.000, 1.000)

S = ( 0.398,-0.916, 0.052)
X = ( 0.139,-0.903, 0.408) // X = M * S
T = ( 0.139,-0.903, 0.408)

Как вы можете видеть, если я преобразую единицу S на M я получил единицу T вектора. PS. my matrix_mul_vector и vector_mul предполагает w=1.0 но как O=(0.0,0.0,0.0) векторы и точки одинаковы.

  • 0
    Большое спасибо за указание на матрицы однородного преобразования 4x4 и ваше ясное объяснение. Из вашего объяснения, если p равно моему стартовому вектору (S), то p 'должен быть моим целевым вектором (T), верно?
  • 0
    @jcampos да ... если p=(x,y,z,0) чем p,p' обрабатываются как векторы, и если p=(x,y,z,1) они обрабатываются как точки ... ,
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню