3ds max to C++/DirectX application orientation conversion
Asked Answered
C

1

14

I want to export object from 3ds max to my C++/DirectX application and I have an problem with orientation exporting.

3ds max uses right-handed Z-up coordinate system and my application makes use of left-handed Y-up coordinate system. I use {x, y, z, w} notation of components in this whole question.

I have 3 bones (or any other hierarchical objects) in 3ds max:

To export their orientation I use MaxScript:

if hasParent then
    localOrientation = boneNode.transform.rotationPart * inverse boneNode.parent.transform.rotationPart
else
    localOrientation = boneNode.transform.rotationPart 

I save this localOrientation to file:

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

I've read that despite 3ds max sing right-handed coordinate system, it uses left-handed system for transform.rotationPart.

My question is, how to now convert the local rotation from that file to my application? Maybe I should apply some conversion to root bone only? I have tried apply this to each bone orientation:

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;
}

And many other combinations of swaping axes, inverting arguments and even leaving everything as is. But each and every way my imported file bones are oriented in a wrong way.


Additional information (if needed):

My 3ds max scene looks like this: enter image description here

And my application (for the convertFrom3dsMax function I presented; don't focus on mesh which is just an helper, look at lines that represent bones): enter image description here (for example, but not only, the last bone is going "up" instead of "down")

When I don't apply anything to loaded Quaterions in my convertFrom3dsMax the scene looks this way: enter image description here (for example, but not only, the middle bone is going "from" instead of "to" the screen)

Note that I use left-handed operations for DirectX in my application (e.g. XMMatrixLookAtLH(...)) and I treat Y as "up".

Rotation matrix in application:

DirectX::XMMATRIX rotationMatrix = DirectX::XMMatrixRotationQuaternion(
    DirectX::XMVectorSet(
        object->global.getX(),
        object->global.getY(),
        object->global.getZ(),
        object->global.getW()
    )
);

And the global orientation is calculated this way: global = local * parent->global where local is loaded for each bone from file (with a help from convertFrom3dsMax) and operator* is defined as:

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);
}

I highly consider the convertFrom3dsMax as the source of my problems (and not the Quaternion math or DirectX calls inside of application).


For position, which is not that tricky as orientation I use boneNode.transform.pos and:

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;
}

which looks just right (the starting position of each line/Bone is ok, position of un-rotated helper mesh vertices are ok).

Calomel answered 15/8, 2016 at 14:42 Comment(0)
M
2

With 3DS using RH Z-Up and you are using LH Y up. The easiest thing to do is ignore your x-axis since it doesn't change; just copy the data over. You need to swap 3DS's Up - Z with your Y - Up. After the swap of these two axis, then what you need to do is invert the Z after the swap; that is due to the fact that a LH system the +z is coming out of the screen towards you.

Example:

3DS Max point in a RHS as being [Right (+x), Up (+z), Forward (+y)] and with your LHS [Right (+x), Up (+y) and Forward(-z)]. So if you have a vertex or a point in a RHS system such as [3,4,5] when you convert to your LHS system the point should now be [3,5,-4]. Assuming that +Z in your LHS is coming out of the screen.

I don't think you should have to worry about converting individual parts; I think the entire model or its root transform node needs to be converted by that convention.

So it should look something like this:

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;
}

Where mat4 would be your model's model transform matrix in model space.

Myriagram answered 19/8, 2016 at 23:17 Comment(3)
I don't really want to export matrices from 3ds max to my app (file). I want to save an orientation (as quaternion) and I know it's stored under object.transform.rotationPart. My problem is about converting quaternion from 3ds max coordinate system to mine. The matrices vs quaternions is a bit off-topic, let's just say quaternions have strong advantages, especially in fields of bones and interpolation. And yes, 3ds max does use RHS but (as I mentioned in question) the transform.rotationPart which stores the orientation (as quaternion) seems to be in LHS (despite 3ds max UI uses RHS).Calomel
I understand what you are getting at now; but even if it is a quaternion instead of a matrix; you can still model the function above as the same except for instead of passing a mat4 model you'd be passing a quaternion and returning another. It's been a while since I've worked with 3DS or Maya; but the principles are still the same. It is more of a math problem and how their operations. Yes you still have to swap your Y & Z axis; but you still have to invert it when done, otherwise your orientation, translations and rotations won't be correct due to the difference of RHS versus a LHS.Myriagram
You can almost think of a quaternion as being a matrix. It is in short a specialized vector of 4D space so it is in fact a 1x4 or a 4x1 matrix. The only difference is are their fields. Instead of their fields being an actual scalar value of a physical location or distance from origin along its axis of a plane, It is a rotation value according to a specific axis where the w component is an arbitrary axis or the imaginary plane axis so to speak.Myriagram

© 2022 - 2024 — McMap. All rights reserved.