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
This commit is contained in:
Nicholas Bishop 2012-05-22 15:29:57 +00:00
parent 11309a19e2
commit 45265b326a
6 changed files with 201 additions and 3 deletions

@ -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);

@ -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 |

@ -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);
}

@ -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);

@ -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<<OB_MESH)));
}
static int skin_edit_poll(bContext *C)
{
return (CTX_data_edit_object(C) &&
@ -1542,6 +1550,192 @@ void OBJECT_OT_skin_radii_equalize(wmOperatorType *ot)
ot->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 *********************/

@ -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);