Я импортирую сетку в Blender, экспортирую ее с настройкой axis_forward='-Z', axis_up='Y'
, импортирую в FleX от NVIDIA, поворачиваю ее и сохраняю на диске; Я называю эту сетку X
. Я также импортирую сетку в Blender и вращаю ее столько же; Я называю эту сетку Y
. После того, как я импортировал X
в Blender (настройка axis_forward='-Z', axis_up='Y'
), я понял, что X
имеет другое вращение, что означает, что FleX использует разные глобальные оси (я думаю, что -Y
вперед и Z
вверх) или он применяет повороты в другом порядке или их комбинации. Так что я сейчас в замешательстве. Я не хочу ничего менять на стороне FleX. Однако я хочу повернуть Y
таким образом, чтобы это соответствовало тому, что экспортирует FleX (X
) после поворота. Я также попробовал с Quaternions, но я все еще не могу понять, как FleX трансформирует объект. Единственное, что мне удалось выяснить эмпирически, это то, что значение вращения rx
применяется одинаково для FleX и Blender. Это означает, что объекты X
и Y
будут полностью перекрываться, если импортироваться в сцену в Blender.
Моя цель - вращать объект в FleX, чтобы вращение объекта Y
точно совпадало с объектом X
, когда я импортирую X
в Blender. Например, я хочу, чтобы FleX вращал объект так же, как Блендер вращает его с вектором вращения Эйлера [rx, ry, rz]
. Как мне этого добиться?
Обратите внимание , что я не изменяю порядок вращения в Blender и использую вращение по умолчанию XYZ
.
Вот некоторые изображения визуальных различий между FleX и Blender для таких преобразований:
Вектор вращения Эйлера: [0, 89.9, 0]
для объекта Y
в Blender.
После применения вращения в Blender (объект Y
):
После применения того же вращения ([0, 89.9, 0]
) в FleX и импорта объекта X
в Blender:
Вектор вращения Эйлера: [0, 0, 89.9]
для объекта Y
в Blender.
После применения того же поворота ([0, 0, 89.9]
) в FleX и импорта объекта X
в Blender:
Может показаться, что по изображениям FleX легко угадать ry
и rz
при применении поворота. Если я также поменяю местами ry
и rz
при применении вращений в Blender, то и X
, и Y
перекрываются. Однако это работает, только если все компоненты вектора вращения равны нулю, кроме одной из них. Если вектор вращения имеет вид, подобный [-43.964176, 20.641195, -1.2689421]
X
и Y
, больше не перекрываются, и расхождения начинают проявляться, как показано ниже:
Расхождения более заметны, если я положу ткань на X
в FleX, импортирую ткань и Y
в Blender и повернем Y
на [-43.964176, -1.2689421, 20.641195]
(обратите внимание, что я поменялся ry
и rz
при применении вращения в Blender, а не в FleX):
Обратите внимание, что если я импортирую X
здесь, ткань будет идеально прикрывать его, прикасаясь к нему на поверхности:
После некоторого взлома для последнего примера я заметил, что если применить вектор вращения [-43.964176, 1.2689421, 20.641195]
(rx, -rz, ry), объекты почти полностью перекрываются:
В качестве другого примера, я хочу применить вращение [87.68034, 79.94778, 82.697876]
в Blender, которое должно в идеале дать мне что-то вроде этого:
Тем не менее, FleX дает мне следующее (без обмена перед передачей вектора вращения в FleX):
Я думал, что, возможно, применение поворота в порядке (rx, -rz, ry)
в Blender даст мне совершенно совпадающий результат, который я получил для предыдущего примера, но вместо этого я получил очень странные результаты для другого, как показано ниже. Обратите внимание, что я хотел повернуть объект на [87.68034, 79.94778, 82.697876] `:
Вращая объект вручную в Blender, я в конечном итоге мог получить его как можно ближе к Y
(экспортировано из FleX). Удивительно, но вектор вращения, который перекрывает X
и Y
, сильно отличается от [87.68034, 79.94778, 82.697876]
в (rx, ry, rz)
или [87.68034 -82.697876, 79.94778]
в (rx, -rz, ry)
. Это что-то около [5.38, -10.1, 88.6]
в `(rx, ry, rz), как показано ниже:
Хотя вам может понадобиться больше информации, чтобы точно выяснить, что происходит, но ниже я публикую код, который используется в FleX для вычисления его матриц вращения. Верхний используется, когда используются углы Эйлера, а второй используется, когда вводятся кватернионы:
// generate a rotation matrix around an axis, from PBRT p74
inline Mat44 RotationMatrix(float angle, const Vec3& axis)
{
Vec3 a = Normalize(axis);
float s = sinf(angle);
float c = cosf(angle);
float m[4][4];
m[0][0] = a.x * a.x + (1.0f - a.x * a.x) * c;
m[0][1] = a.x * a.y * (1.0f - c) + a.z * s;
m[0][2] = a.x * a.z * (1.0f - c) - a.y * s;
m[0][3] = 0.0f;
m[1][0] = a.x * a.y * (1.0f - c) - a.z * s;
m[1][1] = a.y * a.y + (1.0f - a.y * a.y) * c;
m[1][2] = a.y * a.z * (1.0f - c) + a.x * s;
m[1][3] = 0.0f;
m[2][0] = a.x * a.z * (1.0f - c) + a.y * s;
m[2][1] = a.y * a.z * (1.0f - c) - a.x * s;
m[2][2] = a.z * a.z + (1.0f - a.z * a.z) * c;
m[2][3] = 0.0f;
m[3][0] = 0.0f;
m[3][1] = 0.0f;
m[3][2] = 0.0f;
m[3][3] = 1.0f;
return Mat44(&m[0][0]);
}
inline Mat44 RotationMatrix(Quat q)
{
Matrix33 rotation(q);
Matrix44 m;
m.SetAxis(0, rotation.cols[0]);
m.SetAxis(1, rotation.cols[1]);
m.SetAxis(2, rotation.cols[2]);
m.SetTranslation(Point3(0.0f));
return m;
}
А вот как я применяю вектор вращения Эйлера:
obj->Transform(RotationMatrix(op.rotate.x, Vec3(1.0f, 0.0f, 0.0f)));
obj->Transform(RotationMatrix(op.rotate.y, Vec3(0.0f, 1.0f, 0.0f)));
obj->Transform(RotationMatrix(op.rotate.z, Vec3(0.0f, 0.0f, 1.0f)));
И я думаю, что так должно быть Transform()
:
void Mesh::Transform(const Matrix44& m)
{
for (uint32_t i=0; i < m_positions.size(); ++i)
{
m_positions[i] = m*m_positions[i];
m_normals[i] = m*m_normals[i];
}
}