Форум программистов, компьютерный форум CyberForum.ru

Объединение view и projection матриц - C++

Восстановить пароль Регистрация
 
 
Pro100Tom
 Аватар для Pro100Tom
69 / 28 / 7
Регистрация: 29.10.2012
Сообщений: 326
19.09.2016, 11:45     Объединение view и projection матриц #1
Здравствуйте!

Извиняюсь заранее, если "не туда" пишу, тут много разделов, выбирал между "математикой" и "играми".

Если издалека, то чтобы обработать вертексы, мы их пропускаем через transformation матрицу. Она состоит из трёх: translation, rotation и scaling. Тут есть два варианта перемножения. Либо перемножить матрицы в одну, а потом пропускать вертексы через неё либо пропустить вертексы сначала через translation матрицу, потом то, что получится через rotation и потом результат пропустить ещё и через scaling. Я провёл несколько подсчётов и убедился, что первый вариант быстрее (если в объекте больше четырёх вертексов, что почти всегда и бывает).

Дальше мы пропускаем вертексы через view и projection матрицы. И тут, я тоже подумал: "окей, вместо того чтобы перемножать вертексы на view матрицу, и потом снова новые вертексы перемножать на projection матрицу, лучше я их объединю в viewProjection матрицу и пропущу вертексы через неё".
Здесь и появляется проблема. Моя projection матрица является перспективной. А view матрица имеет перемещение по оси z (0.0f, 0.0f, 15.0f), (view матрицу мы инверсируем, в итоге получаем -15.0f). И дело в том, что я получаю разные результаты: если я сначала перемножаю вертексы на view матрицу, а потом получившиеся перемножаю на projection матрицу, то всё работает. А если я сначала перемножаю эти две матрицы и перемножаю вертексы на viewProjection матрицу, то получается... да вообще ничего не получается. Там компонента z и w совсем другая становится.

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

Я пока код решил не скидывать, так как пока вопрос теоретический. Но, если нужен будет, то всё выложу и подробно расскажу.

Заранее спасибо.
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Nick Alte
Эксперт С++
1594 / 986 / 117
Регистрация: 27.09.2009
Сообщений: 1,901
Завершенные тесты: 1
21.09.2016, 21:22     Объединение view и projection матриц #21
Цитата Сообщение от Pro100Tom Посмотреть сообщение
Надо projection * view вместо view * projection!!!
Если матрицы считаются правильно, то надо как раз view * projection.
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Pro100Tom
 Аватар для Pro100Tom
69 / 28 / 7
Регистрация: 29.10.2012
Сообщений: 326
22.09.2016, 16:12  [ТС]     Объединение view и projection матриц #22
Цитата Сообщение от Nick Alte Посмотреть сообщение
Если матрицы считаются правильно, то надо как раз view * projection.
Вот и я так думал сначала. Не подскажете, где у меня ошибка?
Nick Alte
Эксперт С++
1594 / 986 / 117
Регистрация: 27.09.2009
Сообщений: 1,901
Завершенные тесты: 1
23.09.2016, 17:23     Объединение view и projection матриц #23
Возможно, путаница в ориентации матриц при их формировании (row-wise или column-wise) и/или порядке умножения на вектор? Попробуйте прогнать простые тестовые матрицы и векторы через ваши процедуры и посмотрите, что будет получаться.
Pro100Tom
 Аватар для Pro100Tom
69 / 28 / 7
Регистрация: 29.10.2012
Сообщений: 326
23.09.2016, 17:51  [ТС]     Объединение view и projection матриц #24
Создам отдельный проект где только перемножать матрицы и векторы буду.

Скажите правильно ли всё делаю?
Column-Major

translation
1 0 0 Tx
0 1 0 Ty
0 0 1 Tz
0 0 0 1

rotation (y)
cos(a) 0 0 sin(a)
0 1 0 0
-sin(a) 0 0 cos(a)
0 0 0 1

scale
Sx 0 0 0
0 Sy 0 0
0 0 Sz 0
0 0 0 1

view матрица: абсолютно тоже самое, только инверсирована (инверсию проверю на wolfram alpha)
projection
s 0 0 0
0 s 0 0
0 0 a -1
0 0 b 0
где s = 1 / tan(0.5 * fov * pi / 180)
a = -f / (f - n)
b = -f * n / (f - n)

все эти матрицы перемножаю как transformation * view * projection

как я это делаю?
Код
x 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0

transformationView[0][0] = 
	transformation[0][0] * view[0][0] +  
	transformation[0][1] * view[1][0] +
	transformation[0][2] * view[2][0] + 
	transformation[0][3] * view[3][0];


0 x 0 0
0 0 0 0
0 0 0 0
0 0 0 0

transformationView[0][1] = 
	transformation[0][0] * view[0][1] +  
	transformation[0][1] * view[1][1] +
	transformation[0][2] * view[2][1] + 
	transformation[0][3] * view[3][1];
	
	
0 0 x 0
0 0 0 0
0 0 0 0
0 0 0 0
	
transformationView[0][2] = 
	transformation[0][0] * view[0][2] +  
	transformation[0][1] * view[1][2] +
	transformation[0][2] * view[2][2] + 
	transformation[0][3] * view[3][2];
	
	
0 0 0 x
0 0 0 0
0 0 0 0
0 0 0 0
	
transformationView[0][3] = 
	transformation[0][0] * view[0][3] +  
	transformation[0][1] * view[1][3] +
	transformation[0][2] * view[2][3] + 
	transformation[0][3] * view[3][3];
	

	
0 0 0 0
x 0 0 0
0 0 0 0
0 0 0 0

transformationView[1][0] = 
	transformation[1][0] * view[0][0] +  
	transformation[1][1] * view[1][0] +
	transformation[1][2] * view[2][0] + 
	transformation[1][3] * view[3][0];
	
	
0 0 0 0
0 x 0 0
0 0 0 0
0 0 0 0

transformationView[1][1] = 
	transformation[1][0] * view[0][1] +  
	transformation[1][1] * view[1][1] +
	transformation[1][2] * view[2][1] + 
	transformation[1][3] * view[3][1];
и так далее...

Добавлено через 3 минуты
Как я перемножаю вертекс на матрицу:
Код
vertex.x = 
	matrix[0][0] * vertex.x +
	matrix[0][1] * vertex.y +
	matrix[0][2] * vertex.z +
	matrix[0][3] * vertex.w;
	
где [0][1] - это
0 x 0 0
0 0 0 0
0 0 0 0
0 0 0 0


vertex.y = 
	matrix[1][0] * vertex.x +
	matrix[1][1] * vertex.y +
	matrix[1][2] * vertex.z +
	matrix[1][3] * vertex.w;
	
где [1][2] - это
0 0 0 0
0 0 x 0
0 0 0 0
0 0 0 0
грубо говоря: первый индекс - вниз, второй - вправо

Добавлено через 3 минуты
Цитата Сообщение от Pro100Tom Посмотреть сообщение
где s = 1 / tan(0.5 * fov * pi / 180)
a = -f / (f - n)
b = -f * n / (f - n)
fov - у меня 10.
near = -1
far = 1

Добавлено через 2 минуты
чтобы получить transformation матрицу я перемножаю:
translation * rotation * scaling.
(сначала первые две, а потом то, что получится на scaling).
Nick Alte
Эксперт С++
1594 / 986 / 117
Регистрация: 27.09.2009
Сообщений: 1,901
Завершенные тесты: 1
23.09.2016, 19:33     Объединение view и projection матриц #25
Цитата Сообщение от Pro100Tom Посмотреть сообщение
Column-Major
Это row-major, то, что и требовалось, соответствует привычной форме записи линейных уравнений.

Цитата Сообщение от Pro100Tom Посмотреть сообщение
view матрица: абсолютно тоже самое, только инверсирована
Нет. Инверсии там быть не должно никакой. Задача model - перенести точки из собственной СК объекта в СК сцены, задача view-матрицы перенести точки из СК сцены в СК наблюдателя (где глаз в нулевой позиции, направление взгляда по оси Z и так далее). Как правило, view-матрица содержит 2 преобразования: перенос на координаты наблюдателя, взятые со знаком минус (очевидно, что после этого он окажется в начале координат, что и требовалось) и поворот, совмещающий направление взгляда с осью Z и направление вверх с осью Y.

Цитата Сообщение от Pro100Tom Посмотреть сообщение
все эти матрицы перемножаю
Порядок перемножения матриц не зависит от row-major или column-major, и судя по исходникам, тут он соблюдён.

Цитата Сообщение от Pro100Tom Посмотреть сообщение
Как я перемножаю вертекс на матрицу:
Если это не настоящий код, а просто иллюстрация порядка перемножения, то порядок правильный, соответствующий row-major order. Если настоящий код, то это ужас-ужас (нельзя же пересчитывать компоненту, опираясь на уже изменённые предыдущие компоненты).
После перемножения не забываем делить итоговый вектор на его компоненту w (нормализация).

Цитата Сообщение от Pro100Tom Посмотреть сообщение
чтобы получить transformation матрицу я перемножаю
Перемножать надо в той последовательности, в которой применяются эти преобразования. Если у нас есть объект в центре, то translation(10, 0, 0) * scale (2) отнесёт его на 20 единиц, а scale(2) * translation(10, 0, 0) на 10 единиц.

Добавлено через 6 минут
Забыл упомянуть: порядок умножения зависит от того, в какой СК выражено преобразование. Если мы выражаем преобразования, всё время оставаясь в исходной СК и наблюдая за изменяющимся от наших действий объектом, то перемножать надо в обратном порядке. Если же после каждого преобразования мы следуем в новую СК вслед за объектом (при этом он для нас остаётся неизменным и неподвижным), то перемножение идёт в прямом порядке.
Pro100Tom
 Аватар для Pro100Tom
69 / 28 / 7
Регистрация: 29.10.2012
Сообщений: 326
23.09.2016, 21:27  [ТС]     Объединение view и projection матриц #26
Цитата Сообщение от Nick Alte Посмотреть сообщение
то перемножать надо в обратном порядке.
поэтому и получается, что всё работает, когда я перемножаю projection на view после того, как я уже трасформировал вертексы.

Добавлено через 1 минуту
Цитата Сообщение от Nick Alte Посмотреть сообщение
Если настоящий код, то это ужас-ужас
Конечно это не настоящий код, у меня же всё работает (при определённых условиях).

Я просто, блин, запутался. То один говорот, что у меня column-major, а я думал, что row-major. Теперь я начал всё перепроверять по несколько раз. Теперь вы говорите, что у меня row-major. Так же и с порядком перемножения матриц.
Nick Alte
Эксперт С++
1594 / 986 / 117
Регистрация: 27.09.2009
Сообщений: 1,901
Завершенные тесты: 1
23.09.2016, 22:02     Объединение view и projection матриц #27
Цитата Сообщение от Pro100Tom Посмотреть сообщение
поэтому и получается, что всё работает, когда я перемножаю projection на view
Нет, это относится только к матрице model. Преобразования view и projection чётко определены в соответствующих СК (сцены и зрителя соответственно). Поэтому порядок именно model * view * projection:
СК объекта --(model)--> СК сцены --(view)--> СК зрителя --(projection)--> экранная СК.

Цитата Сообщение от Pro100Tom Посмотреть сообщение
Теперь вы говорите, что у меня row-major
В Википедии есть соответствующая статья, можно свериться с ней.

Цитата Сообщение от Pro100Tom Посмотреть сообщение
Так же и с порядком перемножения матриц.
Это относится только к построению model из нескольких преобразований. Цепочку элементарных преобразований можно строить сколь угодно длинную, всё накопится в одной матрице, а вот как задаётся элементарное преобразование - вопрос отдельный, зависит от специфики того, как размещаются объекты в сцене. Иногда удобно сразу работать в СК сцены, как делал OpenGL, и множить в обратном порядке. Иногда удобно следовать за объектом и множить последовательно. Иногда приходится вообще совмещать оба подхода.
Pro100Tom
 Аватар для Pro100Tom
69 / 28 / 7
Регистрация: 29.10.2012
Сообщений: 326
24.09.2016, 23:15  [ТС]     Объединение view и projection матриц #28
Вот что я для себя нашёл (если хочешь чтобы объект вращался как планета вокруг солнца):
Код
translatedVertices = translationMatrix * vertices
translatedRotatedVertices = rotationMatrix * translatedVertices
тоже самое что и
Код
translationRotationMatrix = rotationMatrix * translationMatrix
translatedRotatedVertices = translationRotationMatrix * vertices
И если я не прав, то код, доказывающий обратное в студию!

Я еще не проверял, но теперь предполагаю, что чтобы перемножить обычные вертексы на смешанную матрицу, то её надо перемножать в таком порядке:
Код
projection * view * scaling * rotation * translation
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
25.09.2016, 19:15     Объединение view и projection матриц
Еще ссылки по теме:

Вычисление степени матрицы, вычисления произведения двух матриц, вычисление суммы двух матриц C++
C++ Что такое Model - View - Controller
C++ WinAPI Выбор tree-view control
C++ Model view controller
C++ WinAPI List View Control в WindowsXP

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
Nick Alte
Эксперт С++
1594 / 986 / 117
Регистрация: 27.09.2009
Сообщений: 1,901
Завершенные тесты: 1
25.09.2016, 19:15     Объединение view и projection матриц #29
Цитата Сообщение от Pro100Tom Посмотреть сообщение
И если я не прав, то код, доказывающий обратное в студию!
Вы придаёте какое-то непонятное, едва ли не фетишисткое значение *виду* преобразования, а не его *смыслу*. Порядок, в котором отдельные преобразования сливаются в единую матрицу model, зависит не от того, вращение это или смещение, а от того, какой у них смысл и как они заданы. Мне доводилось делать систему, воспроизводящую вид звёзд, Солнца, Земли и Луны с точки зрения находящегося на орбите объекта, и там мне приходилось выстраивать цепочки из нескольких перемещений и поворотов, и их точная последовательность зависела от смысла и того, как было задано преобразование.

Цитата Сообщение от Pro100Tom Посмотреть сообщение
Я еще не проверял, но теперь предполагаю, что чтобы перемножить обычные вертексы на смешанную матрицу, то её надо перемножать в таком порядке:
Вчитайтесь внимательно в мой предыдущий ответ внимательнее. То, что вы пишете, категорически неверно.
Yandex
Объявления
25.09.2016, 19:15     Объединение view и projection матриц
Ответ Создать тему
Опции темы

Текущее время: 06:09. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru