从*.FBX文件中读取和显示动画

gbk*_*gbk 9 animation objective-c++ ios fbx opengl-es-2.0

我想从fbx文件中读取3d模型并openGL es 2.0在iPhone上的引擎内显示它(不使用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();
Run Code Online (Sandbox Code Playgroud)

在这里我得到start = 0end = 0.014为每个解析的图层,所以我猜这是不正确的(fbx我要显示的文件包含1个网格与简单的5秒持续时间动画).


更新

经过几个小时的调查后,我接下来的事情:

作为参考,这是我想要显示的测试obj的结构:

在此输入图像描述

在这里你可以看到很多骨头(更具体 - 19)我能够得到(如上所述)列表中的19个动画obj(如骨骼/ obj的名称)和每组151帧内的19组曲线(具有帧速率) 30正好5秒的动画 - 30*5 = 150 + 1最后一个单位矩阵).

如果我尝试逐个使用每个曲线组到我的网格(我只能解析1个网格)我看到网格的不同部分的动画应用于所有网格(例如垂直旋转或水平平移),所以我认为这个每组中的曲线应该精确地应用于特定骨骼,因此我将获得我的网格动画.问题是我不知道如何仅为选定的骨骼顶点部分设置动画.

现在的问题是如何应用这个所有动画分为将特定于骨的组分离到整个obj(因为我只有一个网格)?

如何从包含所有曲线组的列表中为每个帧获得1个全局曲线列表?


UPDATE2

感谢@codetiger的建议,我遵循评论中提供的链接中的指令,并且通过该技术,我能够检索具有开始和结束时间以及所需变换的骨骼特定垫片列表,但这几乎与我之前使用曲线相同 - 与曲线的唯一区别我应该从9条曲线创建mat(对于xyz进行平移/缩放/旋转)而不是使用完整矩阵,但问题仍然存在 - 如何将它们组合在1个全局矩阵中?

我使用的代码(找到几个链接):

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

        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在这里我收到121矩阵而不是151 - 但是一些矩阵变换的持续时间超过1帧抽取的持续时间,所以这里的q-ty我认为也是正确的

float duration = end.GetSecondDouble() - start.GetSecondDouble(); //return 5 as and expected
Run Code Online (Sandbox Code Playgroud)

我想Autodesk SDK有一种方法可以为每个drawCall获得1个全局变换

有什么建议?这可能吗?


为任何可以描述如何在OpenGLES 2.0中使用Autodesk SDK在iPhone上显示动画的人添加赏金...(抱歉拼写错误而不是Facebook)


在这里我能得到什么

原始对象 blender

在此输入图像描述

如果我分别绘制骨骼(相同的VBO具有不同的变换,并且每个骨骼只有相应的指数)

在此输入图像描述

在此输入图像描述

cod*_*ger 4

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

方法一:(GPU换肤)

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

使用 BindAttributes 将网格信息绑定到 GPU 一次,并将矩阵以制服形式发送到着色器。

第 1 步:读取所有骨骼矩阵并创建一个矩阵数组,并将这些数据发送到制服中的着色器。

步骤 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);
}
Run Code Online (Sandbox Code Playgroud)

在此着色器中,我已将权重绘制信息发送到属性 optionData1 和 optalData2 中。数据的打包方式如下:(BoneId1、BoneId2、BoneId3、BoneId4) 和 (Weight4Bone1、Weight4Bone2​​、Weight4Bone3、Weight4Bone4)。因此,在这种情况下,影响每个属性的骨骼最多为 4 个。片段着色器部分是常见的。

方法二:(CPU换肤)

如果您无法忍受 GPU 蒙皮的限制,那么唯一的方法就是在 CPU 端进行计算。

步骤1:通过乘以属于影响顶点的骨骼的矩阵来计算当前帧中的顶点位置。

步骤 2:收集当前帧的新位置并将信息发送到顶点属性中的 GPU。

步骤 3:重新计算每一帧中的新顶点位置并更新属性缓冲区。

该方法将计算负载转移给CPU。