Импортер FBX SDK и система координат LH в OpenGL

Мы разрабатываем средство визуализации с использованием OpenGL. Одной из функций является возможность импорта моделей FBX. Модуль импорта использует FBX SDK (2017). Теперь, как мы все знаем,OpenGL является правосторонней системой координат. Это прямое направление от положительного к отрицательному, правое - правое, а вектор вверх - вверх. В нашем приложении требование иметь положительный вектор вперед, аналогично DirectX. На уровне приложения мы устанавливаем это, масштабируя Z матрицы проекции с -1. используя glm math:

glm::mat4 persp = glm::perspectiveLH (glm::radians (fov), width / height, mNearPlane, mFarPlane);

Что так же, как делать это:

glm::mat4 persp = glm::perspective (glm::radians (fov), width / height, mNearPlane, mFarPlane);
persp = glm::scale (persp , glm::vec3 (1.0f, 1.0f, -1.0f));

Пока все хорошо. Самое смешное, когда мы импортируем модели FBX.

При использовании

FbxAxisSystem::OpenGL.ConvertScene(pSceneFbx);

Затем преобразуем вершины с помощью глобального преобразования узла, которое вычисляется так:

 FbxSystemUnit fbxUnit = node->GetScene()->GetGlobalSettings().GetSystemUnit();
    FbxMatrix globalTransform = node->EvaluateGlobalTransform();
    glm::dvec4 c0 = glm::make_vec4((double*)globalTransform.GetColumn(0).Buffer());
    glm::dvec4 c1 = glm::make_vec4((double*)globalTransform.GetColumn(1).Buffer());
    glm::dvec4 c2 = glm::make_vec4((double*)globalTransform.GetColumn(2).Buffer());
    glm::dvec4 c3 = glm::make_vec4((double*)globalTransform.GetColumn(3).Buffer());

Геометрические грани инвертированы. (Порядок намотки по умолчанию против часовой стрелки в OpenGL)

При использовании конвертера DirectX:

  FbxAxisSystem::DirectX.ConvertScene(pSceneFbx);

Модель как перевернутая, так и перевернутая вверх дном.

OpenGL преобразован:

DirectX преобразован:

То, что мы нашли, что решает эту проблему, это отрицание Z столбца 3 в этой матрице. И также вращение его на 180 градусов вокруг оси Z. В противном случае передняя часть модели будет расположена сзади (да, звучит сложно, но это имеет смысл, когда сравнение различий между системами координат OpenGL и DirectX.

Итак, вся матрица "преобразования" теперь выглядит так:

  FbxSystemUnit fbxUnit = node->GetScene()->GetGlobalSettings().GetSystemUnit();
    FbxMatrix globalTransform = node->EvaluateGlobalTransform();
    glm::dvec4 c0 = glm::make_vec4((double*)globalTransform.GetColumn(0).Buffer());
    glm::dvec4 c1 = glm::make_vec4((double*)globalTransform.GetColumn(1).Buffer());
    glm::dvec4 c2 = glm::make_vec4((double*)globalTransform.GetColumn(2).Buffer());
    glm::dvec4 c3 = glm::make_vec4((double*)globalTransform.GetColumn(3).Buffer());

   glm::mat4    mat =
    glm::mat4(1, 0, 0, 0,
              0, 1, 0, 0,
              0, 0, -1, 0,//flip z to get correct mesh direction  (CCW)
              0, 0, 0, 1);
//in this case the model faces look right dir ,but the model
//itself needs to be rotated because the camera looks at it from the
//wrong direction.
    mat = glm::rotate(mat, glm::radians(180.0f), glm::vec3(0.0f, 0.0f, 1.0f));

    glm::mat4 convertMatr = glm::mat4(c0, c1, c2, c3)  *mat;

Затем преобразование вершин модели FBX с помощью этой матрицы дает желаемый результат:

Кстати, откуда мы знаем, что результат желателен? Мы сравниваем его с игровым движком Unity3D.

Теперь, это первый раз, когда я должен выполнить такой хак. Это похоже на очень неприятный хак. Особенно, когда речь идет о сетчатых сетках, нам нужно преобразовать с помощью матрицы преобразования также матрицы костей, матрицы поз, а что нет...

В этом случае возникает вопрос, когда нам нужно сохранить порядок намотки CCW и иметь позитивный форвард в OpenGL. Это единственный способ получить правильные геометрические преобразования?

(Источник 3d-модели - 3DsMax, экспортируется с Y-up.)

1 ответ

В большинстве программ, которые я делал в OpenGL, использовалась левосторонняя система, а не правосторонняя система DirectX. Что нужно понимать в OpenGL по сравнению с DirectX, так это в том, что в OpenGL нет встроенного объекта камеры. Вы должны создать / поставить свою собственную камеру, и, таким образом, вы можете буквально установить свою систему координат как RHC или LHC, в зависимости от того, как вы настроили свои сохраненные матрицы, в большинстве случаев настройками по умолчанию являются LHC. Другое важное различие между DirectX и OpenGL заключается в том, что, когда у вас есть сцена и камера в 3D-пространстве с DirectX, когда вы перемещаете камеру или поворачиваете ее; это именно камера, которая на самом деле движется, где, как в OpenGL, это не камера, которая движется, потому что она зафиксирована, и это вся сцена, которая движется относительно камеры. Таким образом, самый простой способ проиллюстрировать преобразование - это понять или узнать операции множественных матричных вычислений и узнать порядок ваших матриц MVP (модель - вид - проекция). Преобразование из RHC в LHC должно быть выполнено и предварительно рассчитано после открытия и загрузки в файл модели, а затем сохранено в матрицу модели. Затем, когда у вас есть подходящая матрица модели, остальные расчеты MVP должны быть точными.

Это были бы основные шаги

  • Откройте файл модели, извлеките необходимые или требуемые данные и загрузите содержимое в специальные пользовательские структуры данных приложения
  • При необходимости конвертируйте из одной системы координат в другую и сохраняйте обратно в пользовательские структуры.
  • Используйте пользовательские структуры для создания ваших MVP и отправки их на графическую карту с помощью пакетного процесса, используя нужные шейдеры
  • Рендеринг объектов на экран для каждого кадра буфера.

Вот несколько очень хороших прочтений при преобразовании между одной системой координат:

Самое простое, что можно сделать при преобразовании из RHC в LHC и наоборот, если X направлен влево и вправо, а Y - вверх и вниз, и все, что вам нужно сделать, это отменить каждую координату z, но это хорошо только для перевода и не вращения. Теперь, если в каком-либо приложении есть система RHC, и вы используете систему LHC, но в этом приложении сохранены данные модели, где, скажем, их вектор Up равен Z, а вектор входа и выхода - Y, тогда вам сначала нужно поменять местами каждый Y с Z, затем вы нужно отменить новый Z после перестановки, и снова это хорошо только с переводами, а не с поворотами.

Вот основная формула для конверсий:

Пусть M0 - заданная матрица преобразования 4x4.

Пусть M1 - дополнительная матрица аффинного преобразования 4x4, которая отображается из левой системы координат, которую вы хотите, в правую систему координат, которая у вас есть в настоящее время.

Тогда полное преобразование = inv(M1) * M0*M1

который может быть найден здесь: mathworks: mathlab * Математика или формула - это то же самое преобразование в любом направлении.

Другие вопросы по тегам