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

C++

Войти
Регистрация
Восстановить пароль
 
 
Pro100Tom
69 / 28 / 7
Регистрация: 29.10.2012
Сообщений: 328
#1

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

19.09.2016, 11:45. Просмотров 874. Ответов 28
Метки нет (Все метки)

Здравствуйте!

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

Если издалека, то чтобы обработать вертексы, мы их пропускаем через 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 совсем другая становится.

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

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

Заранее спасибо.
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Pro100Tom
69 / 28 / 7
Регистрация: 29.10.2012
Сообщений: 328
20.09.2016, 18:49  [ТС]     Объединение view и projection матриц #16
У меня все матрицы значит в column major записаны.
scaling - не имеет значения, она симметрична.
rotation
cos() 0 sin() 0
0 0 0 0
-sin() 0 cos() 0
0 0 0 1

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

view
1 0 0 0
0 1 0 0
0 0 1 -15
0 0 0 1

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)

Добавлено через 46 минут
Скажите, правильно ли я понимаию стадии pipeline'а?
(пошагово для удобства)
1). TransformationMatrix - пропускаем оригинальные вертекса объекта, чтобы получить вертексы в World пространстве
2). ViewMatrix - пропускаем вертексы World пространства, чтобы получить вертексы в Camera пространстве
3). ProjectionMatrix - пропускаем вертексы Camera пространства через матрицу проекции, чтобы симулировать перспективу.
Для этого надо каждую компоненту каждого вертекса разделить на компоненту w.
После этого просто используем x и y, предварительно проверив находятся ли они в пределах окна.

Ничего не пропустил?
Fulcrum_013
663 / 731 / 72
Регистрация: 14.12.2014
Сообщений: 5,699
Завершенные тесты: 3
20.09.2016, 20:12     Объединение view и projection матриц #17
Цитата Сообщение от Pro100Tom Посмотреть сообщение
Скажите, правильно ли я понимаию стадии pipeline'а?
Ну примерно так. А если подробнее:
1) сборка примитивов. Т.е. Определение по индексам какие номера вертексов потребуются.
2) Трансформация. Т.е. умножение координат вертекса на матрицу трансформации. (произведение Model*View*Projection) (т.е. фактически то что делает VertexShader)
3) Отсечение. т.е. обрезка отрезков/треугольников/удаление точек вышедших за пределы пирамиды/куба перспективы (как минимум желательно обрезать плоскостью near)
4) Перспетивное деление.
5) Окончательное отсечение (обрезка остальными плоскостями если в пункте 3 резали только плоскостью near)
6) Масштабирование в ScreenSpace
7) Растеризация. т.е. вычисление закрашенных примитивами точек с учетом Z координаты (z интерполируется вдоль примитива) и сортировка по глубине (т.е. z-буфер). Для прошедших z-тест фрагментов вычисление освещенности (т.е. то что делает PixelShader)
Для отрисовки нурбсов и т.п. либо применяют более другие виды интерполяции нежели интерполяция плоскости треугольник при растеризации (в конвейерах профессиональных карт) либо добавляют еще одну стадию конвейера для разбиения патча на треугольники (в обычных домашних ускорителях то что делают Hull и Domain шейдеры) Стадия добавляется между 2 и 3.
Отсечение кстати задачка со многими неизвестными. Потому как по Near очень стоит отсекать до перспективного деления (при перспективном делении все что имеет отрицательный Z будет перевернуто вверх ногами что путает все карты при отсечении отрезков/треугольников вертексы которых лежат по разные стороны плоскости z=0, а вертексы имеющие z=0 вообще вылетят с ексекпшином или получат неопределенное значение). А с другой стороны удобнее отсекать после перспективного деления так как в результате перспективного деления пирамида отсечения превращается в куб отсечения.

Ну а вообще матрицы имеют свойство накапливать трансформацию. При этом в общем то не важно они Row Major или Column Major. Важен только порядок умножения.
К примеру для RowMajor нужно умножать Model*View*Projection и вектор координат умножать на матрицу. А для column Major умножать Projection*View*Model и матрицу умножать на вектор вертекса.

Добавлено через 10 минут
Цитата Сообщение от Pro100Tom Посмотреть сообщение
У меня все матрицы значит в column major записаны.
projection в RowMajor.
в Translation ошибка.
Должно быть
1 0 0 Tx
0 1 0 Ty
0 0 1 Tz
0 0 0 1
Pro100Tom
69 / 28 / 7
Регистрация: 29.10.2012
Сообщений: 328
20.09.2016, 21:42  [ТС]     Объединение view и projection матриц #18
Цитата Сообщение от Fulcrum_013 Посмотреть сообщение
projection в RowMajor.
Спасибо, переведу сейчас. А по поводу translation - это опечатка.

Добавлено через 29 минут
Транспонировал я матрицу проекции - ни фига. Не работает!
Но вот, что забавно. И обычная и траспонированная матрица проекции визуализирует объект нормально. И fov работает как надо и eye (хоть он во view), единственное отличие, так это то, что в траспонированной матрице проекции объект перевёрнут.

Добавлено через 33 минуты
Нашёл!!!

Надо projection * view вместо view * projection!!!
Fulcrum_013
663 / 731 / 72
Регистрация: 14.12.2014
Сообщений: 5,699
Завершенные тесты: 3
20.09.2016, 21:56     Объединение view и projection матриц #19
Цитата Сообщение от Pro100Tom Посмотреть сообщение
Нашёл!!!
Надо projection * view вместо view * projection!!!
От перемены мест множителей результат транспанируется.
Pro100Tom
69 / 28 / 7
Регистрация: 29.10.2012
Сообщений: 328
20.09.2016, 22:03  [ТС]     Объединение view и projection матриц #20
Цитата Сообщение от Fulcrum_013 Посмотреть сообщение
От перемены мест множителей результат транспанируется.
Сорри, не соглашусь с вами.
Nick Alte
Эксперт С++
1628 / 1000 / 118
Регистрация: 27.09.2009
Сообщений: 1,931
Завершенные тесты: 1
21.09.2016, 21:22     Объединение view и projection матриц #21
Цитата Сообщение от Pro100Tom Посмотреть сообщение
Надо projection * view вместо view * projection!!!
Если матрицы считаются правильно, то надо как раз view * projection.
Pro100Tom
69 / 28 / 7
Регистрация: 29.10.2012
Сообщений: 328
22.09.2016, 16:12  [ТС]     Объединение view и projection матриц #22
Цитата Сообщение от Nick Alte Посмотреть сообщение
Если матрицы считаются правильно, то надо как раз view * projection.
Вот и я так думал сначала. Не подскажете, где у меня ошибка?
Nick Alte
Эксперт С++
1628 / 1000 / 118
Регистрация: 27.09.2009
Сообщений: 1,931
Завершенные тесты: 1
23.09.2016, 17:23     Объединение view и projection матриц #23
Возможно, путаница в ориентации матриц при их формировании (row-wise или column-wise) и/или порядке умножения на вектор? Попробуйте прогнать простые тестовые матрицы и векторы через ваши процедуры и посмотрите, что будет получаться.
Pro100Tom
69 / 28 / 7
Регистрация: 29.10.2012
Сообщений: 328
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
Эксперт С++
1628 / 1000 / 118
Регистрация: 27.09.2009
Сообщений: 1,931
Завершенные тесты: 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
69 / 28 / 7
Регистрация: 29.10.2012
Сообщений: 328
23.09.2016, 21:27  [ТС]     Объединение view и projection матриц #26
Цитата Сообщение от Nick Alte Посмотреть сообщение
то перемножать надо в обратном порядке.
поэтому и получается, что всё работает, когда я перемножаю projection на view после того, как я уже трасформировал вертексы.

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

Я просто, блин, запутался. То один говорот, что у меня column-major, а я думал, что row-major. Теперь я начал всё перепроверять по несколько раз. Теперь вы говорите, что у меня row-major. Так же и с порядком перемножения матриц.
Nick Alte
Эксперт С++
1628 / 1000 / 118
Регистрация: 27.09.2009
Сообщений: 1,931
Завершенные тесты: 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
69 / 28 / 7
Регистрация: 29.10.2012
Сообщений: 328
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++ WinAPI Выбор tree-view control
Перерисовка фрагмента области view Visual C++
C++ WinAPI List View Control в WindowsXP
C++ Что такое Model - View - Controller
C++ Люди помогите с Tree View Control

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

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

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

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