[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [22111] branches/soc-2009-chingachgook/ source/blender/collada: Importer now creates skin vertex groups and reads vertex weights.
Chingiz Dyussenov
chingiz.ds at gmail.com
Sat Aug 1 08:44:19 CEST 2009
Revision: 22111
http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=22111
Author: chingachgook
Date: 2009-08-01 08:44:18 +0200 (Sat, 01 Aug 2009)
Log Message:
-----------
Importer now creates skin vertex groups and reads vertex weights.
Modified Paths:
--------------
branches/soc-2009-chingachgook/source/blender/collada/DocumentImporter.cpp
branches/soc-2009-chingachgook/source/blender/collada/SConscript
Modified: branches/soc-2009-chingachgook/source/blender/collada/DocumentImporter.cpp
===================================================================
--- branches/soc-2009-chingachgook/source/blender/collada/DocumentImporter.cpp 2009-08-01 06:27:40 UTC (rev 22110)
+++ branches/soc-2009-chingachgook/source/blender/collada/DocumentImporter.cpp 2009-08-01 06:44:18 UTC (rev 22111)
@@ -37,6 +37,10 @@
{
#include "ED_keyframing.h"
#include "ED_armature.h"
+#include "ED_mesh.h" // add_vert_to_defgroup, ...
+#include "ED_anim_api.h"
+#include "WM_types.h"
+#include "WM_api.h"
#include "BKE_main.h"
#include "BKE_customdata.h"
@@ -126,21 +130,39 @@
return "UNKNOWN";
}
+// works for COLLADAFW::Node, COLLADAFW::Geometry
+template<class T>
+const char *get_dae_name(T *node)
+{
+ const std::string& name = node->getName();
+ return name.size() ? name.c_str() : node->getOriginalId().c_str();
+}
+
+float get_float_value(const COLLADAFW::FloatOrDoubleArray& array, int index)
+{
+ if (array.getType() == COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT)
+ return array.getFloatValues()->getData()[index];
+ else
+ return array.getDoubleValues()->getData()[index];
+}
+
typedef std::map<COLLADAFW::TextureMapId, std::vector<MTex*> > TexIndexTextureArrayMap;
+// this is only for ArmatureImporter to "see" MeshImporter::get_object_by_geom_uid
+class MeshImporterBase
+{
+public:
+ virtual Object *get_object_by_geom_uid(const COLLADAFW::UniqueId& geom_uid) = 0;
+};
+
class ArmatureImporter
{
private:
Scene *scene;
UnitConverter *unit_converter;
- // to build armature bones from inverse bind matrices
- struct JointData {
- float inv_bind_mat[4][4]; // joint inverse bind matrix
- Object *ob_arm; // armature object
- };
- std::map<int, JointData> joint_index_to_joint_info_map;
- std::map<COLLADAFW::UniqueId, int> joint_id_to_joint_index_map;
+ // std::map<int, JointData> joint_index_to_joint_info_map;
+ // std::map<COLLADAFW::UniqueId, int> joint_id_to_joint_index_map;
struct LeafBone {
// COLLADAFW::Node *node;
@@ -155,17 +177,244 @@
// XXX not used
// float min_angle; // minimum angle between bone head-tail and a row of bone matrix
+#if 0
struct ArmatureJoints {
Object *ob_arm;
std::vector<COLLADAFW::Node*> root_joints;
};
std::vector<ArmatureJoints> armature_joints;
+#endif
Object *empty; // empty for leaf bones
+ std::map<COLLADAFW::UniqueId, COLLADAFW::UniqueId> geom_uid_by_controller_uid;
+ std::map<COLLADAFW::UniqueId, COLLADAFW::Node*> joint_by_uid; // contains all joints
std::vector<COLLADAFW::Node*> root_joints;
- std::map<COLLADAFW::UniqueId, COLLADAFW::UniqueId> controller_id_to_geom_id_map;
+ // This is used to store data passed in write_controller_data.
+ // Arrays from COLLADAFW::SkinControllerData lose ownership, so do this class members
+ // so that arrays don't get freed until we free them explicitly.
+ class SkinInfo
+ {
+ private:
+ // to build armature bones from inverse bind matrices
+ struct JointData {
+ float inv_bind_mat[4][4]; // joint inverse bind matrix
+ COLLADAFW::UniqueId joint_uid; // joint node UID
+ // Object *ob_arm; // armature object
+ };
+
+ float bind_shape_matrix[4][4];
+
+ // data from COLLADAFW::SkinControllerData, each array should be freed
+ COLLADAFW::UIntValuesArray joints_per_vertex;
+ COLLADAFW::UIntValuesArray weight_indices;
+ COLLADAFW::UIntValuesArray joint_indices;
+ // COLLADAFW::FloatOrDoubleArray weights;
+ std::vector<float> weights;
+
+ std::vector<JointData> joint_data; // index to this vector is joint index
+
+ UnitConverter *unit_converter;
+
+ Object *ob_arm;
+ COLLADAFW::UniqueId controller_uid;
+ public:
+
+ SkinInfo() {}
+
+ SkinInfo(const SkinInfo& skin) : weights(skin.weights),
+ joint_data(skin.joint_data),
+ unit_converter(skin.unit_converter),
+ ob_arm(skin.ob_arm),
+ controller_uid(skin.controller_uid)
+ {
+ Mat4CpyMat4(bind_shape_matrix, (float (*)[4])skin.bind_shape_matrix);
+
+ transfer_array_data_const(skin.joints_per_vertex, joints_per_vertex);
+ transfer_array_data_const(skin.weight_indices, weight_indices);
+ transfer_array_data_const(skin.joint_indices, joint_indices);
+ }
+
+ SkinInfo(UnitConverter *conv) : unit_converter(conv), ob_arm(NULL) {}
+
+ // nobody owns the data after this, so it should be freed manually with releaseMemory
+ void transfer_array_data(COLLADAFW::UIntValuesArray& src, COLLADAFW::UIntValuesArray& dest)
+ {
+ dest.setData((unsigned int*)src.getData(), src.getCount());
+ src.yieldOwnerShip();
+ dest.yieldOwnerShip();
+ }
+
+ // when src is const we cannot src.yieldOwnerShip, this is used by copy constructor
+ void transfer_array_data_const(const COLLADAFW::UIntValuesArray& src, COLLADAFW::UIntValuesArray& dest)
+ {
+ dest.setData((unsigned int*)src.getData(), src.getCount());
+ dest.yieldOwnerShip();
+ }
+
+ void borrow_skin_controller_data(const COLLADAFW::SkinControllerData* skin)
+ {
+ transfer_array_data((COLLADAFW::UIntValuesArray&)skin->getJointsPerVertex(), joints_per_vertex);
+ transfer_array_data((COLLADAFW::UIntValuesArray&)skin->getWeightIndices(), weight_indices);
+ transfer_array_data((COLLADAFW::UIntValuesArray&)skin->getJointIndices(), joint_indices);
+ // transfer_array_data(skin->getWeights(), weights);
+
+ // cannot transfer data for FloatOrDoubleArray, copy values manually
+ const COLLADAFW::FloatOrDoubleArray& weight = skin->getWeights();
+ for (int i = 0; i < weight.getValuesCount(); i++)
+ weights.push_back(get_float_value(weight, i));
+
+ unit_converter->mat4_from_dae(bind_shape_matrix, skin->getBindShapeMatrix());
+ }
+
+ void free()
+ {
+ joints_per_vertex.releaseMemory();
+ weight_indices.releaseMemory();
+ joint_indices.releaseMemory();
+ // weights.releaseMemory();
+ }
+
+ // using inverse bind matrices to construct armature
+ // it is safe to invert them to get the original matrices
+ // because if they are inverse matrices, they can be inverted
+ void add_joint(const COLLADABU::Math::Matrix4& matrix)
+ {
+ JointData jd;
+ unit_converter->mat4_from_dae(jd.inv_bind_mat, matrix);
+ joint_data.push_back(jd);
+ }
+
+ // called from write_controller
+ void create_armature(const COLLADAFW::SkinController* co, Scene *scene)
+ {
+ ob_arm = add_object(scene, OB_ARMATURE);
+
+ controller_uid = co->getUniqueId();
+
+ const COLLADAFW::UniqueIdArray& joint_uids = co->getJoints();
+ for (int i = 0; i < joint_uids.getCount(); i++) {
+ joint_data[i].joint_uid = joint_uids[i];
+
+ // // store armature pointer
+ // JointData& jd = joint_index_to_joint_info_map[i];
+ // jd.ob_arm = ob_arm;
+
+ // now we'll be able to get inv bind matrix from joint id
+ // joint_id_to_joint_index_map[joint_ids[i]] = i;
+ }
+ }
+
+ bool get_joint_inv_bind_matrix(float inv_bind_mat[][4], COLLADAFW::Node *node)
+ {
+ const COLLADAFW::UniqueId& uid = node->getUniqueId();
+ std::vector<JointData>::iterator it;
+ for (it = joint_data.begin(); it != joint_data.end(); it++) {
+ if ((*it).joint_uid == uid) {
+ Mat4CpyMat4(inv_bind_mat, (*it).inv_bind_mat);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ Object *get_armature()
+ {
+ return ob_arm;
+ }
+
+ const COLLADAFW::UniqueId& get_controller_uid()
+ {
+ return controller_uid;
+ }
+
+ // some nodes may not be referenced by SkinController,
+ // in this case to determine if the node belongs to this armature,
+ // we need to search down the tree
+ bool uses_joint(COLLADAFW::Node *node)
+ {
+ const COLLADAFW::UniqueId& uid = node->getUniqueId();
+ std::vector<JointData>::iterator it;
+ for (it = joint_data.begin(); it != joint_data.end(); it++) {
+ if ((*it).joint_uid == uid)
+ return true;
+ }
+
+ COLLADAFW::NodePointerArray& children = node->getChildNodes();
+ for (int i = 0; i < children.getCount(); i++) {
+ if (this->uses_joint(children[i]))
+ return true;
+ }
+
+ return false;
+ }
+
+ void link_armature(bContext *C, Object *ob, std::map<COLLADAFW::UniqueId, COLLADAFW::Node*>& joint_by_uid)
+ {
+ ob->parent = ob_arm;
+ ob->partype = PARSKEL;
+ ob->recalc |= OB_RECALC_OB|OB_RECALC_DATA;
+
+ ((bArmature*)ob_arm->data)->deformflag = ARM_DEF_VGROUP;
+
+ // we need armature matrix here... where do we get it from I wonder...
+ // root node/joint? or node with <instance_controller>?
+ float parmat[4][4];
+ Mat4One(parmat);
+ Mat4Invert(ob->parentinv, parmat);
+
+ // create all vertex groups
+ std::vector<JointData>::iterator it;
+ int joint_index;
+ for (it = joint_data.begin(), joint_index = 0; it != joint_data.end(); it++, joint_index++) {
+ const char *name = "Group";
+
+ // name group by joint node name
+ if (joint_by_uid.find((*it).joint_uid) != joint_by_uid.end()) {
+ name = get_dae_name(joint_by_uid[(*it).joint_uid]);
+ }
+
+ add_defgroup_name(ob, (char*)name);
+ }
+
+ // <vcount> - number of joints per vertex - joints_per_vertex
+ // <v> - [[bone index, weight index] * joints per vertex] * vertices - weight indices
+ // ^ bone index can be -1 meaning weight toward bind shape, how to express this in Blender?
+
+ // for each vertex in weight indices
+ // for each bone index in vertex
+ // add vertex to group at group index
+ // treat group index -1 specially
+
+ // get def group by index with BLI_findlink
+
+ for (int vertex = 0, weight = 0; vertex < joints_per_vertex.getCount(); vertex++) {
+
+ int limit = weight + joints_per_vertex[vertex];
+ for ( ; weight < limit; weight++) {
+ int joint = joint_indices[weight], joint_weight = weight_indices[weight];
+
+ // -1 means "weight towards the bind shape", we just don't assign it to any group
+ if (joint != -1) {
+ bDeformGroup *def = (bDeformGroup*)BLI_findlink(&ob->defbase, joint);
+
+ add_vert_to_defgroup(ob, def, vertex, weights[joint_weight], WEIGHT_REPLACE);
+ }
+ }
+ }
+
+ DAG_scene_sort(CTX_data_scene(C));
+ ED_anim_dag_flush_update(C);
+ WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
+ }
+ };
+
+ std::map<COLLADAFW::UniqueId, SkinInfo> skin_by_data_uid; // data UID = skin controller data UID
+ MeshImporterBase *mesh_importer;
+
+#if 0
JointData *get_joint_data(COLLADAFW::Node *node)
{
const COLLADAFW::UniqueId& joint_id = node->getUniqueId();
@@ -180,24 +429,22 @@
return &joint_index_to_joint_info_map[joint_index];
}
+#endif
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list