Вручную координаты проекта, аналогичные gluLookAt в python - PullRequest
0 голосов
/ 25 августа 2018

Я пытаюсь реализовать матрицу просмотра и проекцию, аналогично gluLookAt, чтобы получить позицию просмотра каждой трехмерной координаты.Я реализовал что-то, что кажется близким к работе, но полностью изменено.Например - следующий код получает правильную позицию (Когда я фактически не изменяю координаты. Но если я изменю вектор вверх, чтобы указывать на X вместо Y, я получу обратные координаты.

import numpy as np

def normalize_vector(vector):
    return vector / (np.linalg.norm(vector))

def get_lookat_matrix(position_vector, front_vector, up_vector):
    m1 = np.zeros([4, 4], dtype=np.float32)
    m2 = np.zeros([4, 4], dtype=np.float32)

    z = normalize_vector(-front_vector)
    x = normalize_vector(np.cross(up_vector, z))
    y = np.cross(z, x)

    m1[:3, 0] = x
    m1[:3, 1] = y
    m1[:3, 2] = z
    m1[3, 3] = 1.0

    m2[0, 0] = m2[1, 1] = m2[2, 2] = 1.0
    m2[:3, 3] = -position_vector
    m2[3, 3] = 1.0

    return np.matmul(m1, m2)

def get_projection_matrix(near, far):
    aspect = 1.0
    fov = 1.0  # 90 Degrees
    m = np.zeros([4, 4], dtype=np.float32)

    m[0, 0] = fov/aspect
    m[1, 1] = fov
    m[2, 2] = (-far)/(far-near)
    m[2, 3] = (-near*far)/(far-near)
    m[3, 2] = -1.0
    return m

position_vector = np.array([0, 0, 0], dtype=np.float32)
front_vector = np.array([0, 0, -1], dtype=np.float32)
up_vector = np.array([0, 1, 0], dtype=np.float32)

viewing_matrix = get_lookat_matrix(position_vector=position_vector, front_vector=front_vector, up_vector=up_vector)
print("viewing_matrix\n", viewing_matrix, "\n\n")
projection_matrix = get_projection_matrix(near=0.1, far=100.0)
point = np.array([1, 0, -10, 1], dtype=np.float32)

projected_point = projection_matrix.dot(viewing_matrix.dot(point))
# Normalize
projected_point /= projected_point[3]
print(projected_point)

И это происходит со многими изменениями координат. Я не уверен, где я ошибаюсь.

Ответы [ 2 ]

0 голосов
/ 25 августа 2018

Есть небольшое изменение, которое вы должны сделать:

m[2, 2] = -(far+near)/(far-near)       //instead of m[2, 2] = (-far)/(far-near)
m[2, 3] = (-2.0*near*far)/(far-near)   //instead of m[2, 3] = (-near*far)/(far-near)

Самое важное - это порядок строк / столбцов ваших матриц.

Как указывал @ Rabbid76, предпочтительным является порядок столбцов мэра.,GLSL предоставляет функцию для транспонирования матрицы.Вы также можете указать транспонировать матрицу, когда она передается в графический процессор с помощью команд семейства glUniformMatrix.

Давайте посмотрим, как работает матрица порядка мэров строк, как это делает ваш код.

Цельтеперь с ЦП получить: finalPoint = matrixMultiply(C, P) с C объединенной матрицей и P координаты точки.matrixMultiply - любая функция, которую вы используете для умножения матриц.Помните, что порядок имеет значение, A · B не совпадает с B · A

Поскольку C является матрицей 4x4, а P равно 1x4, C · P невозможно, это должно быть P · C,Обратите внимание, что с порядком столбцов P равен 4x1, а затем C · P - правильная операция.

Давайте назовем L матрицу просмотра (собственное имя матрица представления ).Он состоит из матрицы ориентации O и матрицы перевода T.При этом порядок столбцов равен L= O·T.

. Свойство транспонированной матрицы равно (A · B) t = B t · A t

Итак, с порядком строк вы получаете O · T = O c t · T c t = (T c · O c ) t , где c - порядок столбцов.Привет!что мы хотим (O c · T c ) t Обратите внимание на изменение порядка умножения?

Итак, если вы работаете сМатрицы порядка строк мэра, порядок их умножения меняется местами.
Комбинированная матрица вида и проекции также должна поменяться местами.

Заменить таким образом:

return np.matmul(m2, m1)   //was return np.matmul(m1, m2)

и

//was projected_point = projection_matrix.dot(viewing_matrix.dot(point))
projected_point = point.dot(viewing_matrix.dot(projection_matrix))

Несмотря на все вышесказанное, рекомендую работатьс приказом мэра колонны.Это лучше для OpenGL.И вы лучше поймете любую математику и учебники, которые найдете в OpenGL.

0 голосов
/ 25 августа 2018

gluLookAt определяет матрицу преобразования просмотра 4 * 4 для использования OpenGL.

"Математическая" матрица 4 * 4 выглядит следующим образом:

  c0  c1  c2  c3            c0  c1  c2  c3
[ Xx  Yx  Zx  Tx ]        [  0   4   8  12 ]     
[ Xy  Yy  Zy  Ty ]        [  1   5   9  13 ]     
[ Xz  Yz  Zz  Tz ]        [  2   6  10  14 ]     
[  0   0   0   1 ]        [  3   7  11  15 ] 

Нообраз памяти матрицы OpenGL 4 * 4 выглядит следующим образом:

[ Xx, Xy, Xz, 0, Yx, Yy, Yz, 0, Zx, Zy, Zz, 0, Tx, Ty, Tz, 1 ]

См. Язык затенения OpenGL 4.6, 5.4.2 Векторные и матричные конструкторы, стр. 101 и OpenGL ES Shading Language 3.20 Спецификация, 5.4.2 Векторные и матричные конструкторы, стр. 100 :

Чтобы инициализировать матрицу путем указания векторов или скаляров, компоненты назначаютсяматричные элементы в главном порядке столбцов .

mat4(float, float, float, float,  // first column
     float, float, float, float,  // second column
     float, float, float, float,  // third column
     float, float, float, float); // fourth column

Обратите внимание, по сравнению с математической матрицей, где столбцы пишутся сверху вниз, что выглядит естественно, наинициализация матрицы OpenGL, столбцы пишутся слева направо.Это привело к тому, что компоненты x, y, z оси или перевода находятся в прямой последовательности в памяти.Это большое преимущество при доступе к векторам оси или вектору трансляции матрицы.См. Также Тип данных (GLSL) - конструкторы матриц .

Это означает, что вам нужно «поменять» столбцы и строки (транспонировать) матрицы:

def get_lookat_matrix(position_vector, front_vector, up_vector):
    m1 = np.zeros([4, 4], dtype=np.float32)
    m2 = np.zeros([4, 4], dtype=np.float32)

    z = normalize_vector(-front_vector)
    x = normalize_vector(np.cross(up_vector, z))
    y = np.cross(z, x)

    m1[0, :3] = x
    m1[1, :3] = y
    m1[2, :3] = z
    m1[3, 3] = 1.0

    m2[0, 0] = m2[1, 1] = m2[2, 2] = 1.0
    m2[3, :3] = -position_vector
    m2[3, 3] = 1.0

    return np.matmul(m1, m2)

def get_projection_matrix(near, far):
    aspect = 1.0
    fov = 1.0  # 90 Degrees
    m = np.zeros([4, 4], dtype=np.float32)

    m[0, 0] = fov/aspect
    m[1, 1] = fov
    m[2, 2] = (-far+near)/(far-near)
    m[3, 2] = (-2.0*near*far)/(far-near)
    m[2, 3] = -1.0
    return m
...