[Bf-blender-cvs] [dd7b9a362d9] master: T45687: Rework the Export/Import of Animations

Gaia Clary noreply at git.blender.org
Sat Feb 24 15:55:32 CET 2018


Commit: dd7b9a362d9e362f81825bfa05f06741e9c1323b
Author: Gaia Clary
Date:   Sat Feb 24 13:11:30 2018 +0100
Branches: master
https://developer.blender.org/rBdd7b9a362d9e362f81825bfa05f06741e9c1323b

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

===================================================================

M	source/blender/collada/AnimationExporter.cpp
M	source/blender/collada/AnimationExporter.h
M	source/blender/collada/AnimationImporter.cpp
M	source/blender/collada/ExportSettings.h
M	source/blender/collada/collada.cpp
M	source/blender/collada/collada.h
M	source/blender/collada/collada_utils.cpp
M	source/blender/collada/collada_utils.h
M	source/blender/editors/io/io_collada.c
M	source/blender/makesrna/intern/rna_scene_api.c
M	tests/python/CMakeLists.txt
A	tests/python/collada/CMakeLists.txt
A	tests/python/collada/mesh/test_mesh_simple.py

===================================================================

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")

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list