несоответствия с матричной математикой между GLSL и GLM, или есть такая вещь, как плохая матрица представления

Итак, я столкнулся с некоторыми странностями между GLSL и GLM.

Если я сгенерирую следующую матрицу представления (С++):

vec3 pos(4, 1, 1);
vec3 dir(1, 0, 0);
mat4 viewMat = glm::lookAt(pos, pos+dir, vec3(0,0,1));

А затем в gsl выполните:

fragColour.rgb = vec3(inverse(viewMat) * vec4(0,0,0,1)) / 4.f;

Затем я ожидаю, что экран станет розовато-красным или (1.0,0.25,0.25). Вместо этого я получаю черный.

Однако, если я сделаю это в GLM:

vec3 colour = vec3(glm::inverse(viewMat) * vec4(0,0,0,1)) / 4.f;
cout << glm::to_string(colour) << endl;

Я получаю ожидаемый результат (1.0,0.25,0.25).

Теперь, если я изменю viewMat на (C++):

vec3 pos(4, 1, 1);
vec3 dir(1, 0.000001, 0);
mat4 viewMat = glm::lookAt(pos, pos+dir, vec3(0,0,1));

Тогда бац! Я получаю (1.0,0.25,0.25) как в GLSL, так и в GLM.

Это не имеет смысла для меня. Почему это происходит? Эта матрица представления отлично работает везде в GLSL — я просто не могу ее инвертировать. Это происходит всякий раз, когда dirY == 0.f.

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

Редактировать: Кроме того, похоже, это не имеет ничего общего с вектором вверх lookAt (который я все равно установил на Z). Даже если я настрою на (0,1,0), произойдет то же самое. Все выворачивается набок, но я все равно не могу инвертировать матрицу вида в GLSL.

Редактировать: Хорошо, поэтому по предложению Дерхасса я уже пытался отправить матрицу представления в инвертированном виде. Бам, отлично работает. Итак, похоже, что моя реализация GL действительно каким-то образом не способна инвертировать эту матрицу. Это должна быть самая странная ошибка GL, с которой я когда-либо сталкивался. Однако было бы полезно какое-то объяснение того, почему инвертировать матрицы в шейдерах - плохая идея. EditAgain: отправка инвертированных матриц через мой движок привела к огромному увеличению частоты кадров. ОБЯЗАТЕЛЬНО СДЕЛАЙТЕ ЭТО.


person Jagoly    schedule 11.04.2015    source источник
comment
Ну, насколько я могу судить, эта проблема совершенно не связана с glm. Похоже, это просто проблема с инвертированием в GLSL. В зависимости от того, как настроена ваша матрица, она должна быть полностью обратимой, и числовые проблемы не должны быть проблемой. Это может быть просто проблема с вашей реализацией GL. Также обратите внимание, что инвертирование матриц в шейдере в большинстве случаев — плохая идея, но она, конечно, должна работать. Я рекомендую проверить это с некоторыми другими реализациями GL, если это возможно.   -  person derhass    schedule 11.04.2015
comment
@derhass Аааа, я не подумал об отправке уже перевернутой матрицы. Я попробую это. Я также попытаюсь увидеть, возникает ли проблема в другом месте. На данный момент я использую довольно старый драйвер nvidia (тот, что в репозиториях Ubuntu 14.04).   -  person Jagoly    schedule 11.04.2015
comment
Это был первый раз, когда я узнал, что GLSL теперь вообще имеет обратную функцию. Это определенно не дружественная к GPU операция. Всегда помните об иерархии операций: за отрисовку, за вершину, за фрагмент. Всегда перемещайте вещи как можно ниже. Вы только что попали в очень маловероятный путь кода, выполнив инверсию для каждой вершины. Также имейте в виду, что общий обратный обычно не требуется. Большинство матриц вида модели должны быть ортонормальными. Где инверсия совпадает с транспонированием.   -  person starmole    schedule 12.04.2015
comment
Хех... наверное, не время говорить, что я делал это по фрагментам :P   -  person Jagoly    schedule 12.04.2015


Ответы (1)


Произвольная инверсия матрицы 4x4 — небыстрая и небезопасная задача

По многим причинам, таким как более низкая точность FPU на стороне GPU и необходимость многих делений при инверсии (ну, это зависит от метода вычисления), и не все матрицы имеют обратную и т. д. (я думаю, что это также причина, по которой GL не имеет такой реализации либо)... Для лучшего изображения см. Понимание матриц гомогенного преобразования 4x4 и найдите там функцию matrix_inv, насколько сложны вычисления действительно есть (используются определители). Существует также GEM (метод исключения Гаусса), но он не используется из-за его особенностей и необходимости сортировки строк...

Если матрицы являются статическими для каждого кадра рендеринга, что обычно имеет место, это пустая трата мощности графического процессора, вычисляющая ее в шейдерах вершин/фрагментов/геометрии снова и снова для каждой вершины/фрагмента (вот почему происходит прирост скорости).

Кто-то может возразить, что инверсия ортогональной однородной матрицы просто транспонирует матрицу, но как GL/GLSL может знайте, что он имеет дело с такой матрицей (проверка тоже не так проста) в любом случае в этом случае вы можете использовать transpose, который реализован на GLSL и должен быть быстрым (это просто переупорядочение элементов)

person Spektre    schedule 08.10.2015
comment
Я ожидаю, что это ответ. Инверсия матрицы обычно приводит к численной нестабильности, и я бы почти всегда избегал инвертирования матрицы, если бы мог. - person Dietrich Epp; 08.10.2015
comment
@DietrichEpp я тоже, но в графике, особенно с эффектами камеры, этого не так просто избежать :( - person Spektre; 08.10.2015
comment
Это распространенное заблуждение, его обычно очень легко избежать. Вы можете генерировать матрицу для нормалей и делать обратные проекции и тому подобное, даже не вычисляя обратную общую матрицу. - person Dietrich Epp; 10.10.2015