Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGaia Clary <gaia.clary@machinimatrix.org>2018-02-24 15:11:30 +0300
committerGaia Clary <gaia.clary@machinimatrix.org>2018-02-24 17:55:27 +0300
commitdd7b9a362d9e362f81825bfa05f06741e9c1323b (patch)
tree1cd3d6dda1f484ba91674336a9094a055e54376b /source/blender/collada/AnimationExporter.cpp
parent4403ca80bda690c0ac44e4a6db0cddf4b2428006 (diff)
T45687: Rework the Export/Import of Animations
This started with a fix for an animated Object Hierarchy. Then i decided to cleanup and optimize a bit. But at the end this has become a more or less full rewrite of the Animation Exporter. All of this happened in a separate local branch and i have retained all my local commits to better see what i have done. Brief description: * I fixed a few issues with exporting keyframed animations of object hierarchies where the objects have parent inverse matrices which differ from the Identity matrix. * I added the option to export sampled animations with a user defined sampling rate (new user interface option) * I briefly tested Object Animations and Rig Animations. What is still needed: * Cleanup the code * Optimize the user interface * Do the Documentation Reviewers: mont29 Reviewed By: mont29 Differential Revision: https://developer.blender.org/D3070
Diffstat (limited to 'source/blender/collada/AnimationExporter.cpp')
-rw-r--r--source/blender/collada/AnimationExporter.cpp515
1 files changed, 423 insertions, 92 deletions
diff --git a/source/blender/collada/AnimationExporter.cpp b/source/blender/collada/AnimationExporter.cpp
index bd5cb05a1fa..759fb1546c7 100644
--- a/source/blender/collada/AnimationExporter.cpp
+++ b/source/blender/collada/AnimationExporter.cpp
@@ -49,38 +49,210 @@ bool AnimationExporter::exportAnimations(Scene *sce)
return has_animations;
}
-// called for each exported object
+
+/*
+ * This function creates a complete LINEAR Collada <Animation> Entry with all needed
+ * <source>, <sampler>, and <channel> entries.
+ * This is is used for creating sampled Transformation Animations for either:
+ *
+ * 1-axis animation:
+ * times contains the time points in seconds from within the timeline
+ * values contains the data (list of single floats)
+ * channel_count = 1
+ * axis_name = ['X' | 'Y' | 'Z']
+ * is_rot indicates if the animation is a rotation
+ *
+ * 3-axis animation:
+ * times contains the time points in seconds from within the timeline
+ * values contains the data (list of floats where each 3 entries are one vector)
+ * channel_count = 3
+ * axis_name = "" (actually not used)
+ * is_rot = false (see xxx below)
+ *
+ * xxx: I tried to create a 3 axis rotation animation
+ * like for translation or scale. But i could not
+ * figure out how to setup the channel for this case.
+ * So for now rotations are exported as 3 separate 1-axis collada animations
+ * See export_sampled_animation() further down.
+ */
+void AnimationExporter::create_sampled_animation(int channel_count,
+ std::vector<float> &times,
+ std::vector<float> &values,
+ std::string ob_name,
+ std::string label,
+ std::string axis_name,
+ bool is_rot)
+{
+
+ char anim_id[200];
+
+ BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char *)translate_id(ob_name).c_str(), label.c_str(), axis_name.c_str());
+
+ openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
+
+ /* create input source */
+ std::string input_id = create_source_from_vector(COLLADASW::InputSemantic::INPUT, times, false, anim_id, "");
+
+ /* create output source */
+ std::string output_id;
+ if (channel_count == 1)
+ output_id = create_source_from_array(COLLADASW::InputSemantic::OUTPUT, &values[0], values.size(), is_rot, anim_id, axis_name.c_str());
+ else if(channel_count = 3)
+ output_id = create_xyz_source(&values[0], times.size(), anim_id);
+
+ std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
+ COLLADASW::LibraryAnimations::Sampler sampler(sw, sampler_id);
+ std::string empty;
+ sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(empty, input_id));
+ sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(empty, output_id));
+
+ /* TODO create in/out tangents source (LINEAR) */
+ std::string interpolation_id = fake_interpolation_source(times.size(), anim_id, "");
+
+ /* Create Sampler */
+ sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
+ addSampler(sampler);
+
+ /* Create channel */
+ std::string target = translate_id(ob_name) + "/" + label + axis_name + ((is_rot) ? ".ANGLE" : "");
+ addChannel(COLLADABU::URI(empty, sampler_id), target);
+
+ closeAnimation();
+
+}
+
+/*
+ * Export all animation FCurves of an Object.
+ *
+ * Note: This uses the keyframes as sample points,
+ * and exports "baked keyframes" while keeping the tangent infromation
+ * of the FCurves intact. This works for simple cases, but breaks
+ * especially when negative scales are involved in the animation.
+ *
+ * If it is necessary to conserve the Animation precisely then
+ * use export_sampled_animation_set() instead.
+ */
+void AnimationExporter::export_keyframed_animation_set(Object *ob)
+{
+ FCurve *fcu = (FCurve *)ob->adt->action->curves.first;
+
+ char *transformName;
+ while (fcu) {
+ //for armature animations as objects
+ if (ob->type == OB_ARMATURE)
+ transformName = fcu->rna_path;
+ else
+ transformName = extract_transform_name(fcu->rna_path);
+
+ if (
+ STREQ(transformName, "location") ||
+ STREQ(transformName, "scale") ||
+ (STREQ(transformName, "rotation_euler") && ob->rotmode == ROT_MODE_EUL) ||
+ STREQ(transformName, "rotation_quaternion"))
+ {
+ create_keyframed_animation(ob, fcu, transformName, false);
+ }
+ fcu = fcu->next;
+ }
+
+}
+
+/*
+ * Export the sampled animation of an Object.
+ *
+ * Note: This steps over all animation frames (step size is given in export_settings.sample_size)
+ * and then evaluates the transformation,
+ * and exports "baked samples" This works always, however currently the interpolation type is set
+ * to LINEAR for now. (maybe later this can be changed to BEZIER)
+ *
+ * Note: If it is necessary to keep the FCurves intact, then use export_keyframed_animation_set() instead.
+ * However be aware that exporting keyframed animation may modify the animation slightly.
+ * Also keyframed animation exports tend to break when negative scales are involved.
+ */
+void AnimationExporter::export_sampled_animation_set(Object *ob)
+{
+ static int LOC = 0;
+ static int EULX = 1;
+ static int EULY = 2;
+ static int EULZ = 3;
+ static int SCALE = 4;
+ static int TIME = 5;
+
+ if (this->export_settings->sampling_rate < 1)
+ return; // to avoid infinite loop
+
+ std::vector<float> baked_curves[6];
+ std::vector<float> &ctimes = baked_curves[TIME];
+ find_sampleframes(ob, ctimes);
+
+ for (std::vector<float>::iterator ctime = ctimes.begin(); ctime != ctimes.end(); ++ctime ) {
+ float fmat[4][4];
+ float floc[3];
+ float fquat[4];
+ float fsize[3];
+ float feul[3];
+
+ evaluate_anim_with_constraints(ob, *ctime); // set object transforms to the frame
+
+ BKE_object_matrix_local_get(ob, fmat);
+ mat4_decompose(floc, fquat, fsize, fmat);
+ quat_to_eul(feul, fquat);
+
+ baked_curves[LOC].push_back(floc[0]);
+ baked_curves[LOC].push_back(floc[1]);
+ baked_curves[LOC].push_back(floc[2]);
+
+ baked_curves[EULX].push_back(feul[0]);
+ baked_curves[EULY].push_back(feul[1]);
+ baked_curves[EULZ].push_back(feul[2]);
+
+ baked_curves[SCALE].push_back(fsize[0]);
+ baked_curves[SCALE].push_back(fsize[1]);
+ baked_curves[SCALE].push_back(fsize[2]);
+
+ }
+
+ std::string ob_name = id_name(ob);
+
+ create_sampled_animation(3, baked_curves[TIME], baked_curves[SCALE], ob_name, "scale", "", false);
+ create_sampled_animation(3, baked_curves[TIME], baked_curves[LOC], ob_name, "location", "", false);
+
+ /* Not sure how to export rotation as a 3channel animation,
+ * so separate into 3 single animations for now:
+ */
+
+ create_sampled_animation(1, baked_curves[TIME], baked_curves[EULX], ob_name, "rotation", "X", true);
+ create_sampled_animation(1, baked_curves[TIME], baked_curves[EULY], ob_name, "rotation", "Y", true);
+ create_sampled_animation(1, baked_curves[TIME], baked_curves[EULZ], ob_name, "rotation", "Z", true);
+
+ fprintf(stdout, "Animation Export: Baked %zd frames for %s (sampling rate: %d)\n",
+ baked_curves[0].size(),
+ ob->id.name,
+ this->export_settings->sampling_rate);
+}
+
+/* called for each exported object */
void AnimationExporter::operator()(Object *ob)
{
- FCurve *fcu;
char *transformName;
+
/* bool isMatAnim = false; */ /* UNUSED */
//Export transform animations
if (ob->adt && ob->adt->action) {
- fcu = (FCurve *)ob->adt->action->curves.first;
- //transform matrix export for bones are temporarily disabled here.
if (ob->type == OB_ARMATURE) {
bArmature *arm = (bArmature *)ob->data;
for (Bone *bone = (Bone *)arm->bonebase.first; bone; bone = bone->next)
write_bone_animation_matrix(ob, bone);
}
-
- while (fcu) {
- //for armature animations as objects
- if (ob->type == OB_ARMATURE)
- transformName = fcu->rna_path;
- else
- transformName = extract_transform_name(fcu->rna_path);
-
- if ((STREQ(transformName, "location") || STREQ(transformName, "scale")) ||
- (STREQ(transformName, "rotation_euler") && ob->rotmode == ROT_MODE_EUL) ||
- (STREQ(transformName, "rotation_quaternion")))
- {
- dae_animation(ob, fcu, transformName, false);
+ else {
+ if (this->export_settings->sampling_rate == -1) {
+ export_keyframed_animation_set(ob);
+ }
+ else {
+ export_sampled_animation_set(ob);
}
- fcu = fcu->next;
}
}
@@ -92,14 +264,14 @@ void AnimationExporter::operator()(Object *ob)
//Export Lamp parameter animations
if ( (ob->type == OB_LAMP) && ((Lamp *)ob->data)->adt && ((Lamp *)ob->data)->adt->action) {
- fcu = (FCurve *)(((Lamp *)ob->data)->adt->action->curves.first);
+ FCurve *fcu = (FCurve *)(((Lamp *)ob->data)->adt->action->curves.first);
while (fcu) {
transformName = extract_transform_name(fcu->rna_path);
if ((STREQ(transformName, "color")) || (STREQ(transformName, "spot_size")) ||
(STREQ(transformName, "spot_blend")) || (STREQ(transformName, "distance")))
{
- dae_animation(ob, fcu, transformName, true);
+ create_keyframed_animation(ob, fcu, transformName, true);
}
fcu = fcu->next;
}
@@ -107,7 +279,7 @@ void AnimationExporter::operator()(Object *ob)
//Export Camera parameter animations
if ( (ob->type == OB_CAMERA) && ((Camera *)ob->data)->adt && ((Camera *)ob->data)->adt->action) {
- fcu = (FCurve *)(((Camera *)ob->data)->adt->action->curves.first);
+ FCurve *fcu = (FCurve *)(((Camera *)ob->data)->adt->action->curves.first);
while (fcu) {
transformName = extract_transform_name(fcu->rna_path);
@@ -116,7 +288,7 @@ void AnimationExporter::operator()(Object *ob)
(STREQ(transformName, "clip_end")) ||
(STREQ(transformName, "clip_start")))
{
- dae_animation(ob, fcu, transformName, true);
+ create_keyframed_animation(ob, fcu, transformName, true);
}
fcu = fcu->next;
}
@@ -128,7 +300,7 @@ void AnimationExporter::operator()(Object *ob)
if (!ma) continue;
if (ma->adt && ma->adt->action) {
/* isMatAnim = true; */
- fcu = (FCurve *)ma->adt->action->curves.first;
+ FCurve *fcu = (FCurve *)ma->adt->action->curves.first;
while (fcu) {
transformName = extract_transform_name(fcu->rna_path);
@@ -136,7 +308,7 @@ void AnimationExporter::operator()(Object *ob)
(STREQ(transformName, "diffuse_color")) || (STREQ(transformName, "alpha")) ||
(STREQ(transformName, "ior")))
{
- dae_animation(ob, fcu, transformName, true, ma);
+ create_keyframed_animation(ob, fcu, transformName, true, ma);
}
fcu = fcu->next;
}
@@ -167,7 +339,7 @@ void AnimationExporter::export_morph_animation(Object *ob)
while (fcu) {
transformName = extract_transform_name(fcu->rna_path);
- dae_animation(ob, fcu, transformName, true);
+ create_keyframed_animation(ob, fcu, transformName, true);
fcu = fcu->next;
}
@@ -200,7 +372,7 @@ void AnimationExporter::make_anim_frames_from_targets(Object *ob, std::vector<fl
obtar = ct->tar;
if (obtar)
- find_frames(obtar, frames);
+ find_keyframes(obtar, frames);
}
if (cti->flush_constraint_targets)
@@ -265,8 +437,8 @@ std::string AnimationExporter::getAnimationPathId(const FCurve *fcu)
return translate_id(rna_path);
}
-//convert f-curves to animation curves and write
-void AnimationExporter::dae_animation(Object *ob, FCurve *fcu, char *transformName, bool is_param, Material *ma)
+/* convert f-curves to animation curves and write */
+void AnimationExporter::create_keyframed_animation(Object *ob, FCurve *fcu, char *transformName, bool is_param, Material *ma)
{
const char *axis_name = NULL;
char anim_id[200];
@@ -274,6 +446,8 @@ void AnimationExporter::dae_animation(Object *ob, FCurve *fcu, char *transformNa
bool has_tangents = false;
bool quatRotation = false;
+ Object *obj = NULL;
+
if (STREQ(transformName, "rotation_quaternion") ) {
fprintf(stderr, "quaternion rotation curves are not supported. rotation curve will not be exported\n");
quatRotation = true;
@@ -291,15 +465,26 @@ void AnimationExporter::dae_animation(Object *ob, FCurve *fcu, char *transformNa
axis_name = axis_names[fcu->array_index];
}
- //axis names for transforms
- else if (STREQ(transformName, "location") ||
- STREQ(transformName, "scale") ||
- STREQ(transformName, "rotation_euler") ||
- STREQ(transformName, "rotation_quaternion"))
+ /*
+ * Note: Handle transformation animations separately (to apply matrix inverse to fcurves)
+ * We will use the object to evaluate the animation on all keyframes and calculate the
+ * resulting object matrix. We need this to incorporate the
+ * effects of the parent inverse matrix (when it contains a rotation component)
+ *
+ * TODO: try to combine exported fcurves into 3 channel animations like done
+ * in export_sampled_animation(). For now each channel is exported as separate <Animation>.
+ */
+
+ else if (
+ STREQ(transformName, "scale") ||
+ STREQ(transformName, "location") ||
+ STREQ(transformName, "rotation_euler"))
{
const char *axis_names[] = {"X", "Y", "Z"};
- if (fcu->array_index < 3)
+ if (fcu->array_index < 3) {
axis_name = axis_names[fcu->array_index];
+ obj = ob;
+ }
}
else {
/* no axis name. single parameter */
@@ -308,7 +493,7 @@ void AnimationExporter::dae_animation(Object *ob, FCurve *fcu, char *transformNa
std::string ob_name = std::string("null");
- //Create anim Id
+ /* Create anim Id */
if (ob->type == OB_ARMATURE) {
ob_name = getObjectBoneName(ob, fcu);
BLI_snprintf(
@@ -357,7 +542,7 @@ void AnimationExporter::dae_animation(Object *ob, FCurve *fcu, char *transformNa
output_id = create_lens_source_from_fcurve((Camera *) ob->data, COLLADASW::InputSemantic::OUTPUT, fcu, anim_id);
}
else {
- output_id = create_source_from_fcurve(COLLADASW::InputSemantic::OUTPUT, fcu, anim_id, axis_name);
+ output_id = create_source_from_fcurve(COLLADASW::InputSemantic::OUTPUT, fcu, anim_id, axis_name, obj);
}
// create interpolations source
@@ -369,10 +554,10 @@ void AnimationExporter::dae_animation(Object *ob, FCurve *fcu, char *transformNa
if (has_tangents) {
// create in_tangent source
- intangent_id = create_source_from_fcurve(COLLADASW::InputSemantic::IN_TANGENT, fcu, anim_id, axis_name);
+ intangent_id = create_source_from_fcurve(COLLADASW::InputSemantic::IN_TANGENT, fcu, anim_id, axis_name, obj);
// create out_tangent source
- outtangent_id = create_source_from_fcurve(COLLADASW::InputSemantic::OUT_TANGENT, fcu, anim_id, axis_name);
+ outtangent_id = create_source_from_fcurve(COLLADASW::InputSemantic::OUT_TANGENT, fcu, anim_id, axis_name, obj);
}
std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
@@ -475,8 +660,11 @@ void AnimationExporter::sample_and_write_bone_animation_matrix(Object *ob_arm, B
if (!pchan)
return;
- //every inserted keyframe of bones.
- find_frames(ob_arm, fra);
+
+ if (this->export_settings->sampling_rate < 1)
+ find_keyframes(ob_arm, fra);
+ else
+ find_sampleframes(ob_arm, fra);
if (flag & ARM_RESTPOS) {
arm->flag &= ~ARM_RESTPOS;
@@ -755,14 +943,60 @@ void AnimationExporter::get_source_values(BezTriple *bezt, COLLADASW::InputSeman
}
}
+// old function to keep compatibility for calls where offset and object are not needed
std::string AnimationExporter::create_source_from_fcurve(COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name)
{
- std::string source_id = anim_id + get_semantic_suffix(semantic);
+ return create_source_from_fcurve(semantic, fcu, anim_id, axis_name, NULL);
+}
- //bool is_angle = STREQ(fcu->rna_path, "rotation");
- bool is_angle = false;
+void AnimationExporter::evaluate_anim_with_constraints(Object *ob, float ctime)
+{
+ BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, ctime, ADT_RECALC_ALL);
+ ListBase *conlist = get_active_constraints(ob);
+ bConstraint *con;
+ for (con = (bConstraint *)conlist->first; con; con = con->next) {
+ ListBase targets = { NULL, NULL };
+
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+
+ if (cti && cti->get_constraint_targets) {
+ bConstraintTarget *ct;
+ Object *obtar;
+ cti->get_constraint_targets(con, &targets);
+ for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) {
+ obtar = ct->tar;
+
+ if (obtar) {
+ BKE_animsys_evaluate_animdata(scene, &obtar->id, obtar->adt, ctime, ADT_RECALC_ANIM);
+ BKE_object_where_is_calc_time(scene, obtar, ctime);
+ }
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 1);
+ }
+ }
+ BKE_object_where_is_calc_time(scene, ob, ctime);
+}
- if (strstr(fcu->rna_path, "rotation") || strstr(fcu->rna_path,"spot_size")) is_angle = true;
+/*
+ * ob is needed to aply parent inverse information to fcurve.
+ * TODO: Here we have to step over all keyframes for each object and for each fcurve.
+ * Instead of processing each fcurve one by one,
+ * step over the animation from keyframe to keyframe,
+ * then create adjusted fcurves (and entries) for all affected objects.
+ * Then we would need to step through the scene only once.
+ */
+std::string AnimationExporter::create_source_from_fcurve(COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id, const char *axis_name, Object *ob)
+{
+ std::string source_id = anim_id + get_semantic_suffix(semantic);
+
+ bool is_angle = (strstr(fcu->rna_path, "rotation") || strstr(fcu->rna_path, "spot_size"));
+ bool is_euler = strstr(fcu->rna_path, "rotation_euler");
+ bool is_translation = strstr(fcu->rna_path, "location");
+ bool is_scale = strstr(fcu->rna_path, "scale");
+ bool is_tangent = false;
+ int offset_index = 0;
COLLADASW::FloatSourceF source(mSW);
source.setId(source_id);
@@ -773,27 +1007,76 @@ std::string AnimationExporter::create_source_from_fcurve(COLLADASW::InputSemanti
case COLLADASW::InputSemantic::INPUT:
case COLLADASW::InputSemantic::OUTPUT:
source.setAccessorStride(1);
+ offset_index = 0;
break;
case COLLADASW::InputSemantic::IN_TANGENT:
case COLLADASW::InputSemantic::OUT_TANGENT:
source.setAccessorStride(2);
+ offset_index = 1;
+ is_tangent = true;
break;
default:
break;
}
-
COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
add_source_parameters(param, semantic, is_angle, axis_name, false);
source.prepareToAppendValues();
- for (unsigned int i = 0; i < fcu->totvert; i++) {
+ for (unsigned int frame_index = 0; frame_index < fcu->totvert; frame_index++) {
+ float fixed_val = 0;
+ if (ob) {
+ float fmat[4][4];
+ float frame = fcu->bezt[frame_index].vec[1][0];
+ float ctime = BKE_scene_frame_get_from_ctime(scene, frame);
+
+ evaluate_anim_with_constraints(ob, ctime); // set object transforms to fcurve's i'th keyframe
+
+ BKE_object_matrix_local_get(ob, fmat);
+ float floc[3];
+ float fquat[4];
+ float fsize[3];
+ mat4_decompose(floc, fquat, fsize, fmat);
+
+ if (is_euler) {
+ float eul[3];
+ quat_to_eul(eul, fquat);
+ fixed_val = RAD2DEGF(eul[fcu->array_index]);
+ }
+ else if (is_translation) {
+ fixed_val = floc[fcu->array_index];
+ }
+ else if (is_scale) {
+ fixed_val = fsize[fcu->array_index];
+ }
+ }
+
float values[3]; // be careful!
+ float offset = 0;
int length = 0;
- get_source_values(&fcu->bezt[i], semantic, is_angle, values, &length);
- for (int j = 0; j < length; j++)
- source.appendValues(values[j]);
+ get_source_values(&fcu->bezt[frame_index], semantic, is_angle, values, &length);
+ if (is_tangent) {
+ float bases[3];
+ int len = 0;
+ get_source_values(&fcu->bezt[frame_index], COLLADASW::InputSemantic::OUTPUT, is_angle, bases, &len);
+ offset = values[offset_index] - bases[0];
+ }
+
+ for (int j = 0; j < length; j++) {
+ float val;
+ if (j == offset_index) {
+ if (ob) {
+ val = fixed_val + offset;
+ }
+ else {
+ val = values[j] + offset;
+ }
+ } else {
+ val = values[j];
+ }
+ source.appendValues(val);
+ }
}
source.finish();
@@ -837,9 +1120,9 @@ std::string AnimationExporter::create_lens_source_from_fcurve(Camera *cam, COLLA
return source_id;
}
-
-
-//Currently called only to get OUTPUT source values ( if rotation and hence the axis is also specified )
+/*
+ * only to get OUTPUT source values ( if rotation and hence the axis is also specified )
+ */
std::string AnimationExporter::create_source_from_array(COLLADASW::InputSemantic::Semantics semantic, float *v, int tot, bool is_rot, const std::string& anim_id, const char *axis_name)
{
std::string source_id = anim_id + get_semantic_suffix(semantic);
@@ -869,7 +1152,10 @@ std::string AnimationExporter::create_source_from_array(COLLADASW::InputSemantic
return source_id;
}
-// only used for sources with INPUT semantic
+
+/*
+ * only used for sources with INPUT semantic
+ */
std::string AnimationExporter::create_source_from_vector(COLLADASW::InputSemantic::Semantics semantic, std::vector<float> &fra, bool is_rot, const std::string& anim_id, const char *axis_name)
{
std::string source_id = anim_id + get_semantic_suffix(semantic);
@@ -935,9 +1221,10 @@ std::string AnimationExporter::create_4x4_source(std::vector<float> &frames, Obj
int j = 0;
for (it = frames.begin(); it != frames.end(); it++) {
float mat[4][4], ipar[4][4];
+ float frame = *it;
- float ctime = BKE_scene_frame_get_from_ctime(scene, *it);
- CFRA = BKE_scene_frame_get_from_ctime(scene, *it);
+ float ctime = BKE_scene_frame_get_from_ctime(scene, frame);
+ CFRA = BKE_scene_frame_get_from_ctime(scene, frame);
//BKE_scene_update_for_newframe(G.main->eval_ctx, G.main,scene,scene->lay);
BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, ctime, ADT_RECALC_ALL);
@@ -959,9 +1246,10 @@ std::string AnimationExporter::create_4x4_source(std::vector<float> &frames, Obj
else
copy_m4_m4(mat, pchan->pose_mat);
- // OPEN_SIM_COMPATIBILITY
- // AFAIK animation to second life is via BVH, but no
- // reason to not have the collada-animation be correct
+ /* OPEN_SIM_COMPATIBILITY
+ * AFAIK animation to second life is via BVH, but no
+ * reason to not have the collada-animation be correct
+ */
if (export_settings->open_sim) {
float temp[4][4];
copy_m4_m4(temp, bone->arm_mat);
@@ -980,7 +1268,11 @@ std::string AnimationExporter::create_4x4_source(std::vector<float> &frames, Obj
}
else {
- calc_ob_mat_at_time(ob, ctime, mat);
+ BKE_scene_frame_set(scene, ctime);
+ Main *bmain = bc_get_main();
+ EvaluationContext *ev_context = bc_get_evaluation_context();
+ BKE_scene_update_for_newframe(ev_context, bmain, scene, scene->lay);
+ copy_m4_m4(mat, ob->obmat);
}
UnitConverter converter;
@@ -1008,7 +1300,9 @@ std::string AnimationExporter::create_4x4_source(std::vector<float> &frames, Obj
}
-// only used for sources with OUTPUT semantic ( locations and scale)
+/*
+ * only used for sources with OUTPUT semantic ( locations and scale)
+ */
std::string AnimationExporter::create_xyz_source(float *v, int tot, const std::string& anim_id)
{
COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT;
@@ -1192,8 +1486,10 @@ std::string AnimationExporter::get_camera_param_sid(char *rna_path, int tm_type,
return std::string("");
}
-// Assign sid of the animated parameter or transform
-// for rotation, axis name is always appended and the value of append_axis is ignored
+/*
+ * Assign sid of the animated parameter or transform for rotation,
+ * axis name is always appended and the value of append_axis is ignored
+ */
std::string AnimationExporter::get_transform_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis)
{
std::string tm_name;
@@ -1277,29 +1573,10 @@ char *AnimationExporter::extract_transform_name(char *rna_path)
return dot ? (dot + 1) : rna_path;
}
-//find keyframes of all the objects animations
-void AnimationExporter::find_frames(Object *ob, std::vector<float> &fra)
-{
- if (ob->adt && ob->adt->action) {
- FCurve *fcu = (FCurve *)ob->adt->action->curves.first;
-
- for (; fcu; fcu = fcu->next) {
- for (unsigned int i = 0; i < fcu->totvert; i++) {
- float f = fcu->bezt[i].vec[1][0];
- if (std::find(fra.begin(), fra.end(), f) == fra.end())
- fra.push_back(f);
- }
- }
-
- // keep the keys in ascending order
- std::sort(fra.begin(), fra.end());
- }
-}
-
-
-
-// enable fcurves driving a specific bone, disable all the rest
-// if bone_name = NULL enable all fcurves
+/*
+ * enable fcurves driving a specific bone, disable all the rest
+ * if bone_name = NULL enable all fcurves
+ */
void AnimationExporter::enable_fcurves(bAction *act, char *bone_name)
{
FCurve *fcu;
@@ -1364,14 +1641,53 @@ bool AnimationExporter::hasAnimations(Scene *sce)
void AnimationExporter::find_rotation_frames(Object *ob, std::vector<float> &fra, const char *prefix, int rotmode)
{
if (rotmode > 0)
- find_frames(ob, fra, prefix, "rotation_euler");
+ find_keyframes(ob, fra, prefix, "rotation_euler");
else if (rotmode == ROT_MODE_QUAT)
- find_frames(ob, fra, prefix, "rotation_quaternion");
+ find_keyframes(ob, fra, prefix, "rotation_quaternion");
/*else if (rotmode == ROT_MODE_AXISANGLE)
;*/
}
-void AnimationExporter::find_frames(Object *ob, std::vector<float> &fra, const char *prefix, const char *tm_name)
+/* Take care to always have the first frame and the last frame in the animation
+ * regardless of the sampling_rate setting
+ */
+void AnimationExporter::find_sampleframes(Object *ob, std::vector<float> &fra)
+{
+ int frame = scene->r.sfra;
+ do {
+ float ctime = BKE_scene_frame_get_from_ctime(scene, frame);
+ fra.push_back(ctime);
+ if (frame == scene->r.efra)
+ break;
+ frame += this->export_settings->sampling_rate;
+ if (frame > scene->r.efra)
+ frame = scene->r.efra; // make sure the last frame is always exported
+
+ } while (true);
+}
+
+/*
+ * find keyframes of all the objects animations
+ */
+void AnimationExporter::find_keyframes(Object *ob, std::vector<float> &fra)
+{
+ if (ob->adt && ob->adt->action) {
+ FCurve *fcu = (FCurve *)ob->adt->action->curves.first;
+
+ for (; fcu; fcu = fcu->next) {
+ for (unsigned int i = 0; i < fcu->totvert; i++) {
+ float f = fcu->bezt[i].vec[1][0];
+ if (std::find(fra.begin(), fra.end(), f) == fra.end())
+ fra.push_back(f);
+ }
+ }
+
+ // keep the keys in ascending order
+ std::sort(fra.begin(), fra.end());
+ }
+}
+
+void AnimationExporter::find_keyframes(Object *ob, std::vector<float> &fra, const char *prefix, const char *tm_name)
{
if (ob->adt && ob->adt->action) {
FCurve *fcu = (FCurve *)ob->adt->action->curves.first;
@@ -1429,10 +1745,10 @@ void AnimationExporter::sample_and_write_bone_animation(Object *ob_arm, Bone *bo
find_rotation_frames(ob_arm, fra, prefix, pchan->rotmode);
break;
case 1:
- find_frames(ob_arm, fra, prefix, "scale");
+ find_keyframes(ob_arm, fra, prefix, "scale");
break;
case 2:
- find_frames(ob_arm, fra, prefix, "location");
+ find_keyframes(ob_arm, fra, prefix, "location");
break;
default:
return;
@@ -1539,8 +1855,23 @@ bool AnimationExporter::validateConstraints(bConstraint *con)
return valid;
}
-void AnimationExporter::calc_ob_mat_at_time(Object *ob, float ctime , float mat[][4])
+#if 0
+/*
+ * Needed for sampled animations.
+ * This function calculates the object matrix at a given time,
+ * also taking constraints into account.
+ *
+ * XXX: Why looking at the constraints here is necessary?
+ * Maybe this can be done better?
+ */
+void AnimationExporter::calc_obmat_at_time(Object *ob, float ctime )
{
+ BKE_scene_frame_set(scene, ctime);
+
+ Main *bmain = bc_get_main();
+ EvaluationContext *ev_context = bc_get_evaluation_context();
+ BKE_scene_update_for_newframe(ev_context, bmain, scene, scene->lay);
+
ListBase *conlist = get_active_constraints(ob);
bConstraint *con;
for (con = (bConstraint *)conlist->first; con; con = con->next) {
@@ -1566,6 +1897,6 @@ void AnimationExporter::calc_ob_mat_at_time(Object *ob, float ctime , float mat[
}
}
BKE_object_where_is_calc_time(scene, ob, ctime);
- copy_m4_m4(mat, ob->obmat);
}
+#endif