FbxSDK使用总结

Fbx文件结构太复杂!FbxSDK太难理解!Fbx官网文档功能介绍太不清晰!FbxSDK中的示例程序太冷门,太不解决问题!

网络上找不到能够解决我的痛点的方法。

有相同烦恼的不只我一个人,一个叫 Tianyu Lang 的歪果仁也发出抱怨,并怒喊:

I have searched almost all the corners on the Internet to clarify things so that I can have a clear 
mapping from FBX SDK's data to what I need in a game engine. Since I don't think anyone has ever 
posted a clear and thorough tutorial on how to convert FBX files to custom formats, I will do it. 
I hope this will help people.
他的怒喊深得我心。本着同样的目的,我要写下这篇文章。(他的文章在这里: 传送门

这篇文章不是一个FbxSDK的入门文章,而是一个进阶文章。

在写这篇文章之前,我已经研究FbxSDK一段时间了,也写了如下两篇博文,大家对照着阅读。

1,《编程知识汇总--3D模型文件的通用格式:FBX》,我搜集的值得阅读的文章,传送门

2,《FbxSDK官网文档阅读总结》,在四处碰壁后,我尝试阅读官网文档,传送门



1,ControlPoint 与 PolygonVertex

FbxMesh对象有如下4个函数,

FbxMesh::GetControlPointsCount()
FbxMesh::GetControlPointAt()
FbxMesh::GetPolygonCount()
FbxMesh::GetPolygonVertex()

ControlPoint 与 PolygonVertex 分别是啥东西呢?

举个栗子(例子)就明白了,有一个四边形,它有4个顶点,由2个三角形构成,那么 FbxMesh::GetControlPointsCount() 就返回4,

FbxMesh::GetPolygonCount() 就返回2。

在 ControlPoint 容器中存储了4个顶点的坐标值,存储结构例如:{[x,y,z], [x,y,z], [x,y,z], [x,y,z]}

在 PolygonVertex 容器中存储了6个索引值,存储结构例如:{0,1,2,0,2,3}

所以, ControlPoint 可以理解成“控制点”,四边形中有4个控制点,每个控制点的坐标变化都会使得四边形的形状发生变化;

PolygonVertex 就是”以三角形为基础图元“的图形学中的概念,每个三角形有3个顶点。

如果你已经理解了Fbx中的Layer的概念(例如法线Layer,UV Layer等等),这里可以做一个类比,ControlPoint 容器就好比

Layer中的 DirectArray ,PolygonVertex 容器就好比 IndexArray 。


2,FbxLayerElement::MappingMode()

在提取顶点数据时(例如法线,UV等等),我们经常碰到 FbxLayerElement::MappingMode() 这个函数。

我们只关心 FbxGeometryElement::eByControlPoint 和 FbxGeometryElement::eByPolygonVertex 这两种取值。

举个栗子(例子),立方体中有8个ControlPoint,24个PolygonVertex,我们以法线Layer做示例,

如果每个ControlPoint只对应着一个法线,那么这种 MappingMode 就是 eByControlPoint。

但是,实际情况是,法线应该是与面(三角形)一一对应的,每个ControlPoint参与构建了3个三角形,那么每个ControlPoint

应该对应了3个法线,也即,法线与PolygonVertex是一一对应的,那么这种 MappingMode 就是 eByPolygonVertex。

MappingMode决定了法线了存储方式。


3,FbxLayerElement::ReferenceMode()

Layer中除了MappingMode,还有ReferenceMode。

我们只关心FbxGeometryElement::eDirect 和 FbxGeometryElement::eIndexToDirect 这两种取值。

举个栗子(例子),立方体中有8个ControlPoint,24个PolygonVertex,我们假设法线Layer的MappingMode值为

eByControlPoint,那么法线Layer中有8个法线值,

假设这8个法线值各不相同,那么存储方式类似这样:DirectArray = {法线1,法线2,法线3,法线4,法线5,法线6,法线7,法线8}

那么 ReferenceMode 的值就是 eDirect。

假设法线3,法线4,法线5的值相同,那么Fbx做了优化,把三个值优化成一个值,然后添加索引,存储方式类似这样:

DirectArray = {法线1,法线2,法线3,法线6,法线7,法线8}

IndexArray = {0, 1, 2, 2, 2, 3, 4, 5}

那么 ReferenceMode 的值就是 eIndexToDirect


4,获取动画数据(矩阵数据)有两种方法

在FbxSDK官网文档中提到了 FbxTakeInfo 这个类,然后指出,获取动画矩阵数据有两种方法,

第一种是使用新方法,用递归的方式遍历FbxScene,依次取得 FbxAnimStack ,FbxAnimLayer ,FbxAnimCurve;

第二种是使用旧方法,获取 FbxTakeInfo 对象。

新方法的示例代码:

//----------------------------------------------------------------
void SoFBXManager::ParseAnimation(FbxScene* pSDKScene)
{
	FbxNode* pNode = pSDKScene->GetRootNode();
	const int nStackCount = pSDKScene->GetSrcObjectCount<FbxAnimStack>();
	for (int i = 0; i < nStackCount; ++i)
	{
		FbxAnimStack* pStack = pSDKScene->GetSrcObject<FbxAnimStack>(i);
		const char* szStackName = pStack->GetName();
		const int nLayerCount = pStack->GetMemberCount<FbxAnimLayer>();
		for (int j = 0; j < nLayerCount; ++j)
		{
			FbxAnimLayer* pLayer = pStack->GetMember<FbxAnimLayer>(j);
			const char* szLayerName = pLayer->GetName();
			ParseLayer(pNode, pLayer);
		}
	}
}
//----------------------------------------------------------------
void SoFBXManager::ParseLayer(FbxNode* pNode, FbxAnimLayer* pLayer)
{
	ParseChannel(pNode, pLayer);

	const int nChildCount = pNode->GetChildCount();
	for (int k = 0; k < nChildCount; ++k)
	{
		ParseLayer(pNode->GetChild(k), pLayer);
	}
}
//----------------------------------------------------------------
void SoFBXManager::ParseChannel(FbxNode* pNode, FbxAnimLayer* pLayer)
{
	FbxAnimCurve* pCurve = pNode->LclTranslation.GetCurve(pLayer, FBXSDK_CURVENODE_COMPONENT_X);
	if (pCurve == 0)
	{
		return;
	}

	FbxTime kTime;
	char lTimeString[256];

	const int nKeyCount = pCurve->KeyGetCount();
	for (int i = 0; i < nKeyCount; ++i)
	{
		kTime = pCurve->KeyGetTime(i);
		const FbxAMatrix& kMatLocal = pNode->EvaluateLocalTransform(kTime);
		const FbxAMatrix& kMatGlobal = pNode->EvaluateGlobalTransform(kTime);
		//
		kTime.GetTimeString(lTimeString, FbxUShort(256));
		SoLogDebug("FBXTime : %s", lTimeString);
	}
}

旧方法的示例代码:

FbxAnimStack* currAnimStack = mFBXScene->GetSrcObject<FbxAnimStack>(0);
FbxString animStackName = currAnimStack->GetName();
mAnimationName = animStackName.Buffer();
FbxTakeInfo* takeInfo = mFBXScene->GetTakeInfo(animStackName);
FbxTime start = takeInfo->mLocalTimeSpan.GetStart();
FbxTime end = takeInfo->mLocalTimeSpan.GetStop();
mAnimationLength = end.GetFrameCount(FbxTime::eFrames24) - start.GetFrameCount(FbxTime::eFrames24) + 1;
Keyframe** currAnim = &mSkeleton.mJoints[currJointIndex].mAnimation;

for (FbxLongLong i = start.GetFrameCount(FbxTime::eFrames24); i <= end.GetFrameCount(FbxTime::eFrames24); ++i)
{
	FbxTime currTime;
	currTime.SetFrame(i, FbxTime::eFrames24);
	*currAnim = new Keyframe();
	(*currAnim)->mFrameNum = i;
	FbxAMatrix currentTransformOffset = inNode->EvaluateGlobalTransform(currTime) * geometryTransform;
	(*currAnim)->mGlobalTransform = currentTransformOffset.Inverse() * currCluster->GetLink()->EvaluateGlobalTransform(currTime);
	currAnim = &((*currAnim)->mNext);
}

我看到了两篇博客都是使用旧方法。

这篇帖子对新方法与旧方法的做了一点区别:http://gamedev.stackexchange.com/questions/59419/c-fbx-animation-importer-using-the-fbx-sdk

新方法的缺陷是,你不知道该动画的持续时长。使用旧方法,你能够得到动画的持续时长,然后根据你

的需要,把该动画切割成若干帧,把每帧的矩阵保存起来。

每个Fbx文件中只能存储一个FbxTakeInfo,也即只能存储一个动画,例如只能存储一个走路动画或者一个跑步动画。

有一个外国团队做了一个插件叫FBX Multi Take (3DS Max),可以把多个动画拼接成一个动画,让fbx文件存储拼接之后的动画。

该插件是收费的,官网在这里 。

Fbx文件中可以只包含mesh顶点数据,也可以只包含骨骼动画数据。一个角色模型,可以把Mesh顶点数据保存成一个fbx文件,

把所有的骨骼动画分别保存成一个fbx文件。





  • 16
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
### 回答1: FBX SDK for Unity是为Unity游戏引擎设计的一种软件开发工具包(SDK)。FBX SDK是由Autodesk开发的一套用于处理和管理FBX文件格式的工具。FBX是一种常见的3D文件格式,用于在不同的3D应用程序之间进行互操作。使用FBX SDK,开发人员可以轻松地将FBX文件导入到Unity中,以便在游戏中使用FBX SDK for Unity提供了一些功能,使开发人员能够更好地在Unity中处理和管理FBX文件。首先,它允许开发人员读取和写入FBX文件。开发人员可以使用FBX SDK在Unity中读取FBX文件的内容,例如模型、材质、动画等,并将其转换为Unity能够使用的数据格式。相反地,开发人员还可以使用FBX SDK将Unity中的内容导出为FBX文件,以便在其他应用程序中使用。 其次,FBX SDK for Unity还提供了一些用于编辑和处理FBX文件的工具和函数。开发人员可以使用FBX SDK更改模型的层次结构、材质属性、动画轨迹等。这使得开发人员能够更好地控制和调整FBX文件以适应他们的游戏需求。 此外,FBX SDK for Unity还提供了一些用于导入和导出FBX文件的辅助功能。开发人员可以使用FBX SDK处理FBX文件的单位、坐标系、标记和动画设置等。这些功能可以让开发人员更加方便地与FBX文件进行交互,并确保在不同应用程序之间进行正确的数据转换。 总之,FBX SDK for Unity是一个非常有用的工具包,使开发人员能够更好地在Unity中处理和管理FBX文件,并与其他3D应用程序进行交互和互操作。它为开发人员提供了更多的灵活性和控制权,以实现他们的游戏开发目标。 ### 回答2: FBX SDK for Unity是一款Unity引擎的插件,用于导入和导出FBX文件格式。FBX文件是一种用于在不同3D软件之间交换模型、动画、材质等数据的通用文件格式。 FBX SDK for Unity提供了许多有用的功能和工具,可以帮助开发者更轻松地在Unity中使用FBX文件。通过该插件,开发者可以导入FBX文件,并将其转换为Unity中可用的资源,如3D模型、骨骼动画、材质、贴图等。同时,开发者也可以将Unity中的资源导出为FBX文件,以便与其他支持FBX格式的软件进行交流和共享。 FBX SDK for Unity还支持模型的网格优化、纹理压缩和骨骼动画的精细调整。通过可以控制导入和导出设置,开发者可以根据需求对FBX文件进行自定义处理,以获得更好的效果和性能。 除此之外,FBX SDK for Unity还提供了一些扩展工具,用于处理FBX文件中的蒙皮、法线、顶点色等数据,以及支持多个FBX文件的批量操作。 总之,FBX SDK for Unity是一款功能强大的插件,提供了导入和导出FBX文件的功能,以帮助Unity开发者更好地使用FBX文件,并加强与其他3D软件的兼容性和交互性。无论是从外部软件导入资源,还是将Unity资源导出到其他软件使用FBX SDK for Unity都是一个非常有用的工具。 ### 回答3: FBX SDK for Unity是一种用于Unity开发环境的软件开发工具包,用于处理和加载FBX文件格式。FBX文件是一种常用的3D模型和动画文件格式,广泛用于游戏开发和动画制作等领域。 通过FBX SDK for Unity,开发者可以在Unity中轻松地导入、加载和展示来自于FBX文件的3D模型和动画。这个SDK提供了一系列功能强大的工具和接口,可以处理FBX文件中的各种元素,如网格、材质、动画、骨骼等等。开发者可以使用这些工具和接口来编辑、控制和操纵FBX模型和动画,在游戏中实现各种效果和功能。 FBX SDK for Unity还支持多种模型和动画文件的转换和导出功能。这意味着开发者可以将FBX文件转换为其他格式,如Unity支持的模型和动画格式,以便在不同的开发环境中使用。同时,也可以将Unity中创建的模型和动画导出为FBX文件,用于与其他软件或平台进行交互和共享。 FBX SDK for Unity为开发者提供了更多的选择和自由,使他们能够更灵活地使用FBX文件中的资源。通过这个SDK,开发者可以更加高效地创建和操作3D模型和动画,加快开发进度,并实现更具创意和吸引力的游戏效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值