从*.FBX文件中读取并展示动画

9

我想从 fbx 文件中读取 3D 模型,并在 iPhone 上的 openGL es 2.0 引擎中显示它(不使用 Unity),并且我还想显示读取的 3D 对象的动画。

如何从 fbx 文件获取动画?

目前,我能够获取姿势名称列表,这些名称似乎是带有变换矩阵的,以及层、堆栈、层中所有姿势的完整列表和许多曲线。

如何将所有这些信息组合起来以显示正确的动画?

我还尝试解析 TakeInfo 中的一些信息,但对我来说结果有点奇怪,例如:

    FbxTakeInfo *ltakeInfo  =  pScene->GetTakeInfo(lAnimStack->GetName());
    FbxTime start = ltakeInfo->mLocalTimeSpan.GetStart();
    FbxTime end = ltakeInfo->mLocalTimeSpan.GetStop();

    self.startTime = start.GetSecondDouble();
    self.endTime = end.GetSecondDouble();

这里我得到了每个解析层的 start = 0end = 0.014,所以我猜测这是不正确的(我想要显示的 fbx 文件包含一个网格和简单的5秒持续动画)。

更新

经过几个小时的调查,我得到了以下结果:

为了参考,这是我想要显示的测试对象的结构:

enter image description here

在这里,您可以看到很多骨头(更具体地说-19个)。如上所述,我能够在列表中获取19个带动画的obj(例如骨骼/obj的名称),以及每个组内有151帧的19个曲线组(帧速率为30,正好是5秒的动画-30 * 5 = 150 +1最后的单位矩阵)。
如果我尝试逐个使用每个曲线组来应用于我的网格(我只能解析一个网格),我会看到应用于所有网格的不同部分的动画(例如垂直旋转或水平平移),因此我认为这些曲线在每个组中应该被准确地应用于特定的骨骼,结果我将获得我的网格的动画。问题是我不知道如何仅对选定的骨骼顶点部分进行动画处理。
现在的问题是如何将分成单独的骨骼的所有动画应用于整个obj(因为我只有一个网格)?
如何从包含所有曲线组的列表中获取每个帧的1个全局曲线列表?
更新2
感谢@codetiger的建议,我遵循评论中提供的链接中的说明,并使用该技术检索了特定骨骼材质的列表,包括开始和结束时间以及所需的变换,但这与我之前使用曲线获得的结果几乎相同——唯一的区别是,对于曲线,我应该从9个曲线(用于x y z的平移/缩放/旋转)创建材料,而不是使用完整矩阵,但问题仍然存在——如何将它们组合在一个全局矩阵中?
我使用的代码(找到了一些链接):
FbxNode* modelNode = _fbxScene->GetRootNode();
FbxAMatrix geometryTransform = GetGeometryTransformation(modelNode);
for (unsigned int deformerIndex = 0; deformerIndex < numOfDeformers; ++deformerIndex) {
    FbxSkin* currSkin = reinterpret_cast<FbxSkin*>(mesh->GetDeformer(deformerIndex, FbxDeformer::eSkin));
    if (!currSkin) {
        continue;
    }
    unsigned int numOfClusters = currSkin->GetClusterCount();
    for (unsigned int clusterIndex = 0; clusterIndex < numOfClusters; ++clusterIndex) {
        FbxCluster* currCluster = currSkin->GetCluster(clusterIndex);
        std::string currJointName = currCluster->GetLink()->GetName();

        FbxAMatrix transformMatrix;
        FbxAMatrix transformLinkMatrix;
        FbxAMatrix globalBindposeInverseMatrix;

        currCluster->GetTransformMatrix(transformMatrix);   
        currCluster->GetTransformLinkMatrix(transformLinkMatrix);   
        globalBindposeInverseMatrix = transformLinkMatrix.Inverse() * transformMatrix * geometryTransform;

        FbxAnimStack* currAnimStack = _fbxScene->GetSrcObject<FbxAnimStack>(0);
        FbxString animStackName = currAnimStack->GetName();
        char *mAnimationName = animStackName.Buffer();
        FbxTakeInfo* takeInfo = _fbxScene->GetTakeInfo(animStackName);
        FbxTime start = takeInfo->mLocalTimeSpan.GetStart();
        FbxTime end = takeInfo->mLocalTimeSpan.GetStop();
        FbxLongLong mAnimationLength = end.GetFrameCount(FbxTime::eFrames24) - start.GetFrameCount(FbxTime::eFrames24) + 1;

        for (FbxLongLong i = start.GetFrameCount(FbxTime::eFrames24); i <= end.GetFrameCount(FbxTime::eFrames24); ++i) {
            FbxTime currTime;
            currTime.SetFrame(i, FbxTime::eFrames24);

            FbxAMatrix currentTransformOffset = modelNode->EvaluateGlobalTransform(currTime) * geometryTransform;
            FbxAMatrix mat = currentTransformOffset.Inverse() * currCluster->GetLink()->EvaluateGlobalTransform(currTime);

        }
    }
}

这里我收到的矩阵是121而不是151 - 但是一些矩阵变换的持续时间比1帧的绘制时间长,所以我认为这里的数量也是正确的。
float duration = end.GetSecondDouble() - start.GetSecondDouble(); //return 5 as and expected

我猜测在 Autodesk SDK 中,有一种方法可以获得每个绘制调用的全局变换。你有什么建议吗?这可行吗?
为任何能够描述如何在iPhone上使用Autodesk SDK和openGLES 2.0显示动画的人添加悬赏...(抱歉,Facebook打错了)
这是我的翻译:

以下是我能获取到的内容

Blender 中的原始对象

enter image description here

如果我单独绘制骨骼(使用同一VBO,但根据每个骨骼的不同变换和索引进行绘制),

enter image description here

enter image description here


请查看此链接:http://gamedev.stackexchange.com/questions/59419/c-fbx-animation-importer-using-the-fbx-sdk - codetiger
我看到了这个链接 - 尝试使用描述的方法获取mats,但是我收到的所有东西都是Identity矩阵... 但是根据我的理解,应该是针对我每个具有特定起始和结束时间的网格的全局转换的mats - hbk
我也尝试在Blender和Autodesk的FBX Review应用程序中播放文件 - 所有工作都正确...关于堆栈和图层的使用,您能否建议一些如何处理这些项目的方法? - hbk
你读取了文件中的动画信息吗?赏金是为了向您提供有关如何在iOS上呈现动画的信息。 - codetiger
我也可以分享我的代码,使我所做的一切更加清晰 - 我想我可能错过了一些重要部分,但不确定... - hbk
显示剩余4条评论
1个回答

4

这里是如何在OpenGL ES中渲染动画网格的方法。这将为您提供有关需要从文件中读取哪些详细信息的公平信息。

方法1:(GPU蒙皮)

此方法仅适用于基于硬件功能的有限数量的骨骼。通常取决于您可以发送到着色器的矩阵数量。

使用BindAttributes将网格信息绑定到GPU上,然后通过uniforms将矩阵发送到着色器。

步骤1:读取所有骨骼矩阵并创建一个矩阵数组,然后通过uniforms将该数据发送到着色器。

步骤2:在顶点着色器中,像下面的着色器一样计算gl_position。

attribute vec3 vertPosition;
attribute vec3 vertNormal;
attribute vec2 texCoord1;
attribute vec3 vertTangent;
attribute vec3 vertBitangent;
attribute vec4 optionalData1;
attribute vec4 optionalData2;

uniform mat4 mvp, jointTransforms[jointsSize];

void main()
{
    mat4 finalMatrix;

    int jointId = int(optionalData1.x);
    if(jointId > 0)
        finalMatrix = jointTransforms[jointId - 1] * optionalData2.x;

    jointId = int(optionalData1.y);
    if(jointId > 0)
        finalMatrix = finalMatrix + (jointTransforms[jointId - 1] * optionalData2.y);

    jointId = int( optionalData1.z);
    if(jointId > 0)
        finalMatrix = finalMatrix + (jointTransforms[jointId - 1] * optionalData2.z);

    jointId = int( optionalData1.w);
    if(jointId > 0)
        finalMatrix = finalMatrix + (jointTransforms[jointId - 1] * optionalData2.w);

    gl_Position = mvp * finalMatrix * vec4(vertPosition, 1.0);
}

在这个着色器中,我已经将权重图信息发送到了属性optionalData1和optionalData2中。数据被打包成这样:(BoneId1,BoneId2,BoneId3,BoneId4)和(Weight4Bone1,Weight4Bone2,Weight4Bone3,Weight4Bone4)。所以在这种情况下,每个属性受影响的骨骼数量最多为4个。片段着色器部分是通常的。
方法2:(CPU蒙皮)
如果您无法接受GPU蒙皮的限制,则唯一的方法是在CPU端进行计算。
步骤1:通过乘以影响顶点的骨骼矩阵计算当前帧中的顶点位置。
步骤2:收集当前帧的新位置,并将信息发送到GPU中的顶点属性中。
步骤3:在每一帧中重新计算新的顶点位置并更新属性缓冲区。
这种方法会使计算负载转移到CPU上。

我猜我会采用第二种方法,但不是通过直接获取矩阵,而是通过从层中获取动画曲线并从这些曲线(曲线类似于tx ty tz sx sy sz rx ry rz)创建变换矩阵。当我尝试使用从函数(如GetTransformMatrix和其他函数)中获得的聚类的矩阵时,在屏幕上看到一些奇怪的东西... - hbk
我接受你的答案 - 因为这是一个很好的起点,但是说实话,我希望有人遇到过与我相同的问题,并能够详细地建议如何使用从fbx文件中提取的骨骼进行动画制作... - hbk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接