【发布时间】:2017-05-04 19:26:49
【问题描述】:
我们正在使用 OpenGL 开发渲染器。其中一项功能是能够导入 FBX 模型。导入器模块使用 FBX SDK (2017)。 现在,众所周知,OpenGL是一个右手坐标系。即向前是从正到负,右是右,上向量是向上。在我们的应用程序中,前向向量的要求是正的,类似于DirectX。 在应用程序级别,我们通过将投影矩阵的 Z 缩放为 -1 来设置它。 使用 glm 数学:
glm::mat4 persp = glm::perspectiveLH (glm::radians (fov), width / height, mNearPlane, mFarPlane);
这和这样做是一样的:
glm::mat4 persp = glm::perspective (glm::radians (fov), width / height, mNearPlane, mFarPlane);
persp = glm::scale (persp , glm::vec3 (1.0f, 1.0f, -1.0f));
到目前为止一切顺利。有趣的部分来自于我们导入 FBX 模型。
如果使用
FbxAxisSystem::OpenGL.ConvertScene(pSceneFbx);
然后用Node的全局变换来变换顶点,计算如下:
FbxSystemUnit fbxUnit = node->GetScene()->GetGlobalSettings().GetSystemUnit();
FbxMatrix globalTransform = node->EvaluateGlobalTransform();
glm::dvec4 c0 = glm::make_vec4((double*)globalTransform.GetColumn(0).Buffer());
glm::dvec4 c1 = glm::make_vec4((double*)globalTransform.GetColumn(1).Buffer());
glm::dvec4 c2 = glm::make_vec4((double*)globalTransform.GetColumn(2).Buffer());
glm::dvec4 c3 = glm::make_vec4((double*)globalTransform.GetColumn(3).Buffer());
几何面是倒置的。 (OpenGL中默认的逆时针缠绕顺序)
如果使用 DirectX 转换器:
FbxAxisSystem::DirectX.ConvertScene(pSceneFbx);
模型既倒置又倒置。
OpenGL 转换:
DirectX 转换:
我们发现解决这个问题的方法是,否定该矩阵中第 3 列的 Z。并且还围绕 Z 轴旋转 180 度。否则模型的前面将是它的背面(是的,听起来很棘手,但它在比较 OpenGL 和 DirectX 坐标系差异时有意义。
所以,整个“转换”矩阵现在看起来像这样:
FbxSystemUnit fbxUnit = node->GetScene()->GetGlobalSettings().GetSystemUnit();
FbxMatrix globalTransform = node->EvaluateGlobalTransform();
glm::dvec4 c0 = glm::make_vec4((double*)globalTransform.GetColumn(0).Buffer());
glm::dvec4 c1 = glm::make_vec4((double*)globalTransform.GetColumn(1).Buffer());
glm::dvec4 c2 = glm::make_vec4((double*)globalTransform.GetColumn(2).Buffer());
glm::dvec4 c3 = glm::make_vec4((double*)globalTransform.GetColumn(3).Buffer());
glm::mat4 mat =
glm::mat4(1, 0, 0, 0,
0, 1, 0, 0,
0, 0, -1, 0,//flip z to get correct mesh direction (CCW)
0, 0, 0, 1);
//in this case the model faces look right dir ,but the model
//itself needs to be rotated because the camera looks at it from the
//wrong direction.
mat = glm::rotate(mat, glm::radians(180.0f), glm::vec3(0.0f, 0.0f, 1.0f));
glm::mat4 convertMatr = glm::mat4(c0, c1, c2, c3) *mat;
然后,使用该矩阵转换 FBX 模型的顶点会得到所需的结果:
顺便说一句,我们如何知道想要的结果?我们将其与 Unity3D 游戏引擎进行比较。
现在,这是我第一次被要求执行这样的 hack。感觉就像是一个非常讨厌的 hack。特别是当涉及到蒙皮网格时,我们需要使用转换矩阵转换骨骼矩阵、姿势矩阵和什么不...
问题是,在这种情况下,当我们需要保持 CCW 缠绕顺序并在 OpenGL 中具有正向前进时。这是正确进行几何变换的唯一方法吗?
(3d模型源为3DsMax,Y-up导出)
【问题讨论】:
-
"现在,众所周知,OpenGL 是一个右手坐标系。" 我们知道吗?我很确定 OpenGL 使用你喜欢的任何坐标系。
-
@NicolBolas,当然!然后我需要调整几何形状以使其看起来正确,或更改缠绕顺序。顺便说一句,如果我在我的情况下更改为 CW,则网格沿 X 轴翻转。
-
转换左坐标右坐标总是涉及轴翻转和缠绕顺序反转,通过改变缠绕顺序状态或翻转几何中的索引。这里没有什么新东西,GL/DX 也不是什么,因为我们使用着色器,唯一的要求是在单位立方体中提供投影顶点(唯一的 GL 和 DX 不同,它们在它的可见 Z 范围内有所不同)。
-
@galop1n 所以你只需确认我正在做的是“官方”的方式吗?