C++11 将动画关键点轨迹导入Maya 我有一个人类双足动画文件格式,我想用C++ API编程到玛雅中。
动画文件格式与的类似 对于每个关节,都有一系列多达60个三维矢量关键点(用于描述关节的平移)和60个四元数关键点(用于描述关节的旋转)。每个关节都保证有相同数量的键(或根本没有键) 可以指定或更改动画的长度(以秒为单位的时间)(例如,对于每秒30帧的动画,可以将60个关键点设置为在2秒内发生) 关节的平移和旋转在每一帧沿骨架树向下传播,生成动画 这是一个样品。有关数据结构的附加说明由日志记录工具添加。为了简洁起见,我把键截断了C++11 将动画关键点轨迹导入Maya 我有一个人类双足动画文件格式,我想用C++ API编程到玛雅中。,c++11,animation,maya-api,C++11,Animation,Maya Api,动画文件格式与的类似 对于每个关节,都有一系列多达60个三维矢量关键点(用于描述关节的平移)和60个四元数关键点(用于描述关节的旋转)。每个关节都保证有相同数量的键(或根本没有键) 可以指定或更改动画的长度(以秒为单位的时间)(例如,对于每秒30帧的动画,可以将60个关键点设置为在2秒内发生) 关节的平移和旋转在每一帧沿骨架树向下传播,生成动画 这是一个样品。有关数据结构的附加说明由日志记录工具添加。为了简洁起见,我把键截断了 Bone Bip01 Parent null 60
Bone Bip01
Parent null
60 Position Keys
0 0.000000 4.903561 99.240829 -0.000000
1 0.033333 4.541568 99.346550 -2.809127
2 0.066667 4.182590 99.490318 -5.616183
... (truncated)
57 1.366667 5.049816 99.042770 -116.122604
58 1.400000 4.902135 99.241692 -118.754120
59 1.400000 4.902135 99.241692 -118.754120
60 Rotation Keys
0 0.000000 -0.045869 0.777062 0.063631 0.624470
1 0.033333 -0.043855 0.775018 0.061495 0.627400
2 0.066667 -0.038545 0.769311 0.055818 0.635212
... (truncated)
57 1.366667 -0.048372 0.777612 0.065493 0.623402
58 1.400000 -0.045869 0.777062 0.063631 0.624470
59 1.400000 -0.045869 0.777062 0.063631 0.624470
Bone Bip01_Spine
Parent Bip01
60 Position Keys
...
60 Rotation Keys
...
在C++中,我现在的数据结构对应于:
std::无序映射平移KeyTrack
用于将一组平移向量映射到相应的骨骼
std::无序映射旋转KeyTrack
用于将一组旋转四元数映射到相应的骨骼
附加说明:有些骨骼不相对于其父骨骼移动;这些骨骼根本没有关键点(但有一个包含0个关键点的条目)。
还有一些骨骼只有旋转或位置关键点。
骨架数据存储在一个单独的文件中,我已经可以使用MFnIkJoint将其读入Maya
动画文件中指定的骨骼与该骨骼数据中的骨骼比例为1:1
现在,我想将此动画数据导入Maya。不过,我不明白
特别是,MFnAnimCurve函数集addKeyFrame
或addKey
只接受绑定到时间键的单个浮点值,而我有一个向量和四元数列表。MFnAnimCurve也接受“切线”;阅读文档后,我仍然不确定如何将我拥有的数据转换为这些切线
我的问题是:如何将我拥有的数据转换为Maya能够理解的内容
我更了解示例,因此一些示例代码将很有帮助。因此,经过几天的反复试验,并检查了互联网上的一些代码片段,我终于想出了一些可行的方法 鉴于上述
TranslationKeyTrack
和RotationKeyTrack
遍历骨架。对于每个接头
MStatus status;
MItDag dagIter(MItDag::kDepthFirst, MFn::kJoint, &status);
for (; !dagIter.isDone(); dagIter.next()) {
MDagPath dagPath;
status = dagIter.getPath(dagPath);
MFnIkJoint joint(dagPath);
string name_key = joint.name().asChar();
// Set initial position, and the translation AnimCurve keys.
if (TranslationKeyTrack.find(name_key) != TranslationKeyTrack.end()) {
auto pos = TranslationKeyTrack[name_key][0];
joint.setTranslation(MVector(pos.x, pos.y, pos.z), MSpace::kTransform);
setPositionAnimKeys(dagPath.node(), positionTracks[name_key]);
}
// Set initial orientation, and the rotation AnimCurve keys.
if (RotationKeyTrack.find(name_key) != RotationKeyTrack.end()) {
auto rot = rotationTracks[name_key][0];
joint.setOrientation(rot.x, rot.y, rot.z, rot.w);
setRotationAnimKeys(dagPath.node(), RotationKeyTrack[name_key]);
}
}
为简洁起见,我将省略显示setPositionAnimKeys
,而仅显示setRotationAnimKeys
。然而,两者的想法是相同的。请注意,我使用了kAnimCurveTL
进行翻译跟踪
void MayaImporter::setRotationAnimKeys(MObject joint, const vector<Quaternion>& rotationTrack) {
if (rotationTrack.size() < 2) return; // Check for empty tracks.
MFnAnimCurve rotX, rotY, rotZ;
setAnimCurve(joint, "rotateX", rotX, MFnAnimCurve::kAnimCurveTA);
setAnimCurve(joint, "rotateY", rotY, MFnAnimCurve::kAnimCurveTA);
setAnimCurve(joint, "rotateZ", rotZ, MFnAnimCurve::kAnimCurveTA);
MFnIkJoint j(joint);
string name = j.name().asChar();
for (int i = 0; i < rotationTrack.size(); i++) {
auto rot = rotationTrack[i];
MQuaternion rotation(rot.x, rot.y, rot.z, rot.w);
// Depending on your input, you may have to do additional processing
// to get the correct Euler rotation here.
auto euler = rotation.asEulerRotation();
MTime time(FPS*i, MTime::kSeconds); // FPS is a number defined elsewhere.
rotX.addKeyframe(time, euler.x);
rotY.addKeyframe(time, euler.y);
rotZ.addKeyframe(time, euler.z);
}
}
void MayaImporter::setAnimCurve(const MObject& joint, const MString attr, MFnAnimCurve& curve, MFnAnimCurve::AnimCurveType type) {
MStatus status;
MPlug plug = MFnDependencyNode(joint).findPlug(attr, false, &status);
if (!plug.isKeyable())
plug.setKeyable(true);
if (plug.isLocked())
plug.setLocked(false);
if (!plug.isConnected()) {
curve.create(joint, plug, type, nullptr, &status);
if (status != MStatus::kSuccess)
cout << "Creating anim curve at joint failed!" << endl;
} else {
MFnAnimCurve animCurve(plug, &status);
if (status == MStatus::kNotImplemented)
cout << "Joint " << animCurve.name() << " has more than one anim curve." << endl;
else if (status != MStatus::kSuccess)
cout << "No anim curves found at joint " << animCurve.name() << endl;
curve.setObject(animCurve.object(&status));
}
}