[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [25746] branches/soc-2009-chingachgook/ source/blender/collada: COLLADA branch: bone anim export works.
Arystanbek Dyussenov
arystan.d at gmail.com
Tue Jan 5 17:07:10 CET 2010
Revision: 25746
http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=25746
Author: kazanbas
Date: 2010-01-05 17:07:10 +0100 (Tue, 05 Jan 2010)
Log Message:
-----------
COLLADA branch: bone anim export works. Export-import roundtrip is possible.
Importer now takes mesh bind position into account.
TODO: read/write object-level anim on armatures and fix memleaks.
Modified Paths:
--------------
branches/soc-2009-chingachgook/source/blender/collada/DocumentExporter.cpp
branches/soc-2009-chingachgook/source/blender/collada/DocumentImporter.cpp
Modified: branches/soc-2009-chingachgook/source/blender/collada/DocumentExporter.cpp
===================================================================
--- branches/soc-2009-chingachgook/source/blender/collada/DocumentExporter.cpp 2010-01-05 15:23:09 UTC (rev 25745)
+++ branches/soc-2009-chingachgook/source/blender/collada/DocumentExporter.cpp 2010-01-05 16:07:10 UTC (rev 25746)
@@ -21,6 +21,7 @@
{
#include "BKE_DerivedMesh.h"
#include "BKE_fcurve.h"
+#include "BKE_animsys.h"
#include "BLI_util.h"
#include "BLI_fileops.h"
#include "ED_keyframing.h"
@@ -36,6 +37,7 @@
#include "BKE_armature.h"
#include "BKE_image.h"
#include "BKE_utildefines.h"
+#include "BKE_object.h"
#include "BLI_math.h"
#include "BLI_string.h"
@@ -198,6 +200,12 @@
return translate_id(id_name(ob)) + "-camera";
}
+std::string get_joint_id(Bone *bone, Object *ob_arm)
+{
+ return translate_id(id_name(ob_arm) + "_" + bone->name);
+}
+
+
/*
Utilities to avoid code duplication.
Definition can take some time to understand, but they should be useful.
@@ -851,11 +859,6 @@
return ob_arm;
}
- std::string get_joint_id(Bone *bone, Object *ob_arm)
- {
- return translate_id(id_name(ob_arm) + "_" + bone->name);
- }
-
std::string get_joint_sid(Bone *bone)
{
char name[100];
@@ -1734,7 +1737,9 @@
class AnimationExporter: COLLADASW::LibraryAnimations
{
Scene *scene;
+
public:
+
AnimationExporter(COLLADASW::StreamWriter *sw): COLLADASW::LibraryAnimations(sw) {}
void exportAnimations(Scene *sce)
@@ -1748,17 +1753,278 @@
closeLibrary();
}
- // create <animation> for each transform axis
+ // called for each exported object
+ void operator() (Object *ob)
+ {
+ if (!ob->adt || !ob->adt->action) return;
+
+ FCurve *fcu = (FCurve*)ob->adt->action->curves.first;
+
+ if (ob->type == OB_ARMATURE) {
+ if (!ob->data) return;
- float convert_time(float frame) {
+ bArmature *arm = (bArmature*)ob->data;
+ for (Bone *bone = (Bone*)arm->bonebase.first; bone; bone = bone->next)
+ write_bone_animation(ob, bone);
+ }
+ else {
+ while (fcu) {
+ // TODO "rotation_quaternion" is also possible for objects (although euler is default)
+ if ((!strcmp(fcu->rna_path, "location") || !strcmp(fcu->rna_path, "scale")) ||
+ (!strcmp(fcu->rna_path, "rotation_euler") && ob->rotmode == ROT_MODE_EUL))
+ dae_animation(fcu, id_name(ob));
+
+ fcu = fcu->next;
+ }
+ }
+ }
+
+protected:
+
+ void dae_animation(FCurve *fcu, std::string ob_name)
+ {
+ const char *axis_names[] = {"X", "Y", "Z"};
+ const char *axis_name = NULL;
+ char anim_id[200];
+ char anim_name[200];
+
+ if (fcu->array_index < 3)
+ axis_name = axis_names[fcu->array_index];
+
+ BLI_snprintf(anim_id, sizeof(anim_id), "%s.%s.%s", (char*)translate_id(ob_name).c_str(),
+ fcu->rna_path, axis_names[fcu->array_index]);
+ BLI_snprintf(anim_name, sizeof(anim_name), "%s.%s.%s",
+ (char*)ob_name.c_str(), fcu->rna_path, axis_names[fcu->array_index]);
+
+ // check rna_path is one of: rotation, scale, location
+
+ openAnimation(anim_id, anim_name);
+
+ // create input source
+ std::string input_id = create_source_from_fcurve(Sampler::INPUT, fcu, anim_id, axis_name);
+
+ // create output source
+ std::string output_id = create_source_from_fcurve(Sampler::OUTPUT, fcu, anim_id, axis_name);
+
+ // create interpolations source
+ std::string interpolation_id = create_interpolation_source(fcu->totvert, anim_id, axis_name);
+
+ std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
+ COLLADASW::LibraryAnimations::Sampler sampler(sampler_id);
+ std::string empty;
+ sampler.addInput(Sampler::INPUT, COLLADABU::URI(empty, input_id));
+ sampler.addInput(Sampler::OUTPUT, COLLADABU::URI(empty, output_id));
+
+ // this input is required
+ sampler.addInput(Sampler::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
+
+ addSampler(sampler);
+
+ std::string target = translate_id(ob_name)
+ + "/" + get_transform_sid(fcu->rna_path, -1, axis_name);
+ addChannel(COLLADABU::URI(empty, sampler_id), target);
+
+ closeAnimation();
+ }
+
+ void write_bone_animation(Object *ob_arm, Bone *bone)
+ {
+ if (!ob_arm->adt)
+ return;
+
+ for (int i = 0; i < 3; i++)
+ sample_and_write_bone_animation(ob_arm, bone, i);
+
+ for (Bone *child = (Bone*)bone->childbase.first; child; child = child->next)
+ write_bone_animation(ob_arm, child);
+ }
+
+ void sample_and_write_bone_animation(Object *ob_arm, Bone *bone, int transform_type)
+ {
+ bArmature *arm = (bArmature*)ob_arm->data;
+ int flag = arm->flag;
+ std::vector<float> fra;
+ char prefix[256];
+
+ BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone->name);
+
+ bPoseChannel *pchan = get_pose_channel(ob_arm->pose, bone->name);
+ if (!pchan)
+ return;
+
+ switch (transform_type) {
+ case 0:
+ find_rotation_frames(ob_arm, fra, prefix, pchan->rotmode);
+ break;
+ case 1:
+ find_frames(ob_arm, fra, prefix, "scale");
+ break;
+ case 2:
+ find_frames(ob_arm, fra, prefix, "location");
+ break;
+ default:
+ return;
+ }
+
+ // exit rest position
+ if (flag & ARM_RESTPOS) {
+ arm->flag &= ~ARM_RESTPOS;
+ where_is_pose(scene, ob_arm);
+ }
+
+ if (fra.size()) {
+ float *v = (float*)MEM_callocN(sizeof(float) * 3 * fra.size(), "temp. anim frames");
+ sample_animation(v, fra, transform_type, bone, ob_arm);
+
+ if (transform_type == 0) {
+ // write x, y, z curves separately if it is rotation
+ float *c = (float*)MEM_callocN(sizeof(float) * fra.size(), "temp. anim frames");
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < fra.size(); j++)
+ c[j] = v[j * 3 + i];
+
+ dae_bone_animation(fra, c, transform_type, i, id_name(ob_arm), bone->name);
+ }
+ MEM_freeN(c);
+ }
+ else {
+ // write xyz at once if it is location or scale
+ dae_bone_animation(fra, v, transform_type, -1, id_name(ob_arm), bone->name);
+ }
+
+ MEM_freeN(v);
+ }
+
+ // restore restpos
+ if (flag & ARM_RESTPOS)
+ arm->flag = flag;
+ where_is_pose(scene, ob_arm);
+ }
+
+ void sample_animation(float *v, std::vector<float> &frames, int type, Bone *bone, Object *ob_arm)
+ {
+ bPoseChannel *pchan, *parchan = NULL;
+ bPose *pose = ob_arm->pose;
+
+ pchan = get_pose_channel(pose, bone->name);
+
+ if (!pchan)
+ return;
+
+ parchan = pchan->parent;
+
+ enable_fcurves(ob_arm->adt->action, bone->name);
+
+ std::vector<float>::iterator it;
+ for (it = frames.begin(); it != frames.end(); it++) {
+ float mat[4][4], ipar[4][4];
+
+ float ctime = bsystem_time(scene, ob_arm, *it, 0.0f);
+
+ BKE_animsys_evaluate_animdata(&ob_arm->id, ob_arm->adt, *it, ADT_RECALC_ANIM);
+ where_is_pose_bone(scene, ob_arm, pchan, ctime);
+
+ // compute bone local mat
+ if (bone->parent) {
+ invert_m4_m4(ipar, parchan->pose_mat);
+ mul_m4_m4m4(mat, pchan->pose_mat, ipar);
+ }
+ else
+ copy_m4_m4(mat, pchan->pose_mat);
+
+ switch (type) {
+ case 0:
+ mat4_to_eul(v, mat);
+ break;
+ case 1:
+ mat4_to_size(v, mat);
+ break;
+ case 2:
+ copy_v3_v3(v, mat[3]);
+ break;
+ }
+
+ v += 3;
+ }
+
+ enable_fcurves(ob_arm->adt->action, NULL);
+ }
+
+ // dae_bone_animation -> add_bone_animation
+ // (blend this into dae_bone_animation)
+ void dae_bone_animation(std::vector<float> &fra, float *v, int tm_type, int axis, std::string ob_name, std::string bone_name)
+ {
+ const char *axis_names[] = {"X", "Y", "Z"};
+ const char *axis_name = NULL;
+ char anim_id[200];
+ char anim_name[200];
+ bool is_rot = tm_type == 0;
+
+ if (!fra.size())
+ return;
+
+ char rna_path[200];
+ BLI_snprintf(rna_path, sizeof(rna_path), "pose.bones[\"%s\"].%s", bone_name.c_str(),
+ tm_type == 0 ? "rotation_quaternion" : (tm_type == 1 ? "scale" : "location"));
+
+ if (axis > -1)
+ axis_name = axis_names[axis];
+
+ std::string transform_sid = get_transform_sid(NULL, tm_type, axis_name);
+
+ BLI_snprintf(anim_id, sizeof(anim_id), "%s.%s.%s", (char*)translate_id(ob_name).c_str(),
+ (char*)translate_id(bone_name).c_str(), (char*)transform_sid.c_str());
+ BLI_snprintf(anim_name, sizeof(anim_name), "%s.%s.%s",
+ (char*)ob_name.c_str(), (char*)bone_name.c_str(), (char*)transform_sid.c_str());
+
+ // TODO check rna_path is one of: rotation, scale, location
+
+ openAnimation(anim_id, anim_name);
+
+ // create input source
+ std::string input_id = create_source_from_vector(Sampler::INPUT, fra, is_rot, anim_id, axis_name);
+
+ // create output source
+ std::string output_id;
+ if (axis == -1)
+ output_id = create_xyz_source(v, fra.size(), anim_id);
+ else
+ output_id = create_source_from_array(Sampler::OUTPUT, v, fra.size(), is_rot, anim_id, axis_name);
+
+ // create interpolations source
+ std::string interpolation_id = create_interpolation_source(fra.size(), anim_id, axis_name);
+
+ std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
+ COLLADASW::LibraryAnimations::Sampler sampler(sampler_id);
+ std::string empty;
+ sampler.addInput(Sampler::INPUT, COLLADABU::URI(empty, input_id));
+ sampler.addInput(Sampler::OUTPUT, COLLADABU::URI(empty, output_id));
+
+ // TODO create in/out tangents source
+
+ // this input is required
+ sampler.addInput(Sampler::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
+
+ addSampler(sampler);
+
+ std::string target = translate_id(ob_name + "_" + bone_name) + "/" + transform_sid;
+ addChannel(COLLADABU::URI(empty, sampler_id), target);
+
+ closeAnimation();
+ }
+
+ float convert_time(float frame)
+ {
return FRA2TIME(frame);
}
- float convert_angle(float angle) {
+ float convert_angle(float angle)
+ {
return COLLADABU::Math::Utils::radToDegF(angle);
}
- std::string get_semantic_suffix(Sampler::Semantic semantic) {
+ std::string get_semantic_suffix(Sampler::Semantic semantic)
+ {
switch(semantic) {
case Sampler::INPUT:
return INPUT_SOURCE_ID_SUFFIX;
@@ -1775,17 +2041,25 @@
}
void add_source_parameters(COLLADASW::SourceBase::ParameterNameList& param,
- Sampler::Semantic semantic, bool rotation, const char *axis) {
+ Sampler::Semantic semantic, bool is_rot, const char *axis)
+ {
switch(semantic) {
case Sampler::INPUT:
param.push_back("TIME");
break;
case Sampler::OUTPUT:
- if (rotation) {
+ if (is_rot) {
param.push_back("ANGLE");
}
else {
- param.push_back(axis);
+ if (axis) {
+ param.push_back(axis);
+ }
+ else {
+ param.push_back("X");
+ param.push_back("Y");
+ param.push_back("Z");
+ }
}
break;
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list