[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