我想从fbx
文件中读取3d模型,并在iPhone上的openGL es 2.0
引擎中显示它(不使用Unity
),我还要显示读取3d对象的动画。< / p>
如何从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 = 0
和end = 0.014
,所以我猜这是不正确的(我要展示的fbx
文件包含1个网格,简单的5秒持续时间动画)。
更新
经过几个小时的调查后,我得到了下一件事:
作为参考,这是我想要显示的测试对象的结构:
在这里你可以看到很多骨头(更具体 - 19) 我能够得到(如上所述)列表中的19个动画obj(如骨骼/ obj的名称)和每组151帧内的19组曲线(帧率30正好是动画的5秒。 - 30 * 5 = 150 + 1最后一个单位矩阵)。
如果我尝试逐个使用每个曲线组到我的网格(我只能解析1个网格)我看到网格的不同部分的动画应用于所有网格(例如垂直旋转或水平平移),所以我我认为每组中的这条曲线应该完全应用于特定的骨骼,因此我将获得我的网格动画。问题是我不知道如何仅为选定的骨骼顶点部分设置动画。
现在问题是如何将所有动画分成几个特定于骨骼的组到整个obj(因为我只有一个网格)?
如何从包含所有曲线组的列表中为每个帧获取1个全局曲线列表?
UPDATE2
感谢@codetiger建议,我按照评论中提供的链接中的说明进行操作,并且通过该技术,我能够检索具有开始和结束时间以及所需变换的特定于骨骼的列表,但这是几乎与我之前使用曲线相同 - 唯一的区别是曲线我应该从9条曲线创建垫子(平移/缩放/旋转为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);
}
}
}
这里我收到121矩阵而不是151 - 但是一些矩阵变换的持续时间超过1帧抽取的持续时间,所以q-ty在这里我认为也是正确的
float duration = end.GetSecondDouble() - start.GetSecondDouble(); //return 5 as and expected
我想那Autodesk SDK
有一种方法可以为每个drawCall获得1个全局变换
有什么建议吗?这可能吗?
为任何能够描述如何在OpenGLES 2.0中使用Autodesk SDK在iPhone上显示动画的人添加赏金......(抱歉拼写错误而不是Facebook )
这是我能够获得的
blender
如果我单独绘制骨骼(相同的VBO具有不同的变换,并且每个骨骼只有相应的指数)
答案 0 :(得分:4)
以下是在OpenGL ES中渲染动画网格的方法。这将为您提供有关您需要从文件中读取的详细信息的票价信息。
方法1 :( 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);
}
在这个着色器中,我在属性optionalData1&amp;中发送了权重绘制信息。 optionalData2。数据打包如下:(BoneId1,BoneId2,BoneId3,BoneId4)和(Weight4Bone1,Weight4Bone2,Weight4Bone3,Weight4Bone4)。因此,在这种情况下,您受限于最多4个骨骼影响每个属性。碎片着色器部分是常见的。
方法2 :( CPU外观)
如果您无法忍受GPU蒙皮的限制,那么唯一的方法就是在CPU端进行计算。
步骤1:通过将属于影响顶点的骨骼的矩阵相乘来计算当前帧中的顶点位置。
步骤2:收集当前帧的新位置,并将信息发送到顶点属性中的GPU。
步骤3:重新计算每个帧中的新Vertex位置并更新属性缓冲区。
此方法将计算负荷带到CPU。