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-11-23 17:57:45 +0300
committerGaia Clary <gaia.clary@machinimatrix.org>2018-11-23 19:08:14 +0300
commit322cf89a1444c685219ed6b863c9c74d41b5d1d1 (patch)
tree4145b1ec18a0c5cd4fe344d4e9ed49a0c2d33d0b /source/blender/collada/AnimationExporter.cpp
parent3bf7c846eeb4a728c62100b40463874d83f5b3e0 (diff)
Partial rewrite of the Collada Module for Blender 2.8
Most important changes are in the Animation exporter and Animation Importer. There is still some cleaning up to be done. But the Exporter/Importer basically work within Blender 2.8 Some details: User Interface: The interface has been reorganized to look more like the FBX interface. New options in user interface: * keep_keyframes: When sampling the distance between 2 keyframes is defined by the sampling rate. Furthermore the keyframes defined in the FCurves are not exported. However when this option is enabled then also the defined keyframes will be added to the exported fcurves * keep_smooth_curves: When sampling we do not use FCurves. So we also have no Curve handles for smooth exporting. However when this option is enabled, Blender does its best to recreate the handles for export. This is a very experimental feature and it is know to break when: - the exported animated objects have parent inverse matrices different from the unit matrix - The exported objects have negative scaling There may be many other situations when this feature breaks. This needs to be further tested. It may be removed later or replaced by something less wonky. BlenderContext: is a new class that contains the bridge to Blender. It contains pointers to the current export/import context plus derived values of Depsgraph, Scene, Main Reporting: I reorganized the output on the Blender Console to become more informative and more readable Preservation of Item names: name attributes are now encoded with XML entities. This makes sure that i can export/import names exactly defined in the tool. This affects material names, bone names and object names. Hierarchy export: * Object and Bone Hierarchies are now exported correctly by taking the Blender parent/child hierarchy into account * Export also not selected intermediate objects Problem: When we export an Object Hierarchy, then we must export all elements of the hierarchy to maintain the transforms. This is especially important when exporting animated objects, because the animation curves are exported as relative curves based on the parent-child hierarchy. If an intermediate animated object is missing then the exported animation breaks. Solution: If the "Selected" Optioon is enabled, then take care to also export all objects which are not selected and hidden, but which are parents of selected objects. Node Based Material Importer (wip): Added basic support for Materials with diffuse color and diffuse textures. More properties (opacity, emission) need changes in the used shader. Note: Materials are all constructed by using the principled BSDF shader. Animation Exporter: * Massive optimization of the Animation Bake tool (Animation Sampler). Instead of sampling each fcurve separately, i now sample all exported fcurves simultaneously. So i avoid many (many!) scene updates during animation export. * Add support for Continuous Acceleration (Fcurve handles) This allows us to create smoother FCurves during importing Collada Animation curves. Possibly this should become an option ionstead of a fixed import feature. * Add support for sampling curves (to bake animations) * The animation sampler now can be used for any animation curve. Before the sampler only looked at curves which are supported by Standard Collada 1.4. However the Collada exporter currently ignores all animation curves which are not covered by the 1.4.1 Collada Standards. There is still some room for improvements here (work in progres) Known issues: * Some exports do currently not work reliably, among those are the camera animations, material animations and light animations those animations will be added back next (work in progres) * Exporting animation curves with keyframes (and tangents) sometimes results in odd curves (when parent inverse matrix is involved) This needs to be checked in more depth (probably it can not be solved). * Export of "all animations in scene" is disabled because the Collada Importer can not handle this reliably at the moment (work in progres). * Support for Animation Clip export Added one extra level to the exported animations such that now all scene animations are enclosed: <Animation name="id_name(ob)_Action"> <Animation>...</Animation> ... </Animation> Animation Importer: * Import of animations for objects with multiple materials When importing multiple materials for one object, the imported material animation curves have all been assigned to the first material in the object. Error handling (wip): The Importer was a bit confused as it sometimes ignored fatal parsing errors and continued to import. I did my best to unconfuse it, but i believe that this needs to be tested more. Refactoring: update : move generation of effect id names into own function update : adjust importer/exporter for no longer supported HEMI lights cleanup: Removed no lopnger existing attribute from the exporter presets cleanup: Removed not needed Context attribute from DocumentExporter fix : Avoid duplicate deletion of temporary items cleanup: fixed indentation and white space issues update : Make BCAnimation class more self contained cleanup: Renamed classes, updated comments for better reading cleanup: Moved static class functions to collada_utils cleanup: Moved typedefs to more intuitive locations cleanup: indentation and class method declarations cleanup: Removed no longer needed methods update : Moved Classes into separate files cleanup: Added comments cleanup: take care of name conventions ... : many more small changes, not helpful to list them all
Diffstat (limited to 'source/blender/collada/AnimationExporter.cpp')
-rw-r--r--source/blender/collada/AnimationExporter.cpp2028
1 files changed, 438 insertions, 1590 deletions
diff --git a/source/blender/collada/AnimationExporter.cpp b/source/blender/collada/AnimationExporter.cpp
index 4113e871e74..4491b7412a6 100644
--- a/source/blender/collada/AnimationExporter.cpp
+++ b/source/blender/collada/AnimationExporter.cpp
@@ -26,656 +26,338 @@
#include "GeometryExporter.h"
#include "AnimationExporter.h"
+#include "AnimationClipExporter.h"
+#include "BCAnimationSampler.h"
#include "MaterialExporter.h"
+#include "collada_utils.h"
-template<class Functor>
-void forEachObjectInExportSet(Scene *sce, Functor &f, LinkNode *export_set)
-{
- LinkNode *node;
- for (node = export_set; node; node = node->next) {
- Object *ob = (Object *)node->link;
- f(ob);
- }
-}
+std::string EMPTY_STRING;
-bool AnimationExporter::exportAnimations(Main *bmain, Scene *sce)
+std::string AnimationExporter::get_axis_name(std::string channel, int id)
{
- bool has_animations = hasAnimations(sce);
- m_bmain = bmain;
- if (has_animations) {
- this->scene = sce;
+ static std::map<std::string, std::vector<std::string>> BC_COLLADA_AXIS_FROM_TYPE = {
+ { "color" ,{ "R", "G", "B" } },
+ { "specular_color",{ "R", "G", "B" } },
+ { "diffuse_color",{ "R", "G", "B" } },
+ { "alpha",{ "R", "G", "B" } },
+ { "scale",{ "X", "Y", "Z" } },
+ { "location",{ "X", "Y", "Z" } },
+ { "rotation_euler",{ "X", "Y", "Z" } }
+ };
- openLibrary();
+ std::map<std::string, std::vector<std::string>>::const_iterator it;
+ it = BC_COLLADA_AXIS_FROM_TYPE.find(channel);
+ if (it == BC_COLLADA_AXIS_FROM_TYPE.end())
+ return "";
- forEachObjectInExportSet(sce, *this, this->export_settings->export_set);
-
- closeLibrary();
- }
- return has_animations;
+ const std::vector<std::string> &subchannel = it->second;
+ if (id >= subchannel.size())
+ return "";
+ return subchannel[id];
}
-bool AnimationExporter::is_flat_line(std::vector<float> &values, int channel_count)
+bool AnimationExporter::open_animation_container(bool has_container, Object *ob)
{
- for (int i = 0; i < values.size(); i += channel_count) {
- for (int j = 0; j < channel_count; j++) {
- if (!bc_in_range(values[j], values[i+j], 0.000001))
- return false;
- }
+ if (!has_container) {
+ char anim_id[200];
+ sprintf(anim_id, "action_container-%s", translate_id(id_name(ob)).c_str());
+ openAnimation(anim_id, encode_xml(id_name(ob)));
}
return true;
}
-/*
- * 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];
-
- if (is_flat_line(values, channel_count))
- return;
-
- 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);
- else if (channel_count == 16)
- output_id = create_4x4_source(times, values, 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 information
- * 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)
+void AnimationExporter::openAnimationWithClip(std::string action_id, std::string action_name)
{
- FCurve *fcu = (FCurve *)ob->adt->action->curves.first;
- if (!fcu) {
- return; /* object has no animation */
- }
-
- if (this->export_settings->export_transformation_type == BC_TRANSFORMATION_TYPE_MATRIX) {
+ std::vector<std::string> anim_meta_entry;
+ anim_meta_entry.push_back(translate_id(action_id));
+ anim_meta_entry.push_back(action_name);
+ anim_meta.push_back(anim_meta_entry);
- std::vector<float> ctimes;
- find_keyframes(ob, ctimes);
- if (ctimes.size() > 0)
- export_sampled_matrix_animation(ob, ctimes);
- }
- else {
- 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;
- }
- }
+ openAnimation(translate_id(action_id), action_name);
}
-/*
- * 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)
+void AnimationExporter::close_animation_container(bool has_container)
{
- std::vector<float>ctimes;
- find_sampleframes(ob, ctimes);
- if (ctimes.size() > 0) {
- if (this->export_settings->export_transformation_type == BC_TRANSFORMATION_TYPE_MATRIX)
- export_sampled_matrix_animation(ob, ctimes);
- else
- export_sampled_transrotloc_animation(ob, ctimes);
- }
+ if (has_container)
+ closeAnimation();
}
-void AnimationExporter::export_sampled_matrix_animation(Object *ob, std::vector<float> &ctimes)
+bool AnimationExporter::exportAnimations()
{
- UnitConverter converter;
+ Scene *sce = blender_context.get_scene();
- std::vector<float> values;
+ LinkNode &export_set = *this->export_settings->export_set;
+ bool has_anim_data = bc_has_animations(sce, export_set);
+ int animation_count = 0;
+ if (has_anim_data) {
- for (std::vector<float>::iterator ctime = ctimes.begin(); ctime != ctimes.end(); ++ctime) {
- float fmat[4][4];
+ BCObjectSet animated_subset;
+ BCAnimationSampler::get_animated_from_export_set(animated_subset, export_set);
+ animation_count = animated_subset.size();
+ BCAnimationSampler animation_sampler(blender_context, animated_subset);
- bc_update_scene(m_bmain, depsgraph, scene, *ctime);
- BKE_object_matrix_local_get(ob, fmat);
- if (this->export_settings->limit_precision)
- bc_sanitize_mat(fmat, 6);
-
- for (int i = 0; i < 4; i++)
- for (int j = 0; j < 4; j++)
- values.push_back(fmat[i][j]);
- }
+ try {
+ animation_sampler.sample_scene(
+ export_settings->sampling_rate,
+ /*keyframe_at_end = */ true,
+ export_settings->open_sim,
+ export_settings->keep_keyframes,
+ export_settings->export_animation_type
+ );
- std::string ob_name = id_name(ob);
+ openLibrary();
- create_sampled_animation(16, ctimes, values, ob_name, "transform", "", false);
-}
+ BCObjectSet::iterator it;
+ for (it = animated_subset.begin(); it != animated_subset.end(); ++it) {
+ Object *ob = *it;
+ exportAnimation(ob, animation_sampler);
+ }
+ }
+ catch (std::invalid_argument &iae)
+ {
+ fprintf(stderr, "Animation export interrupted");
+ fprintf(stderr, "Exception was: %s", iae.what());
+ }
-void AnimationExporter::export_sampled_transrotloc_animation(Object *ob, std::vector<float> &ctimes)
-{
- static int LOC = 0;
- static int EULX = 1;
- static int EULY = 2;
- static int EULZ = 3;
- static int SCALE = 4;
-
- std::vector<float> baked_curves[5];
-
- 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];
-
- bc_update_scene(m_bmain, depsgraph, scene, *ctime);
- 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]);
+ closeLibrary();
+#if 0
+ /* TODO: If all actions shall be exported, we need to call the
+ * AnimationClipExporter which will figure out which actions
+ * need to be exported for which objects
+ */
+ if (this->export_settings->include_all_actions) {
+ AnimationClipExporter ace(eval_ctx, sw, export_settings, anim_meta);
+ ace.exportAnimationClips(sce);
+ }
+#endif
}
-
- std::string ob_name = id_name(ob);
-
- create_sampled_animation(3, ctimes, baked_curves[SCALE], ob_name, "scale", "", false);
- create_sampled_animation(3, ctimes, 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, ctimes, baked_curves[EULX], ob_name, "rotation", "X", true);
- create_sampled_animation(1, ctimes, baked_curves[EULY], ob_name, "rotation", "Y", true);
- create_sampled_animation(1, ctimes, baked_curves[EULZ], ob_name, "rotation", "Z", true);
-
- fprintf(stdout, "Animation Export: Baked %d frames for %s (sampling rate: %d)\n",
- (int)baked_curves[0].size(),
- ob->id.name,
- this->export_settings->sampling_rate);
+ return animation_count;
}
/* called for each exported object */
-void AnimationExporter::operator()(Object *ob)
+void AnimationExporter::exportAnimation(Object *ob, BCAnimationSampler &sampler)
{
- char *transformName;
+ bool container_is_open = false;
- /* bool isMatAnim = false; */ /* UNUSED */
+ //Transform animations (trans, rot, scale)
+ container_is_open = open_animation_container(container_is_open, ob);
- //Export transform animations
- if (ob->adt && ob->adt->action) {
+ /* Now take care of the Object Animations
+ * Note: For Armatures the skeletal animation has already been exported (see above)
+ * However Armatures also can have Object animation.
+ */
+ bool export_as_matrix = this->export_settings->export_transformation_type == BC_TRANSFORMATION_TYPE_MATRIX;
+ if (export_as_matrix) {
+ export_matrix_animation(ob, sampler); // export all transform_curves as one single matrix animation
+ }
- if (ob->type == OB_ARMATURE) {
- /* Export skeletal animation (if any)*/
- bArmature *arm = (bArmature *)ob->data;
- for (Bone *bone = (Bone *)arm->bonebase.first; bone; bone = bone->next)
- write_bone_animation_matrix(ob, bone);
- }
+ export_curve_animation_set(ob, sampler, export_as_matrix);
- /* Armatures can have object animation and skeletal animation*/
- if (this->export_settings->sampling_rate < 1) {
- export_keyframed_animation_set(ob);
- }
- else {
- export_sampled_animation_set(ob);
- }
- }
+ if (ob->type == OB_ARMATURE) {
- export_object_constraint_animation(ob);
+#ifdef WITH_MORPH_ANIMATION
+ /* TODO: This needs to be handled by extra profiles, postponed for now */
+ export_morph_animation(ob);
+#endif
- //This needs to be handled by extra profiles, so postponed for now
- //export_morph_animation(ob);
+ /* Export skeletal animation (if any) */
+ bArmature *arm = (bArmature *)ob->data;
+ for (Bone *root_bone = (Bone *)arm->bonebase.first; root_bone; root_bone = root_bone->next)
+ export_bone_animations_recursive(ob, root_bone, sampler);
+ }
- //Export Lamp parameter animations
- if ( (ob->type == OB_LAMP) && ((Lamp *)ob->data)->adt && ((Lamp *)ob->data)->adt->action) {
- FCurve *fcu = (FCurve *)(((Lamp *)ob->data)->adt->action->curves.first);
- while (fcu) {
- transformName = extract_transform_name(fcu->rna_path);
+ close_animation_container(container_is_open);
+}
- if ((STREQ(transformName, "color")) || (STREQ(transformName, "spot_size")) ||
- (STREQ(transformName, "spot_blend")) || (STREQ(transformName, "distance")))
- {
- create_keyframed_animation(ob, fcu, transformName, true);
- }
- fcu = fcu->next;
+/*
+ * Export all animation FCurves of an Object.
+ *
+ * Note: This uses the keyframes as sample points,
+ * and exports "baked keyframes" while keeping the tangent information
+ * of the FCurves intact. This works for simple cases, but breaks
+ * especially when negative scales are involved in the animation.
+ * And when parent inverse matrices are involved (when exporting
+ * object hierarchies)
+ *
+ */
+void AnimationExporter::export_curve_animation_set(Object *ob, BCAnimationSampler &sampler, bool export_as_matrix)
+{
+ BCAnimationCurveMap *curves = sampler.get_curves(ob);
+
+ BCAnimationCurveMap::iterator it;
+ for (it = curves->begin(); it != curves->end(); ++it) {
+ BCAnimationCurve &curve = *it->second;
+ if (curve.get_channel_target() == "rotation_quaternion") {
+ /*
+ Can not export Quaternion animation in Collada as far as i know)
+ Maybe automatically convert to euler rotation?
+ Discard for now.
+ */
+ continue;
+ }
+
+ if (export_as_matrix && curve.is_transform_curve()) {
+ /* All Transform curves will be exported within a single matrix animation,
+ * see export_matrix_animation()
+ * No need to export the curves here again.
+ */
+ continue;
}
- }
- //Export Camera parameter animations
- if ( (ob->type == OB_CAMERA) && ((Camera *)ob->data)->adt && ((Camera *)ob->data)->adt->action) {
- FCurve *fcu = (FCurve *)(((Camera *)ob->data)->adt->action->curves.first);
- while (fcu) {
- transformName = extract_transform_name(fcu->rna_path);
-
- if ((STREQ(transformName, "lens")) ||
- (STREQ(transformName, "ortho_scale")) ||
- (STREQ(transformName, "clip_end")) ||
- (STREQ(transformName, "clip_start")))
- {
- create_keyframed_animation(ob, fcu, transformName, true);
- }
- fcu = fcu->next;
+ if (!curve.is_animated()) {
+ continue;
}
- }
- //Export Material parameter animations.
- for (int a = 0; a < ob->totcol; a++) {
- Material *ma = give_current_material(ob, a + 1);
- if (!ma) continue;
- if (ma->adt && ma->adt->action) {
- /* isMatAnim = true; */
- FCurve *fcu = (FCurve *)ma->adt->action->curves.first;
- while (fcu) {
- transformName = extract_transform_name(fcu->rna_path);
-
- if ((STREQ(transformName, "specular_hardness")) || (STREQ(transformName, "specular_color")) ||
- (STREQ(transformName, "diffuse_color")) || (STREQ(transformName, "alpha")) ||
- (STREQ(transformName, "ior")))
- {
- create_keyframed_animation(ob, fcu, transformName, true, ma);
- }
- fcu = fcu->next;
- }
+ BCAnimationCurve *mcurve = get_modified_export_curve(ob, curve, *curves);
+ if (mcurve) {
+ export_curve_animation(ob, *mcurve);
+ delete mcurve;
+ }
+ else {
+ export_curve_animation(ob, curve);
}
}
}
-void AnimationExporter::export_object_constraint_animation(Object *ob)
+void AnimationExporter::export_matrix_animation(Object *ob, BCAnimationSampler &sampler)
{
- std::vector<float> fra;
- //Takes frames of target animations
- make_anim_frames_from_targets(ob, fra);
-
- if (fra.size())
- dae_baked_object_animation(fra, ob);
-}
-
-void AnimationExporter::export_morph_animation(Object *ob)
-{
- FCurve *fcu;
- char *transformName;
- Key *key = BKE_key_from_object(ob);
- if (!key) return;
-
- if (key->adt && key->adt->action) {
- fcu = (FCurve *)key->adt->action->curves.first;
-
- while (fcu) {
- transformName = extract_transform_name(fcu->rna_path);
+ std::vector<float> frames;
+ sampler.get_object_frames(frames, ob);
+ if (frames.size() > 0) {
+ BCMatrixSampleMap samples;
+ bool is_animated = sampler.get_object_samples(samples, ob);
+ if (is_animated) {
+ bAction *action = bc_getSceneObjectAction(ob);
+ std::string name = encode_xml(id_name(ob));
+ std::string action_name = (action == NULL) ? name + "-action" : id_name(action);
+ std::string channel_type = "transform";
+ std::string axis = "";
+ std::string id = bc_get_action_id(action_name, name, channel_type, axis);
- create_keyframed_animation(ob, fcu, transformName, true);
+ std::string target = translate_id(name) + '/' + channel_type;
- fcu = fcu->next;
+ export_collada_matrix_animation(id, name, target, frames, samples);
}
}
-
}
-void AnimationExporter::make_anim_frames_from_targets(Object *ob, std::vector<float> &frames )
+//write bone animations in transform matrix sources
+void AnimationExporter::export_bone_animations_recursive(Object *ob, Bone *bone, BCAnimationSampler &sampler)
{
- ListBase *conlist = get_active_constraints(ob);
- if (conlist == NULL) return;
- bConstraint *con;
- for (con = (bConstraint *)conlist->first; con; con = con->next) {
- ListBase targets = {NULL, NULL};
-
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
-
- if (!validateConstraints(con)) continue;
-
- if (cti && cti->get_constraint_targets) {
- bConstraintTarget *ct;
- Object *obtar;
- /* get targets
- * - constraints should use ct->matrix, not directly accessing values
- * - ct->matrix members have not yet been calculated here!
- */
- cti->get_constraint_targets(con, &targets);
-
- for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) {
- obtar = ct->tar;
-
- if (obtar)
- find_keyframes(obtar, frames);
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 1);
+ std::vector<float> frames;
+ sampler.get_bone_frames(frames, ob, bone);
+
+ if (frames.size()) {
+ BCMatrixSampleMap samples;
+ bool is_animated = sampler.get_bone_samples(samples, ob, bone);
+ if (is_animated) {
+ export_bone_animation(ob, bone, frames, samples);
}
}
+
+ for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next)
+ export_bone_animations_recursive(ob, child, sampler);
}
-//euler sources from quternion sources
-float *AnimationExporter::get_eul_source_for_quat(Object *ob)
-{
- FCurve *fcu = (FCurve *)ob->adt->action->curves.first;
- const int keys = fcu->totvert;
- float *quat = (float *)MEM_callocN(sizeof(float) * fcu->totvert * 4, "quat output source values");
- float *eul = (float *)MEM_callocN(sizeof(float) * fcu->totvert * 3, "quat output source values");
- float temp_quat[4];
- float temp_eul[3];
- while (fcu) {
- char *transformName = extract_transform_name(fcu->rna_path);
-
- if (STREQ(transformName, "rotation_quaternion") ) {
- for (int i = 0; i < fcu->totvert; i++) {
- *(quat + (i * 4) + fcu->array_index) = fcu->bezt[i].vec[1][1];
+/*
+* In some special cases the exported Curve needs to be replaced
+* by a modified curve (for collada purposes)
+* This method checks if a conversion is necessary and if applicable
+* returns a pointer to the modified BCAnimationCurve.
+* IMPORTANT: the modified curve must be deleted by the caller when no longer needed
+* if no conversion is needed this method returns a NULL;
+*/
+BCAnimationCurve *AnimationExporter::get_modified_export_curve(Object *ob, BCAnimationCurve &curve, BCAnimationCurveMap &curves)
+{
+ std::string channel_target = curve.get_channel_target();
+ BCAnimationCurve *mcurve = NULL;
+ if (channel_target == "lens") {
+
+ /* Create an xfov curve */
+
+ BCCurveKey key(BC_ANIMATION_TYPE_CAMERA, "xfov", 0);
+ mcurve = new BCAnimationCurve(key, ob);
+
+ // now tricky part: transform the fcurve
+ BCValueMap lens_values;
+ curve.get_value_map(lens_values);
+
+ BCAnimationCurve *sensor_curve = NULL;
+ BCCurveKey sensor_key(BC_ANIMATION_TYPE_CAMERA, "sensor_width", 0);
+ BCAnimationCurveMap::iterator cit = curves.find(sensor_key);
+ if (cit != curves.end()) {
+ sensor_curve = cit->second;
+ }
+
+ BCValueMap::const_iterator vit;
+ for (vit = lens_values.begin(); vit != lens_values.end(); ++vit) {
+ int frame = vit->first;
+ float lens_value = vit->second;
+
+ float sensor_value;
+ if (sensor_curve) {
+ sensor_value = sensor_curve->get_value(frame);
}
+ else {
+ sensor_value = ((Camera *)ob->data)->sensor_x;
+ }
+ float value = RAD2DEGF(focallength_to_fov(lens_value, sensor_value));
+ mcurve->add_value(value, frame);
}
- fcu = fcu->next;
+ mcurve->clean_handles(); // to reset the handles
}
-
- for (int i = 0; i < keys; i++) {
- for (int j = 0; j < 4; j++)
- temp_quat[j] = quat[(i * 4) + j];
-
- quat_to_eul(temp_eul, temp_quat);
-
- for (int k = 0; k < 3; k++)
- eul[i * 3 + k] = temp_eul[k];
-
- }
- MEM_freeN(quat);
- return eul;
-
-}
-
-//Get proper name for bones
-std::string AnimationExporter::getObjectBoneName(Object *ob, const FCurve *fcu)
-{
- //hard-way to derive the bone name from rna_path. Must find more compact method
- std::string rna_path = std::string(fcu->rna_path);
-
- char *boneName = strtok((char *)rna_path.c_str(), "\"");
- boneName = strtok(NULL, "\"");
-
- if (boneName != NULL)
- return /*id_name(ob) + "_" +*/ std::string(boneName);
- else
- return id_name(ob);
+ return mcurve;
}
-std::string AnimationExporter::getAnimationPathId(const FCurve *fcu)
+void AnimationExporter::export_curve_animation(
+ Object *ob,
+ BCAnimationCurve &curve)
{
- std::string rna_path = std::string(fcu->rna_path);
- return translate_id(rna_path);
-}
-
-/* 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];
-
- 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;
- return;
- }
-
- //axis names for colors
- else if (STREQ(transformName, "color") ||
- STREQ(transformName, "specular_color") ||
- STREQ(transformName, "diffuse_color") ||
- STREQ(transformName, "alpha"))
- {
- const char *axis_names[] = {"R", "G", "B"};
- if (fcu->array_index < 3)
- axis_name = axis_names[fcu->array_index];
- }
+ std::string channel_target = curve.get_channel_target();
/*
- * 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>.
+ * Some curves can not be exported as is and need some conversion
+ * For more information see implementation oif get_modified_export_curve()
+ * note: if mcurve is not NULL then it must be deleted at end of this method;
*/
- else if (
- STREQ(transformName, "scale") ||
- STREQ(transformName, "location") ||
- STREQ(transformName, "rotation_euler"))
- {
- const char *axis_names[] = {"X", "Y", "Z"};
- if (fcu->array_index < 3) {
- axis_name = axis_names[fcu->array_index];
- obj = ob;
- }
- }
- else {
- /* no axis name. single parameter */
- axis_name = "";
- }
+ int channel_index = curve.get_channel_index();
+ std::string axis = get_axis_name(channel_target, channel_index); // RGB or XYZ or ""
- std::string ob_name = std::string("null");
+ std::string action_name;
+ bAction *action = bc_getSceneObjectAction(ob);
+ action_name = (action) ? id_name(action) : "constraint_anim";
- /* Create anim Id */
- if (ob->type == OB_ARMATURE) {
- ob_name = getObjectBoneName(ob, fcu);
- BLI_snprintf(
- anim_id,
- sizeof(anim_id),
- "%s_%s.%s",
- (char *)translate_id(ob_name).c_str(),
- (char *)translate_id(transformName).c_str(),
- axis_name);
- }
- else {
- if (ma)
- ob_name = id_name(ob) + "_material";
- else
- ob_name = id_name(ob);
-
- BLI_snprintf(
- anim_id,
- sizeof(anim_id),
- "%s_%s_%s",
- (char *)translate_id(ob_name).c_str(),
- (char *)getAnimationPathId(fcu).c_str(),
- axis_name);
- }
-
- openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
-
- // create input source
- std::string input_id = create_source_from_fcurve(COLLADASW::InputSemantic::INPUT, fcu, anim_id, axis_name);
+ const std::string curve_name = encode_xml(curve.get_animation_name(ob));
+ std::string id = bc_get_action_id(action_name, curve_name, channel_target, axis, ".");
- // create output source
- std::string output_id;
+ std::string collada_target = translate_id(curve_name);
- //quat rotations are skipped for now, because of complications with determining axis.
- if (quatRotation) {
- float *eul = get_eul_source_for_quat(ob);
- float *eul_axis = (float *)MEM_callocN(sizeof(float) * fcu->totvert, "quat output source values");
- for (int i = 0; i < fcu->totvert; i++) {
- eul_axis[i] = eul[i * 3 + fcu->array_index];
+ if (curve.is_of_animation_type(BC_ANIMATION_TYPE_MATERIAL)) {
+ int material_index = curve.get_subindex();
+ Material *ma = give_current_material(ob, material_index + 1);
+ if (ma) {
+ collada_target = translate_id(id_name(ma)) + "-effect/common/" + get_collada_sid(curve, axis);
}
- output_id = create_source_from_array(COLLADASW::InputSemantic::OUTPUT, eul_axis, fcu->totvert, quatRotation, anim_id, axis_name);
- MEM_freeN(eul);
- MEM_freeN(eul_axis);
- }
- else if (STREQ(transformName, "lens") && (ob->type == OB_CAMERA)) {
- 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, obj);
+ collada_target += "/" + get_collada_sid(curve, axis);
}
- // create interpolations source
- std::string interpolation_id = create_interpolation_source(fcu, anim_id, axis_name, &has_tangents);
-
- // handle tangents (if required)
- std::string intangent_id;
- std::string outtangent_id;
-
- if (has_tangents) {
- // create in_tangent source
- intangent_id = create_source_from_fcurve(COLLADASW::InputSemantic::IN_TANGENT, fcu, anim_id, axis_name, obj);
+ export_collada_curve_animation(id, curve_name, collada_target, axis, curve);
- // create out_tangent source
- 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;
- 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));
-
- // this input is required
- sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
-
- if (has_tangents) {
- sampler.addInput(COLLADASW::InputSemantic::IN_TANGENT, COLLADABU::URI(empty, intangent_id));
- sampler.addInput(COLLADASW::InputSemantic::OUT_TANGENT, COLLADABU::URI(empty, outtangent_id));
- }
-
- addSampler(sampler);
-
- std::string target;
-
- if (!is_param)
- target = translate_id(ob_name) +
- "/" + get_transform_sid(fcu->rna_path, -1, axis_name, true);
- else {
- if (ob->type == OB_LAMP)
- target = get_light_id(ob) +
- "/" + get_light_param_sid(fcu->rna_path, -1, axis_name, true);
-
- if (ob->type == OB_CAMERA)
- target = get_camera_id(ob) +
- "/" + get_camera_param_sid(fcu->rna_path, -1, axis_name, true);
-
- if (ma)
- target = translate_id(id_name(ma)) + "-effect" +
- "/common/" /*profile common is only supported */ + get_transform_sid(fcu->rna_path, -1, axis_name, true);
- //if shape key animation, this is the main problem, how to define the channel targets.
- /*target = get_morph_id(ob) +
- "/value" +*/
- }
- addChannel(COLLADABU::URI(empty, sampler_id), target);
-
- closeAnimation();
}
-
-
-//write bone animations in transform matrix sources
-void AnimationExporter::write_bone_animation_matrix(Object *ob_arm, Bone *bone)
+void AnimationExporter::export_bone_animation(Object *ob, Bone *bone, BCFrames &frames, BCMatrixSampleMap &samples)
{
- if (!ob_arm->adt)
- return;
+ bAction* action = bc_getSceneObjectAction(ob);
+ std::string bone_name(bone->name);
+ std::string name = encode_xml(id_name(ob));
+ std::string id = bc_get_action_id(id_name(action), name, bone_name, "pose_matrix");
+ std::string target = translate_id(id_name(ob) + "_" + bone_name) + "/transform";
- //This will only export animations of bones in deform group.
- /* if (!is_bone_deform_group(bone)) return; */
-
- sample_and_write_bone_animation_matrix(ob_arm, bone);
-
- for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next)
- write_bone_animation_matrix(ob_arm, child);
+ export_collada_matrix_animation(id, name, target, frames, samples);
}
bool AnimationExporter::is_bone_deform_group(Bone *bone)
@@ -695,204 +377,86 @@ bool AnimationExporter::is_bone_deform_group(Bone *bone)
return false;
}
-void AnimationExporter::sample_and_write_bone_animation_matrix(Object *ob_arm, Bone *bone)
-{
- bArmature *arm = (bArmature *)ob_arm->data;
- int flag = arm->flag;
- std::vector<float> fra;
- //char prefix[256];
-
- //Check if there is a fcurve in the armature for the bone in param
- //when baking this check is not needed, solve every bone for every frame.
- /*FCurve *fcu = (FCurve *)ob_arm->adt->action->curves.first;
-
- while (fcu) {
- std::string bone_name = getObjectBoneName(ob_arm, fcu);
- int val = BLI_strcasecmp((char *)bone_name.c_str(), bone->name);
- if (val == 0) break;
- fcu = fcu->next;
- }
- if (!(fcu)) return;*/
+void AnimationExporter::export_collada_curve_animation(
+ std::string id,
+ std::string name,
+ std::string collada_target,
+ std::string axis,
+ BCAnimationCurve &curve)
+{
+ BCFrames frames;
+ BCValues values;
+ curve.get_frames(frames);
+ curve.get_values(values);
+ std::string channel_target = curve.get_channel_target();
- bPoseChannel *pchan = BKE_pose_channel_find_name(ob_arm->pose, bone->name);
- if (!pchan)
- return;
+ fprintf(stdout, "Export animation curve %s (%d control points)\n", id.c_str(), int(frames.size()));
+ openAnimation(id, name);
+ BC_animation_source_type source_type = (curve.is_rotation_curve()) ? BC_SOURCE_TYPE_ANGLE : BC_SOURCE_TYPE_VALUE;
+ std::string input_id = collada_source_from_values(BC_SOURCE_TYPE_TIMEFRAME, COLLADASW::InputSemantic::INPUT, frames, id, axis);
+ std::string output_id = collada_source_from_values(source_type, COLLADASW::InputSemantic::OUTPUT, values, id, axis);
- if (this->export_settings->sampling_rate < 1)
- find_keyframes(ob_arm, fra);
+ bool has_tangents = false;
+ std::string interpolation_id;
+ if (this->export_settings->keep_smooth_curves)
+ interpolation_id = collada_interpolation_source(curve, id, axis, &has_tangents);
else
- find_sampleframes(ob_arm, fra);
+ interpolation_id = collada_linear_interpolation_source(frames.size(), id);
- if (flag & ARM_RESTPOS) {
- arm->flag &= ~ARM_RESTPOS;
- BKE_pose_where_is(depsgraph, scene, ob_arm);
- }
-
- if (fra.size()) {
- dae_baked_animation(fra, ob_arm, bone);
+ std::string intangent_id;
+ std::string outtangent_id;
+ if (has_tangents) {
+ intangent_id = collada_tangent_from_curve(COLLADASW::InputSemantic::IN_TANGENT, curve, id, axis);
+ outtangent_id = collada_tangent_from_curve(COLLADASW::InputSemantic::OUT_TANGENT, curve, id, axis);
}
- if (flag & ARM_RESTPOS)
- arm->flag = flag;
- BKE_pose_where_is(depsgraph, scene, ob_arm);
-}
-
-void AnimationExporter::dae_baked_animation(std::vector<float> &fra, Object *ob_arm, Bone *bone)
-{
- std::string ob_name = id_name(ob_arm);
- std::string bone_name = bone->name;
- char anim_id[200];
-
- if (!fra.size())
- return;
-
- BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s_%s", (char *)translate_id(ob_name).c_str(),
- (char *)translate_id(bone_name).c_str(), "pose_matrix");
-
- openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
-
- // create input source
- std::string input_id = create_source_from_vector(COLLADASW::InputSemantic::INPUT, fra, false, anim_id, "");
+ std::string sampler_id = std::string(id) + SAMPLER_ID_SUFFIX;
- // create output source
- std::string output_id;
-
- output_id = create_4x4_source(fra, ob_arm, bone, anim_id);
-
- // create interpolations source
- std::string interpolation_id = fake_interpolation_source(fra.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
+ sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(EMPTY_STRING, input_id));
+ sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(EMPTY_STRING, output_id));
+ sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(EMPTY_STRING, interpolation_id));
- // this input is required
- sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
+ if (has_tangents) {
+ sampler.addInput(COLLADASW::InputSemantic::IN_TANGENT, COLLADABU::URI(EMPTY_STRING, intangent_id));
+ sampler.addInput(COLLADASW::InputSemantic::OUT_TANGENT, COLLADABU::URI(EMPTY_STRING, outtangent_id));
+ }
addSampler(sampler);
-
- std::string target = get_joint_id(ob_arm, bone) + "/transform";
- addChannel(COLLADABU::URI(empty, sampler_id), target);
+ addChannel(COLLADABU::URI(EMPTY_STRING, sampler_id), collada_target);
closeAnimation();
}
-void AnimationExporter::dae_baked_object_animation(std::vector<float> &fra, Object *ob)
+void AnimationExporter::export_collada_matrix_animation(std::string id, std::string name, std::string target, BCFrames &frames, BCMatrixSampleMap &samples)
{
- std::string ob_name = id_name(ob);
- char anim_id[200];
-
- if (!fra.size())
- return;
-
- BLI_snprintf(anim_id, sizeof(anim_id), "%s_%s", (char *)translate_id(ob_name).c_str(),
- "object_matrix");
-
- openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
+ fprintf(stdout, "Export animation matrix %s (%d control points)\n", id.c_str(), int(frames.size()));
- // create input source
- std::string input_id = create_source_from_vector(COLLADASW::InputSemantic::INPUT, fra, false, anim_id, "");
+ openAnimationWithClip(id, name);
- // create output source
- std::string output_id;
- output_id = create_4x4_source( fra, ob, NULL, anim_id);
+ std::string input_id = collada_source_from_values(BC_SOURCE_TYPE_TIMEFRAME, COLLADASW::InputSemantic::INPUT, frames, id, "");
+ std::string output_id = collada_source_from_values(samples, id);
+ std::string interpolation_id = collada_linear_interpolation_source(frames.size(), id);
- // create interpolations source
- std::string interpolation_id = fake_interpolation_source(fra.size(), anim_id, "");
-
- std::string sampler_id = std::string(anim_id) + SAMPLER_ID_SUFFIX;
+ std::string sampler_id = std::string(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
-
- // this input is required
- sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
-
- addSampler(sampler);
- std::string target = translate_id(ob_name) + "/transform";
- addChannel(COLLADABU::URI(empty, sampler_id), target);
- closeAnimation();
-}
-
-// dae_bone_animation -> add_bone_animation
-// (blend this into dae_bone_animation)
-void AnimationExporter::dae_bone_animation(std::vector<float> &fra, float *values, 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];
- bool is_rot = tm_type == 0;
+ sampler.addInput(COLLADASW::InputSemantic::INPUT, COLLADABU::URI(EMPTY_STRING, input_id));
+ sampler.addInput(COLLADASW::InputSemantic::OUTPUT, COLLADABU::URI(EMPTY_STRING, output_id));
+ sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(EMPTY_STRING, interpolation_id));
- 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, false);
-
- 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());
-
- openAnimation(anim_id, COLLADABU::Utils::EMPTY_STRING);
-
- // create input source
- std::string input_id = create_source_from_vector(COLLADASW::InputSemantic::INPUT, fra, is_rot, anim_id, axis_name);
-
- // create output source
- std::string output_id;
- if (axis == -1)
- output_id = create_xyz_source(values, fra.size(), anim_id);
- else
- output_id = create_source_from_array(COLLADASW::InputSemantic::OUTPUT, values, fra.size(), is_rot, anim_id, axis_name);
-
- // create interpolations source
- std::string interpolation_id = fake_interpolation_source(fra.size(), anim_id, axis_name);
-
- 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
-
- // this input is required
- sampler.addInput(COLLADASW::InputSemantic::INTERPOLATION, COLLADABU::URI(empty, interpolation_id));
+ // Matrix animation has no tangents
addSampler(sampler);
-
- std::string target = translate_id(ob_name + "_" + bone_name) + "/" + transform_sid;
- addChannel(COLLADABU::URI(empty, sampler_id), target);
+ addChannel(COLLADABU::URI(EMPTY_STRING, sampler_id), target);
closeAnimation();
}
-float AnimationExporter::convert_time(float frame)
-{
- return FRA2TIME(frame);
-}
-
-float AnimationExporter::convert_angle(float angle)
-{
- return COLLADABU::Math::Utils::radToDegF(angle);
-}
-
std::string AnimationExporter::get_semantic_suffix(COLLADASW::InputSemantic::Semantics semantic)
{
switch (semantic) {
@@ -913,7 +477,10 @@ std::string AnimationExporter::get_semantic_suffix(COLLADASW::InputSemantic::Sem
}
void AnimationExporter::add_source_parameters(COLLADASW::SourceBase::ParameterNameList& param,
- COLLADASW::InputSemantic::Semantics semantic, bool is_rot, const char *axis, bool transform)
+ COLLADASW::InputSemantic::Semantics semantic,
+ bool is_rot,
+ const std::string axis,
+ bool transform)
{
switch (semantic) {
case COLLADASW::InputSemantic::INPUT:
@@ -924,7 +491,7 @@ void AnimationExporter::add_source_parameters(COLLADASW::SourceBase::ParameterNa
param.push_back("ANGLE");
}
else {
- if (axis) {
+ if (axis != "") {
param.push_back(axis);
}
else
@@ -948,262 +515,83 @@ void AnimationExporter::add_source_parameters(COLLADASW::SourceBase::ParameterNa
}
}
-void AnimationExporter::get_source_values(BezTriple *bezt, COLLADASW::InputSemantic::Semantics semantic, bool is_angle, float *values, int *length)
+std::string AnimationExporter::collada_tangent_from_curve(COLLADASW::InputSemantic::Semantics semantic, BCAnimationCurve &curve, const std::string& anim_id, std::string axis_name)
{
- switch (semantic) {
- case COLLADASW::InputSemantic::INPUT:
- *length = 1;
- values[0] = convert_time(bezt->vec[1][0]);
- break;
- case COLLADASW::InputSemantic::OUTPUT:
- *length = 1;
- if (is_angle) {
- values[0] = RAD2DEGF(bezt->vec[1][1]);
- }
- else {
- values[0] = bezt->vec[1][1];
- }
- break;
+ Scene *scene = blender_context.get_scene();
+ std::string channel = curve.get_channel_target();
- case COLLADASW::InputSemantic::IN_TANGENT:
- *length = 2;
- values[0] = convert_time(bezt->vec[0][0]);
- if (bezt->ipo != BEZT_IPO_BEZ) {
- // We're in a mixed interpolation scenario, set zero as it's irrelevant but value might contain unused data
- values[0] = 0;
- values[1] = 0;
- }
- else if (is_angle) {
- values[1] = RAD2DEGF(bezt->vec[0][1]);
- }
- else {
- values[1] = bezt->vec[0][1];
- }
- break;
+ const std::string source_id = anim_id + get_semantic_suffix(semantic);
- case COLLADASW::InputSemantic::OUT_TANGENT:
- *length = 2;
- values[0] = convert_time(bezt->vec[2][0]);
- if (bezt->ipo != BEZT_IPO_BEZ) {
- // We're in a mixed interpolation scenario, set zero as it's irrelevant but value might contain unused data
- values[0] = 0;
- values[1] = 0;
- }
- else if (is_angle) {
- values[1] = RAD2DEGF(bezt->vec[2][1]);
- }
- else {
- values[1] = bezt->vec[2][1];
- }
- break;
- default:
- *length = 0;
- break;
- }
-}
-
-// 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)
-{
- return create_source_from_fcurve(semantic, fcu, anim_id, axis_name, NULL);
-}
-
-void AnimationExporter::evaluate_anim_with_constraints(Object *ob, float ctime)
-{
- BKE_animsys_evaluate_animdata(depsgraph, 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(depsgraph, scene, &obtar->id, obtar->adt, ctime, ADT_RECALC_ANIM);
- BKE_object_where_is_calc_time(this->depsgraph, scene, obtar, ctime);
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 1);
- }
- }
- BKE_object_where_is_calc_time(this->depsgraph, scene, ob, ctime);
-}
-
-/*
- * 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;
+ bool is_angle = (bc_startswith(channel, "rotation") || channel == "spot_size");
COLLADASW::FloatSourceF source(mSW);
source.setId(source_id);
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
- source.setAccessorCount(fcu->totvert);
-
- switch (semantic) {
- 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;
- }
+ source.setAccessorCount(curve.sample_count());
+ source.setAccessorStride(2);
COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
add_source_parameters(param, semantic, is_angle, axis_name, false);
source.prepareToAppendValues();
- 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[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];
- }
+ const FCurve *fcu = curve.get_fcurve();
+ int tangent = (semantic == COLLADASW::InputSemantic::IN_TANGENT) ? 0 : 2;
- 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);
- }
- }
+ for (int i = 0; i < fcu->totvert; ++i) {
+ BezTriple &bezt = fcu->bezt[i];
- source.finish();
-
- return source_id;
-}
-
-/*
- * Similar to create_source_from_fcurve, but adds conversion of lens
- * animation data from focal length to FOV.
- */
-std::string AnimationExporter::create_lens_source_from_fcurve(Camera *cam, COLLADASW::InputSemantic::Semantics semantic, FCurve *fcu, const std::string& anim_id)
-{
- std::string source_id = anim_id + get_semantic_suffix(semantic);
+ float sampled_time = bezt.vec[tangent][0];
+ float sampled_val = bezt.vec[tangent][1];
- COLLADASW::FloatSourceF source(mSW);
- source.setId(source_id);
- source.setArrayId(source_id + ARRAY_ID_SUFFIX);
- source.setAccessorCount(fcu->totvert);
-
- source.setAccessorStride(1);
-
- COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
- add_source_parameters(param, semantic, false, "", false);
+ if (is_angle) {
+ sampled_val = RAD2DEGF(sampled_val);
+ }
- source.prepareToAppendValues();
+ source.appendValues(FRA2TIME(sampled_time));
+ source.appendValues(sampled_val);
- for (unsigned int i = 0; i < fcu->totvert; i++) {
- float values[3]; // be careful!
- int length = 0;
- get_source_values(&fcu->bezt[i], semantic, false, values, &length);
- for (int j = 0; j < length; j++)
- {
- float val = RAD2DEGF(focallength_to_fov(values[j], cam->sensor_x));
- source.appendValues(val);
- }
}
-
source.finish();
-
return source_id;
}
-/*
- * 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 AnimationExporter::collada_source_from_values(
+ BC_animation_source_type source_type,
+ COLLADASW::InputSemantic::Semantics semantic,
+ std::vector<float> &values,
+ const std::string& anim_id,
+ const std::string axis_name)
{
+ Scene *scene = blender_context.get_scene();
+ /* T can be float, int or double */
+
+ int stride = 1;
+ int entry_count = values.size() / stride;
std::string source_id = anim_id + get_semantic_suffix(semantic);
COLLADASW::FloatSourceF source(mSW);
source.setId(source_id);
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
- source.setAccessorCount(tot);
- source.setAccessorStride(1);
+ source.setAccessorCount(entry_count);
+ source.setAccessorStride(stride);
COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
- add_source_parameters(param, semantic, is_rot, axis_name, false);
+ add_source_parameters(param, semantic, source_type== BC_SOURCE_TYPE_ANGLE, axis_name, false);
source.prepareToAppendValues();
- for (int i = 0; i < tot; i++) {
- float val = v[i];
- ////if (semantic == COLLADASW::InputSemantic::INPUT)
- // val = convert_time(val);
- //else
- if (is_rot)
+ for (int i = 0; i < entry_count; i++) {
+ float val = values[i];
+ switch (source_type) {
+ case BC_SOURCE_TYPE_TIMEFRAME:
+ val = FRA2TIME(val);
+ break;
+ case BC_SOURCE_TYPE_ANGLE:
val = RAD2DEGF(val);
+ break;
+ default: break;
+ }
source.appendValues(val);
}
@@ -1213,39 +601,9 @@ std::string AnimationExporter::create_source_from_array(COLLADASW::InputSemantic
}
/*
- * 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);
-
- COLLADASW::FloatSourceF source(mSW);
- source.setId(source_id);
- source.setArrayId(source_id + ARRAY_ID_SUFFIX);
- source.setAccessorCount(fra.size());
- source.setAccessorStride(1);
-
- COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
- add_source_parameters(param, semantic, is_rot, axis_name, false);
-
- source.prepareToAppendValues();
-
- std::vector<float>::iterator it;
- for (it = fra.begin(); it != fra.end(); it++) {
- float val = *it;
- //if (semantic == COLLADASW::InputSemantic::INPUT)
- val = convert_time(val);
- /*else if (is_rot)
- val = convert_angle(val);*/
- source.appendValues(val);
- }
-
- source.finish();
-
- return source_id;
-}
-
-std::string AnimationExporter::create_4x4_source(std::vector<float> &ctimes, std::vector<float> &values , const std::string &anim_id)
+ * Create a collada matrix source for a set of samples
+*/
+std::string AnimationExporter::collada_source_from_values(BCMatrixSampleMap &samples, const std::string &anim_id)
{
COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT;
std::string source_id = anim_id + get_semantic_suffix(semantic);
@@ -1253,181 +611,38 @@ std::string AnimationExporter::create_4x4_source(std::vector<float> &ctimes, std
COLLADASW::Float4x4Source source(mSW);
source.setId(source_id);
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
- source.setAccessorCount(ctimes.size());
+ source.setAccessorCount(samples.size());
source.setAccessorStride(16);
COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
- add_source_parameters(param, semantic, false, NULL, true);
+ add_source_parameters(param, semantic, false, "", true);
source.prepareToAppendValues();
- std::vector<float>::iterator it;
-
- for (it = values.begin(); it != values.end(); it+=16) {
- float mat[4][4];
-
- bc_copy_m4_farray(mat, &*it);
-
- UnitConverter converter;
- double outmat[4][4];
- converter.mat4_to_dae_double(outmat, mat);
-
- if (this->export_settings->limit_precision)
- bc_sanitize_mat(outmat, 6);
-
- source.appendValues(outmat);
+ BCMatrixSampleMap::iterator it;
+ int precision = (this->export_settings->limit_precision) ? 6 : -1; // could be made configurable
+ for (it = samples.begin(); it != samples.end(); it++) {
+ const BCMatrix *sample = it->second;
+ double daemat[4][4];
+ sample->get_matrix(daemat, true, precision);
+ source.appendValues(daemat);
}
source.finish();
return source_id;
}
-std::string AnimationExporter::create_4x4_source(std::vector<float> &frames, Object *ob, Bone *bone, const std::string &anim_id)
-{
- bool is_bone_animation = ob->type == OB_ARMATURE && bone;
-
- COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT;
- std::string source_id = anim_id + get_semantic_suffix(semantic);
-
- COLLADASW::Float4x4Source source(mSW);
- source.setId(source_id);
- source.setArrayId(source_id + ARRAY_ID_SUFFIX);
- source.setAccessorCount(frames.size());
- source.setAccessorStride(16);
-
- COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
- add_source_parameters(param, semantic, false, NULL, true);
-
- source.prepareToAppendValues();
-
- bPoseChannel *parchan = NULL;
- bPoseChannel *pchan = NULL;
-
- if (is_bone_animation) {
- bPose *pose = ob->pose;
- pchan = BKE_pose_channel_find_name(pose, bone->name);
- if (!pchan)
- return "";
-
- parchan = pchan->parent;
-
- enable_fcurves(ob->adt->action, bone->name);
- }
-
- std::vector<float>::iterator it;
- 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, frame);
- bc_update_scene(m_bmain, depsgraph, scene, ctime);
- if (is_bone_animation) {
-
- if (pchan->flag & POSE_CHAIN) {
- enable_fcurves(ob->adt->action, NULL);
- BKE_animsys_evaluate_animdata(depsgraph, scene, &ob->id, ob->adt, ctime, ADT_RECALC_ALL);
- BKE_pose_where_is(depsgraph, scene, ob);
- }
- else {
- BKE_pose_where_is_bone(depsgraph, scene, ob, pchan, ctime, 1);
- }
-
- // compute bone local mat
- if (bone->parent) {
- invert_m4_m4(ipar, parchan->pose_mat);
- mul_m4_m4m4(mat, ipar, pchan->pose_mat);
- }
- 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
- */
- if (export_settings->open_sim) {
- float temp[4][4];
- copy_m4_m4(temp, bone->arm_mat);
- temp[3][0] = temp[3][1] = temp[3][2] = 0.0f;
- invert_m4(temp);
-
- mul_m4_m4m4(mat, mat, temp);
-
- if (bone->parent) {
- copy_m4_m4(temp, bone->parent->arm_mat);
- temp[3][0] = temp[3][1] = temp[3][2] = 0.0f;
-
- mul_m4_m4m4(mat, temp, mat);
- }
- }
-
- }
- else {
- copy_m4_m4(mat, ob->obmat);
- }
-
- UnitConverter converter;
-
- double outmat[4][4];
- converter.mat4_to_dae_double(outmat, mat);
-
- if (this->export_settings->limit_precision)
- bc_sanitize_mat(outmat, 6);
-
- source.appendValues(outmat);
-
- j++;
-
- BIK_release_tree(scene, ob, ctime);
- }
-
- if (ob->adt) {
- enable_fcurves(ob->adt->action, NULL);
- }
-
- source.finish();
-
- return source_id;
-}
-
-
-/*
- * 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;
- std::string source_id = anim_id + get_semantic_suffix(semantic);
-
- COLLADASW::FloatSourceF source(mSW);
- source.setId(source_id);
- source.setArrayId(source_id + ARRAY_ID_SUFFIX);
- source.setAccessorCount(tot);
- source.setAccessorStride(3);
-
- COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
- add_source_parameters(param, semantic, false, NULL, false);
-
- source.prepareToAppendValues();
-
- for (int i = 0; i < tot; i++) {
- source.appendValues(*v, *(v + 1), *(v + 2));
- v += 3;
- }
-
- source.finish();
-
- return source_id;
-}
-
-std::string AnimationExporter::create_interpolation_source(FCurve *fcu, const std::string& anim_id, const char *axis_name, bool *has_tangents)
+std::string AnimationExporter::collada_interpolation_source(const BCAnimationCurve &curve,
+ const std::string& anim_id,
+ const std::string axis,
+ bool *has_tangents)
{
std::string source_id = anim_id + get_semantic_suffix(COLLADASW::InputSemantic::INTERPOLATION);
COLLADASW::NameSource source(mSW);
source.setId(source_id);
source.setArrayId(source_id + ARRAY_ID_SUFFIX);
- source.setAccessorCount(fcu->totvert);
+ source.setAccessorCount(curve.sample_count());
source.setAccessorStride(1);
COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
@@ -1437,12 +652,17 @@ std::string AnimationExporter::create_interpolation_source(FCurve *fcu, const st
*has_tangents = false;
- for (unsigned int i = 0; i < fcu->totvert; i++) {
- if (fcu->bezt[i].ipo == BEZT_IPO_BEZ) {
+ std::vector<float>frames;
+ curve.get_frames(frames);
+
+ for (unsigned int i = 0; i < curve.sample_count(); i++) {
+ float frame = frames[i];
+ int ipo = curve.get_interpolation_type(frame);
+ if (ipo == BEZT_IPO_BEZ) {
source.appendValues(BEZIER_NAME);
*has_tangents = true;
}
- else if (fcu->bezt[i].ipo == BEZT_IPO_CONST) {
+ else if (ipo == BEZT_IPO_CONST) {
source.appendValues(STEP_NAME);
}
else { // BEZT_IPO_LIN
@@ -1456,7 +676,7 @@ std::string AnimationExporter::create_interpolation_source(FCurve *fcu, const st
return source_id;
}
-std::string AnimationExporter::fake_interpolation_source(int tot, const std::string& anim_id, const char *axis_name)
+std::string AnimationExporter::collada_linear_interpolation_source(int tot, const std::string& anim_id)
{
std::string source_id = anim_id + get_semantic_suffix(COLLADASW::InputSemantic::INTERPOLATION);
@@ -1480,474 +700,102 @@ std::string AnimationExporter::fake_interpolation_source(int tot, const std::str
return source_id;
}
-std::string AnimationExporter::get_light_param_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis)
-{
- std::string tm_name;
- // when given rna_path, determine tm_type from it
- if (rna_path) {
- char *name = extract_transform_name(rna_path);
-
- if (STREQ(name, "color"))
- tm_type = 1;
- else if (STREQ(name, "spot_size"))
- tm_type = 2;
- else if (STREQ(name, "spot_blend"))
- tm_type = 3;
- else if (STREQ(name, "distance"))
- tm_type = 4;
- else
- tm_type = -1;
- }
-
- switch (tm_type) {
- case 1:
- tm_name = "color";
- break;
- case 2:
- tm_name = "fall_off_angle";
- break;
- case 3:
- tm_name = "fall_off_exponent";
- break;
- case 4:
- tm_name = "blender/blender_dist";
- break;
-
- default:
- tm_name = "";
- break;
- }
-
- if (tm_name.size()) {
- if (axis_name[0])
- return tm_name + "." + std::string(axis_name);
- else
- return tm_name;
- }
-
- return std::string("");
-}
-
-std::string AnimationExporter::get_camera_param_sid(char *rna_path, int tm_type, const char *axis_name, bool append_axis)
+const std::string AnimationExporter::get_collada_name(std::string channel_target) const
{
- std::string tm_name;
- // when given rna_path, determine tm_type from it
- if (rna_path) {
- char *name = extract_transform_name(rna_path);
-
- if (STREQ(name, "lens"))
- tm_type = 0;
- else if (STREQ(name, "ortho_scale"))
- tm_type = 1;
- else if (STREQ(name, "clip_end"))
- tm_type = 2;
- else if (STREQ(name, "clip_start"))
- tm_type = 3;
-
- else
- tm_type = -1;
- }
-
- switch (tm_type) {
- case 0:
- tm_name = "xfov";
- break;
- case 1:
- tm_name = "xmag";
- break;
- case 2:
- tm_name = "zfar";
- break;
- case 3:
- tm_name = "znear";
- break;
-
- default:
- tm_name = "";
- break;
- }
-
- if (tm_name.size()) {
- if (axis_name[0])
- return tm_name + "." + std::string(axis_name);
- else
- return tm_name;
- }
-
- return std::string("");
+ /*
+ * Translation table to map FCurve animation types to Collada animation.
+ * Todo: Maybe we can keep the names from the fcurves here instead of
+ * mapping. However this is what i found in the old code. So keep
+ * this map for now.
+ */
+ static std::map<std::string, std::string> BC_CHANNEL_BLENDER_TO_COLLADA = {
+ { "rotation", "rotation" },
+ { "rotation_euler", "rotation" },
+ { "rotation_quaternion", "rotation" },
+ { "scale", "scale" },
+ { "location", "location" },
+
+ /* Materials */
+ { "specular_color", "specular" },
+ { "diffuse_color", "diffuse" },
+ { "ior", "index_of_refraction" },
+ { "specular_hardness", "specular_hardness" },
+ { "alpha", "alpha" },
+
+ /* Lamps */
+ { "color", "color" },
+ { "fall_off_angle", "falloff_angle" },
+ { "spot_size", "falloff_angle" },
+ { "fall_off_exponent", "falloff_exponent" },
+ { "spot_blend", "falloff_exponent" },
+ { "blender/blender_dist", "blender/blender_dist" }, // special blender profile (todo: make this more elegant)
+ { "distance", "blender/blender_dist" }, // special blender profile (todo: make this more elegant)
+
+ /* Cameras */
+ { "lens", "xfov" },
+ { "xfov", "xfov" },
+ { "xmag", "xmag" },
+ { "zfar", "zfar" },
+ { "znear", "znear" },
+ { "ortho_scale", "xmag" },
+ { "clip_end", "zfar" },
+ { "clip_start", "znear" }
+ };
+
+ std::map<std::string, std::string>::iterator name_it = BC_CHANNEL_BLENDER_TO_COLLADA.find(channel_target);
+ if (name_it == BC_CHANNEL_BLENDER_TO_COLLADA.end())
+ return "";
+
+ std::string tm_name = name_it->second;
+ return tm_name;
}
/*
* 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 AnimationExporter::get_collada_sid(const BCAnimationCurve &curve, const std::string axis_name)
{
- std::string tm_name;
- bool is_angle = false;
- // when given rna_path, determine tm_type from it
- if (rna_path) {
- char *name = extract_transform_name(rna_path);
-
- if (STREQ(name, "rotation_euler"))
- tm_type = 0;
- else if (STREQ(name, "rotation_quaternion"))
- tm_type = 1;
- else if (STREQ(name, "scale"))
- tm_type = 2;
- else if (STREQ(name, "location"))
- tm_type = 3;
- else if (STREQ(name, "specular_hardness"))
- tm_type = 4;
- else if (STREQ(name, "specular_color"))
- tm_type = 5;
- else if (STREQ(name, "diffuse_color"))
- tm_type = 6;
- else if (STREQ(name, "alpha"))
- tm_type = 7;
- else if (STREQ(name, "ior"))
- tm_type = 8;
+ std::string channel_target = curve.get_channel_target();
+ std::string tm_name = get_collada_name(channel_target);
- else
- tm_type = -1;
- }
+ bool is_angle = curve.is_rotation_curve();
- switch (tm_type) {
- case 0:
- case 1:
- tm_name = "rotation";
- is_angle = true;
- break;
- case 2:
- tm_name = "scale";
- break;
- case 3:
- tm_name = "location";
- break;
- case 4:
- tm_name = "shininess";
- break;
- case 5:
- tm_name = "specular";
- break;
- case 6:
- tm_name = "diffuse";
- break;
- case 7:
- tm_name = "transparency";
- break;
- case 8:
- tm_name = "index_of_refraction";
- break;
-
- default:
- tm_name = "";
- break;
- }
if (tm_name.size()) {
if (is_angle)
return tm_name + std::string(axis_name) + ".ANGLE";
else
- if (axis_name[0])
- return tm_name + "." + std::string(axis_name);
- else
- return tm_name;
- }
-
- return std::string("");
-}
-
-char *AnimationExporter::extract_transform_name(char *rna_path)
-{
- char *dot = strrchr(rna_path, '.');
- return dot ? (dot + 1) : rna_path;
-}
-
-/*
- * 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;
- char prefix[200];
-
- if (bone_name)
- BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone_name);
-
- for (fcu = (FCurve *)act->curves.first; fcu; fcu = fcu->next) {
- if (bone_name) {
- if (STREQLEN(fcu->rna_path, prefix, strlen(prefix)))
- fcu->flag &= ~FCURVE_DISABLED;
+ if (axis_name != "")
+ return tm_name + "." + std::string(axis_name);
else
- fcu->flag |= FCURVE_DISABLED;
- }
- else {
- fcu->flag &= ~FCURVE_DISABLED;
- }
+ return tm_name;
}
-}
-bool AnimationExporter::hasAnimations(Scene *sce)
-{
- LinkNode *node;
-
- for (node=this->export_settings->export_set; node; node=node->next) {
- Object *ob = (Object *)node->link;
-
- FCurve *fcu = 0;
- //Check for object transform animations
- if (ob->adt && ob->adt->action)
- fcu = (FCurve *)ob->adt->action->curves.first;
- //Check for Lamp parameter animations
- else if ( (ob->type == OB_LAMP) && ((Lamp *)ob->data)->adt && ((Lamp *)ob->data)->adt->action)
- fcu = (FCurve *)(((Lamp *)ob->data)->adt->action->curves.first);
- //Check for Camera parameter animations
- else if ( (ob->type == OB_CAMERA) && ((Camera *)ob->data)->adt && ((Camera *)ob->data)->adt->action)
- fcu = (FCurve *)(((Camera *)ob->data)->adt->action->curves.first);
-
- //Check Material Effect parameter animations.
- for (int a = 0; a < ob->totcol; a++) {
- Material *ma = give_current_material(ob, a + 1);
- if (!ma) continue;
- if (ma->adt && ma->adt->action) {
- fcu = (FCurve *)ma->adt->action->curves.first;
- }
- }
-
- //check shape key animation
- if (!fcu) {
- Key *key = BKE_key_from_object(ob);
- if (key && key->adt && key->adt->action)
- fcu = (FCurve *)key->adt->action->curves.first;
- }
- if (fcu)
- return true;
- }
- return false;
-}
-
-//------------------------------- Not used in the new system.--------------------------------------------------------
-void AnimationExporter::find_rotation_frames(Object *ob, std::vector<float> &fra, const char *prefix, int rotmode)
-{
- if (rotmode > 0)
- find_keyframes(ob, fra, prefix, "rotation_euler");
- else if (rotmode == ROT_MODE_QUAT)
- find_keyframes(ob, fra, prefix, "rotation_quaternion");
- /*else if (rotmode == ROT_MODE_AXISANGLE)
- ;*/
+ return 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)
+#ifdef WITH_MORPH_ANIMATION
+/* TODO: This function needs to be implemented similar to the material animation export
+So we have to update BCSample for this to work.
+*/
+void AnimationExporter::export_morph_animation(Object *ob, BCAnimationSampler &sampler)
{
- 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;
-
- for (; fcu; fcu = fcu->next) {
- if (prefix && !STREQLEN(prefix, fcu->rna_path, strlen(prefix)))
- continue;
-
- char *name = extract_transform_name(fcu->rna_path);
- if (STREQ(name, tm_name)) {
- 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::write_bone_animation(Object *ob_arm, Bone *bone)
-{
- if (!ob_arm->adt)
- return;
-
- //write bone animations for 3 transform types
- //i=0 --> rotations
- //i=1 --> scale
- //i=2 --> location
- 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 AnimationExporter::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 = BKE_pose_channel_find_name(ob_arm->pose, bone->name);
- if (!pchan)
- return;
- //Fill frame array with key frame values framed at \param:transform_type
- switch (transform_type) {
- case 0:
- find_rotation_frames(ob_arm, fra, prefix, pchan->rotmode);
- break;
- case 1:
- find_keyframes(ob_arm, fra, prefix, "scale");
- break;
- case 2:
- find_keyframes(ob_arm, fra, prefix, "location");
- break;
- default:
- return;
- }
-
- // exit rest position
- if (flag & ARM_RESTPOS) {
- arm->flag &= ~ARM_RESTPOS;
- BKE_pose_where_is(depsgraph, scene, ob_arm);
- }
- //v array will hold all values which will be exported.
- if (fra.size()) {
- float *values = (float *)MEM_callocN(sizeof(float) * 3 * fra.size(), "temp. anim frames");
- sample_animation(values, fra, transform_type, bone, ob_arm, pchan);
-
- if (transform_type == 0) {
- // write x, y, z curves separately if it is rotation
- float *axisValues = (float *)MEM_callocN(sizeof(float) * fra.size(), "temp. anim frames");
-
- for (int i = 0; i < 3; i++) {
- for (unsigned int j = 0; j < fra.size(); j++)
- axisValues[j] = values[j * 3 + i];
-
- dae_bone_animation(fra, axisValues, transform_type, i, id_name(ob_arm), bone->name);
- }
- MEM_freeN(axisValues);
- }
- else {
- // write xyz at once if it is location or scale
- dae_bone_animation(fra, values, transform_type, -1, id_name(ob_arm), bone->name);
- }
-
- MEM_freeN(values);
- }
-
- // restore restpos
- if (flag & ARM_RESTPOS)
- arm->flag = flag;
- BKE_pose_where_is(depsgraph, scene, ob_arm);
-}
-
-void AnimationExporter::sample_animation(float *v, std::vector<float> &frames, int type, Bone *bone, Object *ob_arm, bPoseChannel *pchan)
-{
- bPoseChannel *parchan = NULL;
- bPose *pose = ob_arm->pose;
-
- pchan = BKE_pose_channel_find_name(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];
+ FCurve *fcu;
+ Key *key = BKE_key_from_object(ob);
+ if (!key) return;
- float ctime = BKE_scene_frame_get_from_ctime(scene, *it);
+ if (key->adt && key->adt->action) {
+ fcu = (FCurve *)key->adt->action->curves.first;
+ while (fcu) {
+ BC_animation_transform_type tm_type = get_transform_type(fcu->rna_path);
- BKE_animsys_evaluate_animdata(depsgraph, scene, &ob_arm->id, ob_arm->adt, ctime, ADT_RECALC_ANIM);
- BKE_pose_where_is_bone(depsgraph, scene, ob_arm, pchan, ctime, 1);
+ create_keyframed_animation(ob, fcu, tm_type, true, sampler);
- // compute bone local mat
- if (bone->parent) {
- invert_m4_m4(ipar, parchan->pose_mat);
- mul_m4_m4m4(mat, ipar, pchan->pose_mat);
- }
- 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;
+ fcu = fcu->next;
}
-
- v += 3;
}
- enable_fcurves(ob_arm->adt->action, NULL);
-}
-
-bool AnimationExporter::validateConstraints(bConstraint *con)
-{
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- /* these we can skip completely (invalid constraints...) */
- if (cti == NULL)
- return false;
- if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF))
- return false;
-
- /* these constraints can't be evaluated anyway */
- if (cti->evaluate_constraint == NULL)
- return false;
-
- /* influence == 0 should be ignored */
- if (con->enforce == 0.0f)
- return false;
-
- /* validation passed */
- return true;
}
+#endif