Я хочу экспортировать объект из 3ds max в мое приложение C ++ / DirectX, и у меня возникла проблема с ориентация экспорта.
3ds Max использует правша Z-Up система координат и мое приложение использует левша Y-Up система координат. я использую {x, y, z, w}
обозначения компонентов во всем этом вопросе.
У меня есть 3 кости (или любые другие иерархические объекты) в 3ds Max:
Для экспорта их ориентации я использую MaxScript:
if hasParent then
localOrientation = boneNode.transform.rotationPart * inverse boneNode.parent.transform.rotationPart
else
localOrientation = boneNode.transform.rotationPart
Я сохраняю эту локальную ориентацию в файл:
BoneRoot no_parent 0.707107 0.0 0.0 0.707107 //stands for (-90, 0, 0) Euler rotation in 3ds max UI
Bone001 BoneRoot 0.0 -0.382683 0.0 0.92388 //local orientation (parent space)
Bone002 Bone001 -0.353553 -0.612372 0.353553 -0.612372
Я читал, что, несмотря на 3ds Max петь правую систему координат, это использует левостороннюю систему для transform.rotationPart
,
Мой вопрос Как теперь преобразовать локальное вращение из этого файла в мое приложение? Может быть, я должен применить некоторые преобразования только корень кости? Я попытался применить это к каждой ориентации кости:
Quaternion convertFrom3dsMax(const Quaternion &input) {
auto q = input;
//swap Y and Z
auto temp = q.getZ();
q.setZ(q.getY());
q.setY(temp);
//invert
//q.setX(-q.getX());
q.setY(-q.getY());
q.setZ(-q.getZ());
q.setW(-q.getW());
return q;
}
И многие другие комбинации обмена осями, инвертирования аргументов и даже оставления всего как есть. Но каждый из моих импортных файловых костей ориентирован неправильно.
Моя сцена 3ds max выглядит так:
И мое заявление (для convertFrom3dsMax
функция, которую я представил; не зацикливайтесь на меше, который просто помощник, смотреть на линии которые представляют кости):
(например, но не только, последняя кость идет вверх, а не вниз)
Когда я не применяю ничего к загруженным кватерионам в моем convertFrom3dsMax
сцена выглядит так:
(например, но не только, средняя кость движется «от» вместо «к» экрану)
Обратите внимание, что я использую операции левой руки для DirectX в моем приложении (например, XMMatrixLookAtLH(...)
) и я отношусь к Y как «вверх».
Матрица вращения в приложении:
DirectX::XMMATRIX rotationMatrix = DirectX::XMMatrixRotationQuaternion(
DirectX::XMVectorSet(
object->global.getX(),
object->global.getY(),
object->global.getZ(),
object->global.getW()
)
);
И глобальная ориентация рассчитывается так: global = local * parent->global
где local
загружается для каждой кости из файла (с помощью convertFrom3dsMax
) а также operator*
определяется как:
Quaternion operator* (const Quaternion by) const {
//"R" for result
float wR = w * by.getW() - x * by.getX() - y * by.getY() - z * by.getZ();
float xR = x * by.getW() + w * by.getX() + y * by.getZ() - z * by.getY();
float yR = y * by.getW() + w * by.getY() + z * by.getX() - x * by.getZ();
float zR = z * by.getW() + w * by.getZ() + x * by.getY() - y * by.getX();
return Quaternion(xR, yR, zR, wR);
}
Я высоко ценю convertFrom3dsMax
как источник моих проблем (а не математика Quaternion или вызовы DirectX внутри приложения).
Для положения, которое не так сложно, как ориентация, которую я использую boneNode.transform.pos
а также:
Point3D convertFrom3dsMax(const Point3D &input) {
auto result = input;
//swap Y and Z
auto tempZ = result.getZ();
result.setZ(result.getY());
result.setY(tempZ);
return result;
}
которая выглядит правильно (начальная позиция каждой линии / кости в порядке, позиция не повернутых вершин вспомогательной сетки в порядке).
С 3DS, используя RH Z-Up, и вы используете LH Y up. Самое простое — игнорировать ось X, поскольку она не меняется; просто скопируйте данные. Вам нужно поменять местами 3DS Up — Z с Y — Up. После перестановки этих двух осей вам нужно инвертировать Z после перестановки; это связано с тем, что система LH + z выходит из экрана к вам.
Пример:
3DS Max указывают в RHS как [Право (+ x), Вверх (+ z), Вперед (+ y)] и с вашей LHS [Вправо (+ x), Вверх (+ y) и Вперед (-z)] , Поэтому, если у вас есть вершина или точка в системе RHS, такая как [3,4,5], когда вы переходите в свою систему LHS, точка должна теперь быть [3,5, -4]. Предполагая, что + Z в вашем LHS выходит из экрана.
Я не думаю, что вам нужно беспокоиться о преобразовании отдельных частей; Я думаю, что вся модель или ее корневой узел преобразования должны быть преобразованы в соответствии с этим соглашением.
Так это должно выглядеть примерно так:
mat4 convertRHStoLHS( mat4 model ) {
mat 4 newModel;
newModel.x = model.x; // Where X is X-Axis
newModel.y = model.z; // Y is Y-Axis & Z is Z-Axis
newModel.z = -model.y; // Z is Z-Axis & Y is Y-Axis
return newModel;
}
Где mat4 будет матрица преобразования модели вашей модели в пространстве модели.
Других решений пока нет …