From 45265b326a2854a59327c3d171a3f4797944cc79 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Tue, 22 May 2012 15:29:57 +0000 Subject: [PATCH] Add operator to extract armature and vertex groups from skin. * The operator creates bones for each input edge (does not subdivide them like the skin operator does), adds a fake root bone for skin roots with multiple children. * The operator adds vertex weight groups to the original mesh. * Make copy_object_transform() public, used to match the armature object to the mesh object. Skin modifier documentation: http://wiki.blender.org/index.php/User:Nicholasbishop/SkinModifier --- source/blender/blenkernel/BKE_object.h | 1 + source/blender/blenkernel/intern/customdata.c | 2 +- source/blender/blenkernel/intern/object.c | 4 +- source/blender/editors/object/object_intern.h | 1 + .../blender/editors/object/object_modifier.c | 194 ++++++++++++++++++ source/blender/editors/object/object_ops.c | 2 + 6 files changed, 201 insertions(+), 3 deletions(-) diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 1cdf2ee2e14..890fc40c284 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -53,6 +53,7 @@ struct MovieClip; void BKE_object_workob_clear(struct Object *workob); void BKE_object_workob_calc_parent(struct Scene *scene, struct Object *ob, struct Object *workob); +void BKE_object_transform_copy(struct Object *ob_tar, const struct Object *ob_src); struct SoftBody *copy_softbody(struct SoftBody *sb); struct BulletSoftBody *copy_bulletsoftbody(struct BulletSoftBody *sb); void BKE_object_copy_particlesystems(struct Object *obn, struct Object *ob); diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 645267fce34..04bce0a8f63 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -1168,7 +1168,7 @@ const CustomDataMask CD_MASK_DERIVEDMESH = CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY | CD_MASK_PREVIEW_MLOOPCOL | CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORIGSPACE_MLOOP | CD_MASK_ORCO | CD_MASK_TANGENT | CD_MASK_PREVIEW_MCOL | CD_MASK_NORMAL | CD_MASK_SHAPEKEY | CD_MASK_RECAST | - CD_MASK_ORIGINDEX | CD_MASK_POLYINDEX; + CD_MASK_ORIGINDEX | CD_MASK_POLYINDEX | CD_MASK_MVERT_SKIN; const CustomDataMask CD_MASK_BMESH = CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY | CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_PROP_FLT | CD_MASK_PROP_INT | diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 6f6881ce317..8de832e508d 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -1090,7 +1090,7 @@ Object *BKE_object_pose_armature_get(Object *ob) return NULL; } -static void copy_object_transform(Object *ob_tar, Object *ob_src) +void BKE_object_transform_copy(Object *ob_tar, const Object *ob_src) { copy_v3_v3(ob_tar->loc, ob_src->loc); copy_v3_v3(ob_tar->rot, ob_src->rot); @@ -1365,7 +1365,7 @@ void BKE_object_make_proxy(Object *ob, Object *target, Object *gob) BKE_object_apply_mat4(ob, ob->obmat, FALSE, TRUE); } else { - copy_object_transform(ob, target); + BKE_object_transform_copy(ob, target); ob->parent = target->parent; /* libdata */ copy_m4_m4(ob->parentinv, target->parentinv); } diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index 2bd53a3c0a7..4b33c5663ba 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -163,6 +163,7 @@ void OBJECT_OT_ocean_bake(struct wmOperatorType *ot); void OBJECT_OT_skin_root_mark(struct wmOperatorType *ot); void OBJECT_OT_skin_loose_mark_clear(struct wmOperatorType *ot); void OBJECT_OT_skin_radii_equalize(struct wmOperatorType *ot); +void OBJECT_OT_skin_armature_create(struct wmOperatorType *ot); /* object_constraint.c */ void OBJECT_OT_constraint_add(struct wmOperatorType *ot); diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index e98ff4a6984..e13e15e2a69 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -35,6 +35,7 @@ #include "MEM_guardedalloc.h" #include "DNA_anim_types.h" +#include "DNA_armature_types.h" #include "DNA_curve_types.h" #include "DNA_key_types.h" #include "DNA_mesh_types.h" @@ -42,6 +43,7 @@ #include "DNA_object_force.h" #include "DNA_scene_types.h" +#include "BLI_bitmap.h" #include "BLI_math.h" #include "BLI_listbase.h" #include "BLI_string.h" @@ -1367,6 +1369,12 @@ static void modifier_skin_customdata_ensure(Object *ob) } } +static int skin_poll(bContext *C) +{ + return (!CTX_data_edit_object(C) && + edit_modifier_poll_generic(C, &RNA_SkinModifier, (1<flag = OPTYPE_REGISTER|OPTYPE_UNDO; } +static void skin_armature_bone_create(Object *skin_ob, + MVert *mvert, MEdge *medge, + bArmature *arm, + BLI_bitmap edges_visited, + const MeshElemMap *emap, + EditBone *parent_bone, + int parent_v) +{ + int i; + + for(i = 0; i < emap[parent_v].count; i++) { + int endx = emap[parent_v].indices[i]; + const MEdge *e = &medge[endx]; + EditBone *bone; + bDeformGroup *dg; + int v; + + /* ignore edge if already visited */ + if(BLI_BITMAP_GET(edges_visited, endx)) + continue; + BLI_BITMAP_SET(edges_visited, endx); + + v = (e->v1 == parent_v ? e->v2 : e->v1); + + bone = MEM_callocN(sizeof(EditBone), + "skin_armature_bone_create EditBone"); + + bone->parent = parent_bone; + bone->layer = 1; + bone->flag |= BONE_CONNECTED; + + copy_v3_v3(bone->head, mvert[parent_v].co); + copy_v3_v3(bone->tail, mvert[v].co); + bone->rad_head = bone->rad_tail = 0.25; + BLI_snprintf(bone->name, sizeof(bone->name), "Bone.%.2d", endx); + + BLI_addtail(arm->edbo, bone); + + /* add bDeformGroup */ + if((dg = ED_vgroup_add_name(skin_ob, bone->name))) { + ED_vgroup_vert_add(skin_ob, dg, parent_v, 1, WEIGHT_REPLACE); + ED_vgroup_vert_add(skin_ob, dg, v, 1, WEIGHT_REPLACE); + } + + skin_armature_bone_create(skin_ob, + mvert, medge, + arm, + edges_visited, + emap, + bone, + v); + } +} + +static Object *modifier_skin_armature_create(struct Scene *scene, + Object *skin_ob) +{ + BLI_bitmap edges_visited; + DerivedMesh *deform_dm; + MVert *mvert; + Mesh *me = skin_ob->data; + Object *arm_ob; + bArmature *arm; + MVertSkin *mvert_skin; + MeshElemMap *emap; + int *emap_mem; + int v; + + deform_dm = mesh_get_derived_deform(scene, skin_ob, CD_MASK_BAREMESH); + mvert = deform_dm->getVertArray(deform_dm); + + /* add vertex weights to original mesh */ + CustomData_add_layer(&me->vdata, + CD_MDEFORMVERT, + CD_CALLOC, + NULL, + me->totvert); + + arm_ob = BKE_object_add(scene, OB_ARMATURE); + BKE_object_transform_copy(arm_ob, skin_ob); + arm = arm_ob->data; + arm->layer = 1; + arm_ob->dtx |= OB_DRAWXRAY; + arm->drawtype = ARM_LINE; + arm->edbo = MEM_callocN(sizeof(ListBase), "edbo armature"); + + mvert_skin = CustomData_get_layer(&me->vdata, CD_MVERT_SKIN); + create_vert_edge_map(&emap, &emap_mem, + me->medge, me->totvert, me->totedge); + + edges_visited = BLI_BITMAP_NEW(me->totedge, "edge_visited"); + + /* note: we use EditBones here, easier to set them up and use + * edit-armature functions to convert back to regular bones */ + for(v = 0; v < me->totvert; v++) { + if(mvert_skin[v].flag & MVERT_SKIN_ROOT) { + EditBone *bone = NULL; + + /* Unless the skin root has just one adjacent edge, create + a fake root bone (have it going off in the Y direction + (arbitrary) */ + if (emap[v].count > 1) { + bone = MEM_callocN(sizeof(EditBone), "EditBone"); + + copy_v3_v3(bone->head, me->mvert[v].co); + copy_v3_v3(bone->tail, me->mvert[v].co); + bone->layer = 1; + + bone->head[1] = 1.0f; + bone->rad_head = bone->rad_tail = 0.25; + + BLI_addtail(arm->edbo, bone); + } + + if(emap[v].count >= 1) { + skin_armature_bone_create(skin_ob, + mvert, me->medge, + arm, + edges_visited, + emap, + bone, + v); + } + } + } + + MEM_freeN(edges_visited); + MEM_freeN(emap); + MEM_freeN(emap_mem); + + ED_armature_from_edit(arm_ob); + ED_armature_edit_free(arm_ob); + + return arm_ob; +} + +static int skin_armature_create_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_active_object(C), *arm_ob; + ModifierData *skin_md; + ArmatureModifierData *arm_md; + + /* create new armature */ + arm_ob = modifier_skin_armature_create(scene, ob); + + /* add a modifier to connect the new armature to the mesh */ + arm_md= (ArmatureModifierData*)modifier_new(eModifierType_Armature); + if (arm_md) { + skin_md = edit_modifier_property_get(op, ob, eModifierType_Skin); + BLI_insertlinkafter(&ob->modifiers, skin_md, arm_md); + + arm_md->object = arm_ob; + arm_md->deformflag = ARM_DEF_VGROUP | ARM_DEF_QUATERNION; + DAG_scene_sort(bmain, scene); + DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + } + + WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob); + + return OPERATOR_FINISHED; +} + +static int skin_armature_create_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +{ + if (edit_modifier_invoke_properties(C, op)) + return skin_armature_create_exec(C, op); + else + return OPERATOR_CANCELLED; +} + +void OBJECT_OT_skin_armature_create(wmOperatorType *ot) +{ + ot->name = "Skin Armature Create"; + ot->description = "Create an armature that parallels the skin layout"; + ot->idname = "OBJECT_OT_skin_armature_create"; + + ot->poll = skin_poll; + ot->invoke = skin_armature_create_invoke; + ot->exec = skin_armature_create_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; + edit_modifier_properties(ot); +} /************************ mdef bind operator *********************/ diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index 1f09d8fd5e4..01f6b641709 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -142,6 +142,8 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_skin_root_mark); WM_operatortype_append(OBJECT_OT_skin_loose_mark_clear); WM_operatortype_append(OBJECT_OT_skin_radii_equalize); + WM_operatortype_append(OBJECT_OT_skin_armature_create); + WM_operatortype_append(OBJECT_OT_meshdeform_bind); WM_operatortype_append(OBJECT_OT_explode_refresh); WM_operatortype_append(OBJECT_OT_ocean_bake);