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 应用程序方向转换的主要内容,如果未能解决你的问题,请参考以下文章
Unity3.4 将现有的3ds Max模型导入到Unity
Unity3.3 用3ds Max 2015制作模型并将其导入到Unity