3ds max 到 C++/DirectX 应用程序方向转换

Posted

技术标签:

【中文标题】3ds max 到 C++/DirectX 应用程序方向转换【英文标题】:3ds max to C++/DirectX application orientation conversion 【发布时间】:2016-12-21 18:58:50 【问题描述】:

我想将对象从 3ds max 导出到我的 C++/DirectX 应用程序,但我遇到了方向导出的问题。

3ds max 使用 右手 Z-up 坐标系,而我的应用程序使用 左手 Y-up 坐标系。我在整个问题中使用x, y, z, w 组件表示法。

我在 3ds max 中有 3 个骨骼(或任何其他分层对象):

为了导出它们的方向,我使用 MaxScript:

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

我将此 localOrientation 保存到文件中:

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 中加载的 Quaterions 应用任何东西时,场景看起来是这样的: (例如,但不仅如此,中间骨骼是“从”而不是“到”屏幕)

请注意,我在应用程序中对 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 是我的问题的根源(而不是应用程序内部的四元数数学或 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;

看起来恰到好处(每条线/骨骼的起始位置没问题,未旋转的辅助网格顶点的位置也没问题)。

【问题讨论】:

【参考方案1】:

在 3DS 中使用 RH Z-Up,而您正在使用 LH Y up。最简单的做法是忽略您的 x 轴,因为它不会改变;只需将数据复制过来。您需要将 3DS 的 Up - Z 与 Y - Up 交换。这两个轴交换后,那么你需要做的是交换后的Z反转;这是因为 LH 系统 +z 从屏幕中向您走来。

例子:

RHS 中的 3DS Max 点为 [右 (+x)、上 (+z)、前 (+y)] 并且您的左手 [右 (+x)、上 (+y) 和前 (- z)]。因此,如果您在转换为 LHS 系统时在 RHS 系统中有一个顶点或点,例如 [3,4,5],则该点现在应该是 [3,5,-4]。假设您的 LHS 中的 +Z 从屏幕上显示出来。

我认为您不必担心转换单个零件;我认为整个模型或其根变换节点都需要按照该约定进行转换。

所以它应该看起来像这样:

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 是模型空间中模型的模型变换矩阵。

【讨论】:

我真的不想将矩阵从 3ds max 导出到我的应用程序(文件)。我想保存一个方向(作为四元数),我知道它存储在object.transform.rotationPart 下。我的问题是将四元数从 3ds max 坐标系转换为我的。矩阵与四元数有点跑题了,我们只能说四元数有很强的优势,尤其是在骨骼和插值领域。是的,3ds max 确实使用 RHS,但是(正如我在问题中提到的)存储方向(作为四元数)的 transform.rotationPart 似乎在 LHS 中(尽管 3ds max UI 使用 RHS)。 我了解您现在的情况;但即使它是四元数而不是矩阵;您仍然可以将上面的函数建模为相同的函数,除了传递一个四元数并返回另一个模型,而不是传递一个 mat4 模型。我已经有一段时间没有使用 3DS 或 Maya 了。但原理还是一样的。它更多的是一个数学问题以及它们的操作方式。是的,您仍然需要交换 Y 和 Z 轴;但完成后您仍然必须反转它,否则由于 RHS 与 LHS 的差异,您的方向、平移和旋转将不正确。 您几乎可以将四元数视为一个矩阵。简而言之,它是 4D 空间的专用向量,因此它实际上是 1x4 或 4x1 矩阵。唯一的区别是他们的领域。它们的场不是物理位置的实际标量值或沿其平面轴距原点的距离,而是根据特定轴的旋转值,其中 w 分量是任意轴或假想平面轴.

以上是关于3ds max 到 C++/DirectX 应用程序方向转换的主要内容,如果未能解决你的问题,请参考以下文章

如何计算 3ds Max 材质到模型的映射

Unity3.4 将现有的3ds Max模型导入到Unity

Unity3.3 用3ds Max 2015制作模型并将其导入到Unity

如何将代码发送到 3ds Max 脚本侦听器

从 Maya 发送并执行 maxscript 或 python 到 3ds Max

如何将彩色网格从 meshlab 导入统一!(可能到 3ds max)