From b7bd8d813fd92d25eceedc7b1f23894c12bba6f9 Mon Sep 17 00:00:00 2001 From: Gaia Clary Date: Sun, 2 Jun 2019 19:06:14 +0200 Subject: feature collada: Allow export/import of skeletal animations as curves --- source/blender/collada/AnimationExporter.cpp | 26 ++++++----- source/blender/collada/AnimationImporter.cpp | 66 ++++++++++++++++++---------- source/blender/collada/AnimationImporter.h | 3 +- source/blender/collada/ArmatureImporter.cpp | 35 +++++++++++++++ source/blender/collada/ArmatureImporter.h | 2 + source/blender/collada/BCAnimationCurve.cpp | 14 +++--- source/blender/collada/BCAnimationCurve.h | 3 ++ source/blender/collada/BCSampleData.cpp | 36 +++++++++++---- source/blender/collada/TransformWriter.cpp | 21 +-------- 9 files changed, 138 insertions(+), 68 deletions(-) (limited to 'source/blender/collada') diff --git a/source/blender/collada/AnimationExporter.cpp b/source/blender/collada/AnimationExporter.cpp index c30c0d4ea08..a2c629bd0f1 100644 --- a/source/blender/collada/AnimationExporter.cpp +++ b/source/blender/collada/AnimationExporter.cpp @@ -27,8 +27,9 @@ std::string EMPTY_STRING; -std::string AnimationExporter::get_axis_name(std::string channel, int id) +std::string AnimationExporter::get_axis_name(std::string channel_type, int id) { + static std::map> BC_COLLADA_AXIS_FROM_TYPE = { {"color", {"R", "G", "B"}}, {"specular_color", {"R", "G", "B"}}, @@ -39,7 +40,8 @@ std::string AnimationExporter::get_axis_name(std::string channel, int id) {"rotation_euler", {"X", "Y", "Z"}}}; std::map>::const_iterator it; - it = BC_COLLADA_AXIS_FROM_TYPE.find(channel); + + it = BC_COLLADA_AXIS_FROM_TYPE.find(channel_type); if (it == BC_COLLADA_AXIS_FROM_TYPE.end()) { return ""; } @@ -146,7 +148,7 @@ void AnimationExporter::exportAnimation(Object *ob, BCAnimationSampler &sampler) export_curve_animation_set(ob, sampler, export_as_matrix); - if (ob->type == OB_ARMATURE) { + if (ob->type == OB_ARMATURE && export_as_matrix) { #ifdef WITH_MORPH_ANIMATION /* TODO: This needs to be handled by extra profiles, postponed for now */ @@ -183,7 +185,8 @@ void AnimationExporter::export_curve_animation_set(Object *ob, BCAnimationCurveMap::iterator it; for (it = curves->begin(); it != curves->end(); ++it) { BCAnimationCurve &curve = *it->second; - if (curve.get_channel_target() == "rotation_quaternion") { + std::string channel_type = curve.get_channel_type(); + if (channel_type == "rotation_quaternion") { /* Can not export Quaternion animation in Collada as far as i know) * Maybe automatically convert to euler rotation? * Discard for now. */ @@ -286,9 +289,9 @@ BCAnimationCurve *AnimationExporter::get_modified_export_curve(Object *ob, BCAnimationCurve &curve, BCAnimationCurveMap &curves) { - std::string channel_target = curve.get_channel_target(); + std::string channel_type = curve.get_channel_type(); BCAnimationCurve *mcurve = NULL; - if (channel_target == "lens") { + if (channel_type == "lens") { /* Create an xfov curve */ @@ -339,7 +342,8 @@ void AnimationExporter::export_curve_animation(Object *ob, BCAnimationCurve &cur int channel_index = curve.get_channel_index(); /* RGB or XYZ or "" */ - std::string axis = get_axis_name(channel_target, channel_index); + std::string channel_type = curve.get_channel_type(); + std::string axis = get_axis_name(channel_type, channel_index); std::string action_name; bAction *action = bc_getSceneObjectAction(ob); @@ -767,7 +771,7 @@ std::string AnimationExporter::collada_linear_interpolation_source(int tot, return source_id; } -const std::string AnimationExporter::get_collada_name(std::string channel_target) const +const std::string AnimationExporter::get_collada_name(std::string channel_type) const { /* * Translation table to map FCurve animation types to Collada animation. @@ -811,11 +815,10 @@ const std::string AnimationExporter::get_collada_name(std::string channel_target {"clip_start", "znear"}}; std::map::iterator name_it = BC_CHANNEL_BLENDER_TO_COLLADA.find( - channel_target); + channel_type); if (name_it == BC_CHANNEL_BLENDER_TO_COLLADA.end()) { return ""; } - std::string tm_name = name_it->second; return tm_name; } @@ -828,7 +831,8 @@ std::string AnimationExporter::get_collada_sid(const BCAnimationCurve &curve, const std::string axis_name) { std::string channel_target = curve.get_channel_target(); - std::string tm_name = get_collada_name(channel_target); + std::string channel_type = curve.get_channel_type(); + std::string tm_name = get_collada_name(channel_type); bool is_angle = curve.is_rotation_curve(); diff --git a/source/blender/collada/AnimationImporter.cpp b/source/blender/collada/AnimationImporter.cpp index 4c96ebf2603..ef6c81efff7 100644 --- a/source/blender/collada/AnimationImporter.cpp +++ b/source/blender/collada/AnimationImporter.cpp @@ -170,6 +170,16 @@ void AnimationImporter::fcurve_deg_to_rad(FCurve *cu) } } +void AnimationImporter::fcurve_scale(FCurve *cu, int scale) +{ + for (unsigned int i = 0; i < cu->totvert; i++) { + /* TODO convert handles too */ + cu->bezt[i].vec[1][1] *= scale; + cu->bezt[i].vec[0][1] *= scale; + cu->bezt[i].vec[2][1] *= scale; + } +} + void AnimationImporter::fcurve_is_used(FCurve *fcu) { unused_curves.erase(std::remove(unused_curves.begin(), unused_curves.end(), fcu), @@ -451,7 +461,8 @@ virtual void AnimationImporter::change_eul_to_quat(Object *ob, bAction *act) /* sets the rna_path and array index to curve */ void AnimationImporter::modify_fcurve(std::vector *curves, const char *rna_path, - int array_index) + int array_index, + int scale) { std::vector::iterator it; int i; @@ -466,6 +477,10 @@ void AnimationImporter::modify_fcurve(std::vector *curves, fcu->array_index = array_index; } + if (scale != 1) { + fcurve_scale(fcu, scale); + } + fcurve_is_used(fcu); } } @@ -581,10 +596,20 @@ void AnimationImporter::Assign_transform_animations( modify_fcurve(curves, rna_path, 0); } else if (COLLADABU::Math::Vector3::UNIT_Y == axis) { - modify_fcurve(curves, rna_path, 1); + if (is_joint) { + modify_fcurve(curves, rna_path, 2, -1); // Bone animation from dae to blender + } + else { + modify_fcurve(curves, rna_path, 1); + } } else if (COLLADABU::Math::Vector3::UNIT_Z == axis) { - modify_fcurve(curves, rna_path, 2); + if (is_joint) { + modify_fcurve(curves, rna_path, 1); // Bone animation from dae to blender + } + else { + modify_fcurve(curves, rna_path, 2); + } } else { unused_fcurve(curves); @@ -1061,28 +1086,23 @@ void AnimationImporter::translate_Animations( apply_matrix_curves(ob, animcurves, root, node, transform); } else { - if (is_joint) { - add_bone_animation_sampled(ob, animcurves, root, node, transform); - } - else { - /* calculate rnapaths and array index of fcurves according to transformation and - * animation class */ - Assign_transform_animations( - transform, &bindings[j], &animcurves, is_joint, joint_path); - - std::vector::iterator iter; - /* Add the curves of the current animation to the object */ - for (iter = animcurves.begin(); iter != animcurves.end(); iter++) { - FCurve *fcu = *iter; - - BLI_addtail(AnimCurves, fcu); - fcurve_is_used(fcu); - } + /* calculate rnapaths and array index of fcurves according to transformation and + * animation class */ + Assign_transform_animations( + transform, &bindings[j], &animcurves, is_joint, joint_path); + + std::vector::iterator iter; + /* Add the curves of the current animation to the object */ + for (iter = animcurves.begin(); iter != animcurves.end(); iter++) { + FCurve *fcu = *iter; + + BLI_addtail(AnimCurves, fcu); + fcurve_is_used(fcu); } } } } - if (is_rotation && !is_joint) { + if (is_rotation && !(is_joint || is_matrix)) { ob->rotmode = ROT_MODE_EUL; } } @@ -1822,10 +1842,10 @@ Object *AnimationImporter::translate_animation_OLD( if (is_rotation || is_matrix) { if (is_joint) { bPoseChannel *chan = BKE_pose_channel_find_name(ob->pose, bone_name); - chan->rotmode = ROT_MODE_QUAT; + chan->rotmode = (is_matrix)? ROT_MODE_QUAT : ROT_MODE_EUL; } else { - ob->rotmode = ROT_MODE_QUAT; + ob->rotmode = (is_matrix) ? ROT_MODE_QUAT : ROT_MODE_EUL; } } diff --git a/source/blender/collada/AnimationImporter.h b/source/blender/collada/AnimationImporter.h index f15c02183c7..c62ffdbafd3 100644 --- a/source/blender/collada/AnimationImporter.h +++ b/source/blender/collada/AnimationImporter.h @@ -80,6 +80,7 @@ class AnimationImporter : private TransformReader, public AnimationImporterBase void animation_to_fcurves(COLLADAFW::AnimationCurve *curve); void fcurve_deg_to_rad(FCurve *cu); + void fcurve_scale(FCurve *cu, int scale); void fcurve_is_used(FCurve *fcu); @@ -194,7 +195,7 @@ class AnimationImporter : private TransformReader, public AnimationImporterBase int setAnimType(const COLLADAFW::Animatable *prop, int type, int addition); - void modify_fcurve(std::vector *curves, const char *rna_path, int array_index); + void modify_fcurve(std::vector *curves, const char *rna_path, int array_index, int scale=1); void unused_fcurve(std::vector *curves); // prerequisites: // animlist_map - map animlist id -> animlist diff --git a/source/blender/collada/ArmatureImporter.cpp b/source/blender/collada/ArmatureImporter.cpp index de66c6ebdb2..9bafc58a658 100644 --- a/source/blender/collada/ArmatureImporter.cpp +++ b/source/blender/collada/ArmatureImporter.cpp @@ -659,6 +659,11 @@ Object *ArmatureImporter::create_armature_bones(Main *bmain, SkinInfo &skin) ED_armature_from_edit(bmain, armature); ED_armature_edit_free(armature); + for (ri = root_joints.begin(); ri != root_joints.end(); ri++) { + COLLADAFW::Node *node = *ri; + set_bone_transformation_type(node, ob_arm); + } + ED_armature_to_edit(armature); if (this->import_settings->find_chains) { connect_bone_chains(armature, (Bone *)armature->bonebase.first, UNLIMITED_CHAIN_MAX); @@ -673,6 +678,20 @@ Object *ArmatureImporter::create_armature_bones(Main *bmain, SkinInfo &skin) return ob_arm; } +void ArmatureImporter::set_bone_transformation_type(const COLLADAFW::Node *node, Object *ob_arm) +{ + bPoseChannel *pchan = BKE_pose_channel_find_name(ob_arm->pose, bc_get_joint_name(node)); + if (pchan) { + pchan->rotmode = (node_is_decomposed(node)) ? ROT_MODE_EUL : ROT_MODE_QUAT; + } + + COLLADAFW::NodePointerArray childnodes = node->getChildNodes(); + for (int index = 0; index < childnodes.getCount(); index++) { + node = childnodes[index]; + set_bone_transformation_type(node, ob_arm); + } +} + void ArmatureImporter::set_pose(Object *ob_arm, COLLADAFW::Node *root_node, const char *parentname, @@ -684,9 +703,12 @@ void ArmatureImporter::set_pose(Object *ob_arm, /* object-space */ get_node_mat(obmat, root_node, NULL, NULL); + bool is_decomposed = node_is_decomposed(root_node); // if (*edbone) bPoseChannel *pchan = BKE_pose_channel_find_name(ob_arm->pose, bone_name); + pchan->rotmode = (is_decomposed) ? ROT_MODE_EUL : ROT_MODE_QUAT; + // else fprintf ( "", /* get world-space */ @@ -716,6 +738,19 @@ void ArmatureImporter::set_pose(Object *ob_arm, } } +bool ArmatureImporter::node_is_decomposed(const COLLADAFW::Node *node) +{ + const COLLADAFW::TransformationPointerArray &nodeTransforms = node->getTransformations(); + for (unsigned int i = 0; i < nodeTransforms.getCount(); i++) { + COLLADAFW::Transformation *transform = nodeTransforms[i]; + COLLADAFW::Transformation::TransformationType tm_type = transform->getTransformationType(); + if (tm_type == COLLADAFW::Transformation::MATRIX) { + return false; + } + } + return true; +} + /** * root - if this joint is the top joint in hierarchy, if a joint * is a child of a node (not joint), root should be true since diff --git a/source/blender/collada/ArmatureImporter.h b/source/blender/collada/ArmatureImporter.h index 19f053c61fb..da92c04e5dc 100644 --- a/source/blender/collada/ArmatureImporter.h +++ b/source/blender/collada/ArmatureImporter.h @@ -123,6 +123,8 @@ class ArmatureImporter : private TransformReader { const char *parentname, float parent_mat[4][4]); + void set_bone_transformation_type(const COLLADAFW::Node *node, Object *ob_arm); + bool node_is_decomposed(const COLLADAFW::Node *node); #if 0 void set_leaf_bone_shapes(Object *ob_arm); void set_euler_rotmode(); diff --git a/source/blender/collada/BCAnimationCurve.cpp b/source/blender/collada/BCAnimationCurve.cpp index 57aa2f1bf29..2295821aaf8 100644 --- a/source/blender/collada/BCAnimationCurve.cpp +++ b/source/blender/collada/BCAnimationCurve.cpp @@ -174,7 +174,7 @@ const std::string BCAnimationCurve::get_animation_name(Object *ob) const } else { const char *boneName = BLI_str_quoted_substrN(fcurve->rna_path, "pose.bones["); - name = (boneName) ? std::string(boneName) : ""; + name = (boneName) ? id_name(ob)+"_"+std::string(boneName) : ""; } } break; @@ -331,15 +331,17 @@ void BCAnimationCurve::clean_handles() const bool BCAnimationCurve::is_transform_curve() const { - std::string channel_target = this->get_channel_target(); - return (is_rotation_curve() || channel_target == "scale" || channel_target == "location"); + std::string channel_type = this->get_channel_type(); + return (is_rotation_curve() || channel_type == "scale" || channel_type == "location"); } const bool BCAnimationCurve::is_rotation_curve() const { - std::string channel_target = this->get_channel_target(); - return (channel_target == "rotation" || channel_target == "rotation_euler" || - channel_target == "rotation_quaternion"); + std::string channel_type = this->get_channel_type(); + return (channel_type == "rotation" + || channel_type == "rotation_euler" + || channel_type == "rotation_quaternion" + ); } const float BCAnimationCurve::get_value(const float frame) diff --git a/source/blender/collada/BCAnimationCurve.h b/source/blender/collada/BCAnimationCurve.h index 989ec1d0101..1b97ea4a0ba 100644 --- a/source/blender/collada/BCAnimationCurve.h +++ b/source/blender/collada/BCAnimationCurve.h @@ -119,6 +119,9 @@ class BCAnimationCurve { const std::string get_animation_name(Object *ob) const; /* xxx: this is collada specific */ const std::string get_channel_target() const; + const std::string get_channel_type() const; + const std::string get_channel_posebone() const; // returns "" if channel is not a bone channel + const int get_channel_index() const; const int get_subindex() const; const std::string get_rna_path() const; diff --git a/source/blender/collada/BCSampleData.cpp b/source/blender/collada/BCSampleData.cpp index fff3c393a1d..2443ef9fcaa 100644 --- a/source/blender/collada/BCSampleData.cpp +++ b/source/blender/collada/BCSampleData.cpp @@ -42,17 +42,37 @@ void BCSample::add_bone_matrix(Bone *bone, Matrix &mat) /* Get channel value */ const bool BCSample::get_value(std::string channel_target, const int array_index, float *val) const { - if (channel_target == "location") { - *val = obmat.location()[array_index]; + std::string bname = bc_string_before(channel_target, "."); + std::string channel_type = bc_string_after(channel_target, "."); + + const BCMatrix *matrix = &obmat; + if (bname != channel_target) { + bname = bname.substr(2); + bname = bc_string_before(bname, "\""); + BCBoneMatrixMap::const_iterator it; + for (it = bonemats.begin(); it != bonemats.end(); ++it) { + Bone *bone = it->first; + if (bname == bone->name) { + matrix = it->second; + break; + } + } + } + else { + matrix = &obmat; + } + + if (channel_type == "location") { + *val = matrix->location()[array_index]; } - else if (channel_target == "scale") { - *val = obmat.scale()[array_index]; + else if (channel_type == "scale") { + *val = matrix->scale()[array_index]; } - else if (channel_target == "rotation" || channel_target == "rotation_euler") { - *val = obmat.rotation()[array_index]; + else if (channel_type == "rotation" || channel_type == "rotation_euler") { + *val = matrix->rotation()[array_index]; } - else if (channel_target == "rotation_quat") { - *val = obmat.quat()[array_index]; + else if (channel_type == "rotation_quaternion") { + *val = matrix->quat()[array_index]; } else { *val = 0; diff --git a/source/blender/collada/TransformWriter.cpp b/source/blender/collada/TransformWriter.cpp index bfeec813436..0a66db72cb9 100644 --- a/source/blender/collada/TransformWriter.cpp +++ b/source/blender/collada/TransformWriter.cpp @@ -25,23 +25,6 @@ #include "TransformWriter.h" -static BC_export_transformation_type get_transformation_type(BCExportSettings &export_settings) -{ - bool enforce_matrix_export = export_settings.get_include_animations(); - - return (enforce_matrix_export) ? BC_TRANSFORMATION_TYPE_MATRIX : - export_settings.get_object_transformation_type(); -} - -static BC_export_transformation_type get_transformation_type(Object *ob, - BCExportSettings &export_settings) -{ - bool enforce_matrix_export = ob->type == OB_ARMATURE && export_settings.get_include_animations(); - - return (enforce_matrix_export) ? BC_TRANSFORMATION_TYPE_MATRIX : - export_settings.get_object_transformation_type(); -} - void TransformWriter::add_joint_transform(COLLADASW::Node &node, float mat[4][4], float parent_mat[4][4], @@ -68,7 +51,7 @@ void TransformWriter::add_joint_transform(COLLADASW::Node &node, converter->mat4_to_dae_double(dmat, local); delete converter; - if (get_transformation_type(export_settings) == BC_TRANSFORMATION_TYPE_MATRIX) { + if (export_settings.get_object_transformation_type() == BC_TRANSFORMATION_TYPE_MATRIX) { node.addMatrix("transform", dmat); } else { @@ -96,7 +79,7 @@ void TransformWriter::add_node_transform_ob(COLLADASW::Node &node, bc_add_global_transform(f_obmat, export_settings.get_global_transform()); } - switch (get_transformation_type(ob, export_settings)) { + switch (export_settings.get_object_transformation_type()) { case BC_TRANSFORMATION_TYPE_MATRIX: { UnitConverter converter; double d_obmat[4][4]; -- cgit v1.2.3