FBX人物动画——导出骨骼动画树

导出骨骼动画树

对FBX人物动画文件的骨骼动画节点树中每一个节点的动画帧进行导出时,导出数据为骨骼local space中的offset,传统的导出方式:

out.position[frame] = in.position[frame];
out.rotation[frame] = in.rotation[frame];
out.scale[frame] = in.scale[frame];

但这样在实际应用在导出FBX人物动画场景下可能会出现严重的问题(3dsmax默认使用单位是inch)

1.父节点坐标系的Scaling变化。

如下图,A是B的父节点,那么A节点的坐标系进行Scaling变化时,B是否要变化呢?如果不变,那么可以想象海贼王路飞的伸缩手臂,当只有锁骨部分无限拉长,且其他部位纹丝不动,测试,它是无法像动漫里一样拉伸的。所以当父节点(骨骼绑定在节点上,可以理解为骨骼继承了节点)出现Scale变化时,是需要引起子节点的变化,即A节点Scaling变化,那么所有的子节点都要进行Scaling变化,那么如何变化呢?当然是通过程序运算而来=-=。FBX骨骼动画文件存储的KeyFrame数据都是相对于当前骨骼的局部坐标系,我们需要根据当前节点的Scale作为子节点的全局缩放,一路递归运算…

在这里插入图片描述

FBX骨骼动画文件的KeyFrame信息:
在这里插入图片描述

2.单位问题(1英寸=0.0254米)。

FBX的keyFrame数据导出时,英寸和米的单位换算也会造成动画G掉。当你使用FBX SDK提供的方法将英寸单位转为米后,移动1英寸和移动0.0254米是一样,但Scaling 1英寸和Scaling 0.0254米是一样的嘛?不是的。所以确定好动画KeyFrame的单位变化量也是一件至关重要的事情。

3.解决方式

综上,对于人物动画的导出,解决方式应该具体针对父节点坐标系的Scaling变化需要引起子节点坐标系的Scaling变化,体现在Position和Scale。以及需要注意单位变化量。话不多说,上代码。

代码

动画track的处理

void export(TrackDesc* in, TrackDesc* out, uint32 frame)
{
	size_t childCount = in->GetChildrenCount();
	if (childCount == 0)
		return;
	// 英寸的单位变化量
	const float UNIT_CONVERSION = 0.0254f;
	for (size_t i = 0; i < childCount; ++i)
	{
		TrackDesc* outChild = out->GetChild(i);
		TrackDesc* inChild = in->GetChild(i);
		outChild->positions[frame] = inChild->positions[frame] * globalScale;
		outChild->rotations[frame] = inChild->rotations[frame];
		outChild->scalings[frame] = outChild->scalings[frame]/ UNIT_CONVERSION;
		// 当前节点的局部坐标系为子节点的全局坐标系
		export(inChild, outChild, frame, localScale);
	}
}

得到的是应用了全局缩放后的骨骼局部坐标系下的KeyFrame信息。
骨骼的处理,需要从世界坐标系转化到骨骼的局部坐标系。

Bone bone;
Bone parent = bone.getParent();
bone.scale = bone.scale / parent.scale;
bone.rotation = parent.rotation.inverse() * bone.rotation;
bone.translation =  parent.rotation.inverse() * (bone.translation - parent.translation) / parent.scale();

补充部分

如何实现多个动画Track共用一个骨骼文件=》提供统一的骨骼参考标准T-pose形态下的骨骼。所有动画track数据基于T-pose下的骨骼计算offset值存在track中,这样就不需要多个动画,每一个都需要单独的骨骼的文件存储。

			Vector3		bonePos		= targetBone->getPosition();
			Quaternion	boneQuat	= targetBone->getOrientation();
			Vector3		boneScale	= targetBone->getScale();

			for (uint32 j = 0; j < frameCount; ++j)
			{
				Vector3		&framePos = targetTrack->positions[j];
				Quaternion	&frameOri = targetTrack->rotations[j];
				Vector3		&frameSca = targetTrack->scalings[j];

				framePos = framePos - bonePos;
				frameOri = boneQuat.Inverse() * frameOri;
				frameOri.Normalize();
				frameSca = frameSca / boneScale;
			}
			trackStack.push_back(targetTrack);

这里的坐标系都是局部坐标系,在bone space中,位移的计算不需要考虑scale和rotation,因为它不受父节点的影响。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值