3D векторы — выравнивание системы координат вектора по нормали

#math #vector #3d #transform #coordinate-transformation

#математика #вектор #3D #преобразование #преобразование координат

Вопрос:

Я пытаюсь выровнять систему координат по нормальному направлению, таким образом, я ввожу только X, Y, Z и направление нормали и Y-вращение координаты, чтобы получить новые X, Y, Z из новой выровненной системы координат.

Функция, которая будет выглядеть следующим образом:

 func transform(coordinate: XYZposition, to: XYZnormal, withY:Radians){
    //missing mathematic
    //rotate coordinates        
    return XYZpositionOfNewSystem
}
 

Вот изображение, представляющее визуализацию того, чего я хочу достичь. Ось — это представление системы координат. Первая система координат — исходная, а 2 справа — повернутые.

введите описание изображения здесь

Почему 2 примера справа?

Как вы можете видеть, при выравнивании по нормали к грани остается одна свободная ось. Ось Y может принимать любое вращение и при этом оставаться выровненной по грани.

Вот почему функции необходимо задать вращение, чтобы она также применяла это вращение по оси Y.

Я нашел некоторые математические расчеты на сайте Mathematics Stack Exchange (поверните систему координат 3D так, чтобы ось Z была параллельна заданному вектору), но я потерялся, если это то, что мне нужно, и я немного запутался в применяемой математике и используемых символах.

Ответ №1:

Вот ответ, который вы процитировали, реализованный с использованием python и numpy и обмен ролями y и z в соответствии с вашими потребностями:

 from numpy import array, dot, cross, arccos, sin, cos
from scipy.spatial.distance import cosine

def angle(u,v):
    return arccos(1 - cosine(u,v))

# assumes all four vectors are normalized
def get_transform_matrix(orig_system, n):
    j = orig_system[:,1]
    b = cross(j, n)
    theta = angle(j, n)
    q0 = cos(theta/2)
    q1,q2,q3 = sin(theta/2) * b
    Q = array([
         [q0**2   q1**2 - q2**2 - q3**2, 2*(q1*q3 q0*q2), 2*(q1*q2-q0*q3)],
         [2*(q3*q1-q0*q2), q0**2 - q1**2 - q2**2   q3**2, 2*(q3*q2 q0*q1)],
         [2*(q2*q1 q0*q3), 2*(q2*q3-q0*q1), q0**2 - q1**2   q2**2 - q3**2]
    ])
    return Q
 

Чтобы преобразовать вектор p в новую систему, просто вычислите Q @ p :

 from numpy import eye, sqrt

orig_system = eye(3)
n = array([0,1,1]) / sqrt(2)

Q = get_transform_matrix(orig_system, n)

print(Q)
# [[ 0.9267767   0.          0.        ]
#  [ 0.          0.78033009  0.5       ]
#  [ 0.         -0.5         0.78033009]]

p = array([10, 20, 30])

print(Q @ p)
# [ 9.26776695 30.60660172 13.40990258]
 

Пожалуйста, протестируйте это тщательно!! Я тестировал с несколькими разными векторами, и все выглядело нормально, но я не могу гарантировать, что ошибок нет.

Комментарии:

1. Протестируем это прямо сейчас! Позволит вам, если это сработает, сначала мне нужно будет перевести в Metal, я использую его в шейдере для вычисления UV-координат.