Преобразование ориентации приложения 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 будет вашей модельной матрицей преобразования модели в пространстве модели.