Преобразование ориентации приложения 3ds max в С++/DirectX
Я хочу экспортировать объект из 3ds max в мое приложение С++/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
, которую я представил, не фокусируйтесь на сетке, которая является всего лишь помощником, смотреть строки, которые представляют кости):
(например, но не только, последняя кость идет "вверх" вместо "вниз" )
Если я не применил ничего к загруженным Quaterions в моем 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
как источник своих проблем (а не ответы Quarterion или 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;
}
который выглядит правильно (начальная позиция каждой строки /Bone в порядке, положение вершин с вертушкой без поворота в порядке).
Ответы
Ответ 1
С помощью 3DS с использованием RH Z-Up и вы используете LH Y вверх. Самое простое - игнорировать ось x, так как она не изменяется; просто скопируйте данные. Вам нужно поменять местами 3DS Up - Z с помощью Y - Up. После замены этих двух осей, то, что вам нужно сделать, это инвертировать Z после обмена; это связано с тем, что система LH + z выходит из экрана по направлению к вам.
Пример:
3DS Max point в RHS как [Right (+ x), Up (+ z), Forward (+ y)] и с вашей LHS [Right (+ x), Up (+ y) и Forward (- г)]. Поэтому, если у вас есть вершина или точка в системе RHS, например [3,4,5], когда вы конвертируете в свою систему LHS, точка теперь должна быть [3,5, -4]. Предположим, что + Z в вашей LHS выходит из экрана.
Я не думаю, что вам нужно беспокоиться о преобразовании отдельных частей; Я думаю, что вся модель или ее корневой преобразователь node должны быть преобразованы этим соглашением.
Поэтому он должен выглядеть примерно так:
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 будет вашей модельной матрицей преобразования модели в пространстве модели.