Войти
ПрограммированиеФорумГрафика

Матрица вида и матрица проекции. Фокус

#0
13:32, 6 янв. 2015

Для начала хотел бы уточнить, из чего состоит матрица вида. А то этот вопрос в разных туториалах и факах даже буржуи как-то обходят стороной, во всяком случае я не нашёл объяснений. Ну по сути это передвигание и разворот начала координат сцены (луча 0,0,-z в который мы всегда смотрим). Т.е. сначала нужно переместить начало координат в новую точку положения камеры, вычтя из (0,0,0) координаты этой точки. А за тем надо развернуть эту полуось -z куда-то, а куда? Ну то есть сначала мы сдвинули все вершины сцены на вектор обратный координатам положения камеры, и камера как бы стала в новом начале координат вокруг которого нужно сделать куда-то поворот. Короче не понятно как из чего составить эту матрицу поворота направления камеры.

Далее матрица проекции. Во многих местах я вижу среди входных параметров функции создания матрицы некий угол. Что это за угол?

void Matrix4Perspective(float *M, float fovy, float aspect, float znear, float zfar);

Например в официальном руководстве по opengl (8 издание) есть два варианта создания матрицы перспективной проекции без углов:

vmath::mat4 vmath::frustum(float left, float right, float bottom,
                           float top, float near, float far);
и
vmath::mat4 vmath::lookAt(vmath::vec3 eye, vmath::vec3 center,
                          vmath::vec3 up);

У этих вариантов наверное есть какие-то ограничения и специализации. Я путаюсь в таком большом количестве не очень понятных параметров. Объясните мне пожалуйста, что всё это означает и в каких случаях чево нужно.

Кроме всего, есть такая проблема, как эффект искажения в перспективной проекции. Пользователь видит в углах экрана вместо кругов яйца (можно наблюдать например в игре EVE Online). Глюк этот получается от того, что, грубо говоря, пирамидка плоскости проекции и камеры не пропорциональна монитору и расположению глаз пользователя. Обычно глаза в реале расположены дальше от монитора раза в два чем положение камеры от плоскости проекции сцены. Если приблизиться к монитору до совпадения с фокусом проекции, то предметы по краям экрана удивительнейшим образом приобретают правильную форму. Можете попробовать сами при помощи вот этой демки http://www.gamedev.ru/code/forum/?id=196369 .

Мне собственно хочется программно регулировать это расстояние фокуса. Полный контроль наверно можно сделать через фруструм, ибо он позволяет делать проекцию даже с центром в любой точке экрана (в одной из тем на этом форуме видел кому-то зачем-то нужно было подобное). Может кто чево такое делал, подскажите как.


#1
13:44, 6 янв. 2015
твой ник мне о diablo 2 напоминает...
#2
13:45, 6 янв. 2015

Матрица вида это тоже самое что и мировая матрица для любого объекта, но только обратная к ней. https://ru.wikipedia.org/wiki/Обратная_матрица

Обычная матрица перехода переводит из локальных координат в глобальные, обратная инвертирует это действие и переводит из глобальных коорлинат в локальные. Для матрицы вида локальные координаты задаются так:
центр - центр экрана
X - направленна слева на право, вдоль экрана
Y - снизу вверх
Z - от пользователя вглубь экрана

Получить матрицу вида можно такими же шагами как и мировую матрицу какого-нибудь объекта, https://ru.wikipedia.org/wiki/Матрица_перехода
а затем просто посчитать к ней обратную.

#3
13:45, 6 янв. 2015

vipermagi
> матрица вида
это просто инверсия мировой матрицы камеры.
т.е. у тебя есть обычная матрица с положением/вращением камеры, ты её инверсишь.
в результате если потом умножаешь на неё ворлдспейсовые позиции, то они получаются относительно позиции камеры (как если бы она была нулём координат) И точно так же относительно её ротации.

vipermagi
> Короче не понятно как из чего составить эту матрицу поворота направления
> камеры.
до инверсии это просто ортогональные 3 вектора, по Z ты смотришь.

vipermagi
> Что это за угол
field of view. от него зависит зум, насколько широко или приближённо будет камера видеть.

vipermagi
> vmath::lookAt
это не проекцию создаёт, а просто ротационную матрицу на основе направления от камеры к точке.

vipermagi
> вместо кругов яйца
на это все забивают, но было пара демок экспериментальных с попыткой исправить.
я помню даже на этом форуме кто-то выкладывал одну, не могу найти.

#4
13:48, 6 янв. 2015

vipermagi
> Далее матрица проекции.

[img=]http://mirtankov.su/sites/default/files/img/fov-scheme.png
#5
16:41, 8 янв. 2015
static_cast
> твой ник мне о diablo 2 напоминает...
Синяя футболка из диаблы2 - мой запасной ник, если основной уже зареган.

HOMPAIN
> Матрица вида это тоже самое что и мировая матрица для любого объекта, но только
> обратная к ней.

По сути я могу каждый аргумент входных данных умножить на -1 и получу, чё хотел? Типа, если камера поворачивается влево, то это на тот же угол толко вправо поворачиваются все вершины сцены. Или если камеру нужно сдвинуть куда-то, то это все вершины сцены нужно сдвинуть в противоположную точку.

Mr F
> это не проекцию создаёт, а просто ротационную матрицу на основе направления от
> камеры к точке.
Я не сомневаюсь, что оно основано на тех же типах преобразований и в итоге всё правильно поворачивает. Но мне нужно понимать как матрицы этих шагов преобразования действуют на входные данные. Камера может смотреть на объекты, а не просто так поворачиваться.

В официальной книжке написано буквально следующее
Frustrum, lookAt, perspective projection matrix | Матрица вида и матрица проекции. Фокус

чё-то рисунок какой-то огромный, не вижу в тэгах как отмасштабировать картинку

Либо авторы ошиблись, либо я не так понял.

HOMPAIN
Рисунок по проекции довольно непонятный. На пример, не видно, где находятся начала координат; по рисунку кажется, что на дальней плоскости, но ведь должны быть в фокусе, тогда плоскость near уходит в -z на некоторое расстояние. Не понятно так же что такое left, right, top и bottom, углы, расстояния или просто так площади.

Mr F
> на это все забивают, но было пара демок экспериментальных с попыткой исправить.
Возможно это на форуме они забивают, а у себя там успешно допиливают. Есть у многих людей нехорошая привычка разобравшись в вопросе не написать решение на форум, который пытался им помочь.

Нашёл две ссылки с демками наглядной работы камеры: http://songho.ca/opengl/gl_transform.html и http://user.xmission.com/~nate/tutors.html .

В первой ссылке две демонстрационные проги, показывающие, как меняется вид от разных параметров и как при этом выглядят команды gl*, создающие матрицы и как выглядят сами матрицы. Сразу становится понятно, что left, right, top и bottom - это расстояния от проекции точки фокуса на плоскость near до краёв, которое не меняется с изменением near. Это значит, что в их соотношении заложен угол бозора. А с применением угла в качестве аргумента только путаница одна, ибо тогда при изменении near с изображением ни чего не происходит кроме смены обрезки. С фруструмом же можно непосредственно меняя расстояния на плоскости проекции или сам near менять фокус, а угол обзора автоматом будет таким как надо для этого случая. Короче, с проекцией вроде всё понятно стало.

Во второй ссылке есть демки, в которых показывается как параметры функции lookAt влияют на положение камеры. Матриц ни каких нету и в целом демки сделаны с неудобным управлением. По работе lookAt не особо чего и проясняют. Вопрос то по большей части заключается не в том, что делает функция lookAt, а в том, как правильно задать upX, upY и upZ. На некоторых форумах писалось, что этот вектор не обязательно должен быть перпендикулярным к вектору направления взгляда. И почти всегда туда нужно будет вводить (...0,1,0), это, как я понял, изначальное направление вектора камеры. То есть он как бы проецируется на перпендикулярную вектору взгляда плоскость. Иными словами, после поворота камеры на обозреваемую точку, верхний вектор камеры наклоняется вслед за вектором взгляда, ну если бы можно было не указывать его в трёх последних аргументах. А так, если указывать его старое изначальное положение, то там угол тот же самый 90 градусов будет совпадать и работать непостижимо правильно до момента, когда камера развернётся строго вверх или строго вниз и вектор взгляда и указанный верхний вектор совпадут по (противо-)направлению. По этому мне думается, нужно вектор (0,1,0) перед добавлением в lookAt доварачивать той же матрицей, которая поворачивает изначальный вектор направления взгляда на обозреваемую точку. Тогда верхний вектор всегда будет длиной в 1 и он никогда не совпадёт по направлению с вектором взгляда. То есть возникает вопрос: как по двум векторам построить матрицу поворота? Ну а перед этим можно повернуть обычной матрицей поворота вокруг оси по градусам, если надо верхний вектор отклонить в сторону. Таким образом, должен получиться вектор, который в lookAt вписать не страшно. Но это пока только мои догадки, возможно не совсем верные. Что скажете?

#6
19:27, 8 янв. 2015

vipermagi
> По сути я могу каждый аргумент входных данных умножить на -1 и получу, чё
> хотел? Типа, если камера поворачивается влево, то это на тот же угол толко
> вправо поворачиваются все вершины сцены. Или если камеру нужно сдвинуть
> куда-то, то это все вершины сцены нужно сдвинуть в противоположную точку.
Это очень грубо. Простым умножением на -1 ты только смещение сможешь нормально найти, но не обратный поворот.

vipermagi
> Я не сомневаюсь, что оно основано на тех же типах преобразований и в итоге всё
> правильно поворачивает. Но мне нужно понимать как матрицы этих шагов
> преобразования действуют на входные данные. Камера может смотреть на объекты, а
> не просто так поворачиваться.
Учи математику (линейную алгебру). Начни с "что такое матрицы" и "операции с матрицами". Потом узнай что такое декартовы координаты и что такое однородные координаты.
Когда разберешься со всем этим - можно переходить к матрице проекции. Вот тут шаг за шагом: http://ogltutor.netau.net/tutorials/tutorial12.html

vipermagi
> Рисунок по проекции довольно непонятный. На пример, не видно, где находятся
> начала координат; по рисунку кажется, что на дальней плоскости, но ведь должны
> быть в фокусе, тогда плоскость near уходит в -z на некоторое расстояние. Не
> понятно так же что такое left, right, top и bottom, углы, расстояния или просто
> так площади.
Начало координат находится в глазу. Оно там оказывается когда ты умножаешь вектор на видовую матрицу (vmath:LookAt которая). По поводу left/right/top/bottom это расстояния. Разберись сначала с математикой, ну или на худой конец скачай какой-нибудь пример и посмотри какие значения туда задают.

vipermagi
> Возможно это на форуме они забивают, а у себя там успешно допиливают. Есть у
> многих людей нехорошая привычка разобравшись в вопросе не написать решение на
> форум, который пытался им помочь.
А смысл писать? Это банальная линейная алгебра. Что писать то? Как матрицу задавать по базису?

vipermagi
> Сразу становится понятно, что left, right, top и bottom - это расстояния от
> проекции точки фокуса на плоскость near до краёв, которое не меняется с
> изменением near.
Вот ты там ввел какую то точку фокуса. Но её нету. Точка фокуса появляется только когда свет проходит через линзу. А в рендере тупо проекция. Так что я лично не понимаю о чем ты. Какая еще точка фокуса?

vipermagi
> По этому мне думается, нужно вектор (0,1,0) перед добавлением в lookAt
> доварачивать той же матрицей, которая поворачивает изначальный вектор
> направления взгляда на обозреваемую точку. Тогда верхний вектор всегда будет
> длиной в 1 и он никогда не совпадёт по направлению с вектором взгляда. То есть
> возникает вопрос: как по двум векторам построить матрицу поворота? Ну а перед
> этим можно повернуть обычной матрицей поворота вокруг оси по градусам, если
> надо верхний вектор отклонить в сторону. Таким образом, должен получиться
> вектор, который в lookAt вписать не страшно. Но это пока только мои догадки,
> возможно не совсем верные. Что скажете?
Скажу что тут надо даже не с матриц начинать, а с векторов. Сложение, вычитание, скалярное произведение, векторное произведение, смешанное произведение. На форумах такое писать глупо. Не копировать же материал из учебников по линейной алгебры сюда.

#7
14:51, 9 янв. 2015

vipermagi
Точку нужно перевести из мировых координат в систему координат камеры. Орты системы координат камеры имеют координаты в мировой системе координат. По ним и строй матрицу вида - координаты ортов располагай по столбцам (орт оси Ox камеры в мире - в первом стобце, Oy - во втром и т.д.). Вектор-строка позиции вершины умножается на эту матрицу вида, получается три скалярных произведения, дающих проекции вектора позиции вершины в мире  на оси координат камеры - это и есть координаты вершины в пространстве камеры.
В самом начале расположи оси камеры также как и оси мировой системы. Затем можно их поворачивать и смещать.

При перспективной проекции используется свойство подобных треугольников, некоторые отношения при этом равны котангенсу угла при пирамиде фрустума - для этого и угол.

Прошло более 10 месяцев
#8
13:29, 26 ноя. 2015

вот код с MSDN:

zaxis = normal(cameraTarget - cameraPosition)
xaxis = normal(cross(cameraUpVector, zaxis))
yaxis = cross(zaxis, xaxis)

 xaxis.x           yaxis.x           zaxis.x          0
 xaxis.y           yaxis.y           zaxis.y          0
 xaxis.z           yaxis.z           zaxis.z          0
-dot(xaxis, cameraPosition)  -dot(yaxis, cameraPosition)  -dot(zaxis, cameraPosition)  1
Может кто обьяснить, что происходит тут с позицией в 4 строке? У себя я как матрицу вида использую обратную матрицу трансформции, но по работе столкнулся с использованием стандартных функций, и заинтересовало что это значит.
Так как инвертированная матрица трансформации отличается от матрицы, сформированной по вишеизложенной схеме

#9
14:46, 26 ноя. 2015

Anders333
по сути матрица вида является трансформацией из одной системы координат в другую. сначала ты считаешь новые направляющие осей: xaxis, yaxis, zaxis. а 4 строкой переводишь старые координаты из системы
<1,0,0>;<0,1,0>;<0,0,1> в систему <xaxis>;<yaxis>;<zaxis>
без -dot, ты будешь смещаться по старым направляющим

#10
16:23, 26 ноя. 2015

Ravager
Спасибо за ответ.

#11
17:37, 26 ноя. 2015

Anders333
> Спасибо за ответ. Я правильно понял, что в 4 строке хранится смещение по новым
> осям?
операция умножения матрицы на вектор (xV,yV,zY,1) тебе должно все объяснить.

xG=xV*M.xaxis.x+yV*M.xaxis.y+zV*M.xaxis.z+M.xaxis.w;
yG=xV*M.yaxis.x+yV*M.yaxis.y+zV*M.yaxis.z+M.yaxis.w;
zG=xV*M.zaxis.x+yV*M.zaxis.y+zV*M.zaxis.z+M.zaxis.w;
wG=1;

#12
20:03, 26 ноя. 2015

foxes
понял, всё так и есть =)
Всем еще раз спасибо.

ПрограммированиеФорумГрафика

Тема в архиве.