From 228416e108382df0dda7bff680ac46ce6e788821 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Tue, 27 Nov 2007 21:16:47 +0000 Subject: Heat Weighting ============== Now takes b-bones into account, solving as if each bone segment was an individual bone, and then adding the weights together. --- source/blender/include/BIF_editdeform.h | 2 + source/blender/src/editarmature.c | 149 ++++++++++++++++++++++---------- source/blender/src/editdeform.c | 47 ++++++++++ source/blender/src/meshlaplacian.c | 85 ++++++++++++++---- 4 files changed, 220 insertions(+), 63 deletions(-) (limited to 'source') diff --git a/source/blender/include/BIF_editdeform.h b/source/blender/include/BIF_editdeform.h index 2a8f43c14e7..62b850f9094 100644 --- a/source/blender/include/BIF_editdeform.h +++ b/source/blender/include/BIF_editdeform.h @@ -61,6 +61,8 @@ void add_vert_to_defgroup (struct Object *ob, struct bDeformGroup *dg, int assignmode); void remove_vert_defgroup (struct Object *ob, struct bDeformGroup *dg, int vertnum); +float get_vert_defgroup (struct Object *ob, struct bDeformGroup *dg, + int vertnum); void create_dverts(ID *id); void vertexgroup_select_by_name(struct Object *ob, char *name); diff --git a/source/blender/src/editarmature.c b/source/blender/src/editarmature.c index 24c8382a445..9dcb190509f 100644 --- a/source/blender/src/editarmature.c +++ b/source/blender/src/editarmature.c @@ -2552,7 +2552,7 @@ int bone_looper(Object *ob, Bone *bone, void *data, } -static int bone_skinnable(Object *ob, Bone *bone, void *data) +static int bone_skinnable(Object *ob, Bone *bone, void *datap) { /* Bones that are deforming * are regarded to be "skinnable" and are eligible for @@ -2576,16 +2576,26 @@ static int bone_skinnable(Object *ob, Bone *bone, void *data) * pointers to bones that point to all * skinnable bones. */ - Bone ***hbone; + Bone ***hbone; + int a, segments; + struct { Object *armob; void *list; int heat; } *data = datap; if(!(G.f & G_WEIGHTPAINT) || !(bone->flag & BONE_HIDDEN_P)) { if (!(bone->flag & BONE_NO_DEFORM)) { - if (data != NULL) { - hbone = (Bone ***) data; - **hbone = bone; - ++*hbone; + if(data->heat && data->armob->pose && get_pose_channel(data->armob->pose, bone->name)) + segments = bone->segments; + else + segments = 1; + + if (data->list != NULL) { + hbone = (Bone ***) &data->list; + + for(a=0; aflag & BONE_HIDDEN_P)) { if (!(bone->flag & BONE_NO_DEFORM)) { - if ( !(defgroup = get_named_vertexgroup(ob, bone->name)) ) { + if(data->heat && data->armob->pose && get_pose_channel(data->armob->pose, bone->name)) + segments = bone->segments; + else + segments = 1; + + if(!(defgroup = get_named_vertexgroup(ob, bone->name))) defgroup = add_defgroup_name(ob, bone->name); - } - if (data != NULL) { - hgroup = (bDeformGroup ***) data; - **hgroup = defgroup; - ++*hgroup; + if (data->list != NULL) { + hgroup = (bDeformGroup ***) &data->list; + + for(a=0; arad_head * scale, bone->rad_tail * scale, bone->dist * scale); - + /* add the vert to the deform group if weight!=0.0 */ if (distance!=0.0) add_vert_to_defgroup (ob, dgroup, i, distance, WEIGHT_REPLACE); @@ -2713,59 +2732,95 @@ void add_verts_to_dgroups(Object *ob, Object *par, int heat, int mirror) * The mesh vertex positions used are either the final deformed coords * from the derivedmesh in weightpaint mode, the final subsurf coords * when parenting, or simply the original mesh coords. - */ + */ - bArmature *arm; - Bone **bonelist, **bonehandle, *bone; - bDeformGroup **dgrouplist, **dgroupflip, **dgrouphandle; + bArmature *arm; + Bone **bonelist, *bone; + bDeformGroup **dgrouplist, **dgroupflip; bDeformGroup *dgroup, *curdg; - Mesh *mesh; - float (*root)[3], (*tip)[3], (*verts)[3]; + bPoseChannel *pchan; + Mesh *mesh; + Mat4 *bbone = NULL; + float (*root)[3], (*tip)[3], (*verts)[3]; int *selected; - int numbones, vertsfilled = 0, i, j; + int numbones, vertsfilled = 0, i, j, segments = 0; int wpmode = (G.f & G_WEIGHTPAINT); + struct { Object *armob; void *list; int heat; } looper_data; - /* If the parent object is not an armature exit */ - arm = get_armature(par); - if (!arm) - return; + /* If the parent object is not an armature exit */ + arm = get_armature(par); + if (!arm) + return; + + looper_data.armob = par; + looper_data.heat= heat; + looper_data.list= NULL; - /* count the number of skinnable bones */ - numbones = bone_looper(ob, arm->bonebase.first, NULL, bone_skinnable); + /* count the number of skinnable bones */ + numbones = bone_looper(ob, arm->bonebase.first, &looper_data, bone_skinnable); if (numbones == 0) return; - /* create an array of pointer to bones that are skinnable - * and fill it with all of the skinnable bones */ - bonelist = MEM_callocN(numbones*sizeof(Bone *), "bonelist"); - bonehandle = bonelist; - bone_looper(ob, arm->bonebase.first, &bonehandle, bone_skinnable); + /* create an array of pointer to bones that are skinnable + * and fill it with all of the skinnable bones */ + bonelist = MEM_callocN(numbones*sizeof(Bone *), "bonelist"); + looper_data.list= bonelist; + bone_looper(ob, arm->bonebase.first, &looper_data, bone_skinnable); - /* create an array of pointers to the deform groups that - * coorespond to the skinnable bones (creating them - * as necessary. */ - dgrouplist = MEM_callocN(numbones*sizeof(bDeformGroup *), "dgrouplist"); - dgroupflip = MEM_callocN(numbones*sizeof(bDeformGroup *), "dgroupflip"); + /* create an array of pointers to the deform groups that + * coorespond to the skinnable bones (creating them + * as necessary. */ + dgrouplist = MEM_callocN(numbones*sizeof(bDeformGroup *), "dgrouplist"); + dgroupflip = MEM_callocN(numbones*sizeof(bDeformGroup *), "dgroupflip"); - dgrouphandle = dgrouplist; - bone_looper(ob, arm->bonebase.first, &dgrouphandle, dgroup_skinnable); + looper_data.list= dgrouplist; + bone_looper(ob, arm->bonebase.first, &looper_data, dgroup_skinnable); - /* create an array of root and tip positions transformed into + /* create an array of root and tip positions transformed into * global coords */ - root = MEM_callocN(numbones*sizeof(float)*3, "root"); - tip = MEM_callocN(numbones*sizeof(float)*3, "tip"); + root = MEM_callocN(numbones*sizeof(float)*3, "root"); + tip = MEM_callocN(numbones*sizeof(float)*3, "tip"); selected = MEM_callocN(numbones*sizeof(int), "selected"); for (j=0; j < numbones; ++j) { bone = bonelist[j]; dgroup = dgrouplist[j]; + /* handle bbone */ + if(heat) { + if(segments == 0) { + segments = 1; + bbone = NULL; + + if(par->pose && (pchan=get_pose_channel(par->pose, bone->name))) { + if(bone->segments > 1) { + segments = bone->segments; + bbone = b_bone_spline_setup(pchan, 1); + } + } + } + + segments--; + } + /* compute root and tip */ - VECCOPY(root[j], bone->arm_head); - Mat4MulVecfl(par->obmat, root[j]); + if(bbone) { + VECCOPY(root[j], bbone[segments].mat[3]); + Mat4MulVecfl(bone->arm_mat, root[j]); + if(segments+1 < bone->segments) { + VECCOPY(tip[j], bbone[segments+1].mat[3]) + Mat4MulVecfl(bone->arm_mat, tip[j]); + } + else + VECCOPY(tip[j], bone->arm_tail) + } + else { + VECCOPY(root[j], bone->arm_head); + VECCOPY(tip[j], bone->arm_tail); + } - VECCOPY(tip[j], bone->arm_tail); + Mat4MulVecfl(par->obmat, root[j]); Mat4MulVecfl(par->obmat, tip[j]); /* set selected */ diff --git a/source/blender/src/editdeform.c b/source/blender/src/editdeform.c index 6d0c34f2bf8..b4206a510aa 100644 --- a/source/blender/src/editdeform.c +++ b/source/blender/src/editdeform.c @@ -704,6 +704,53 @@ void remove_vert_defgroup (Object *ob, bDeformGroup *dg, int vertnum) remove_vert_def_nr (ob, def_nr, vertnum); } +/* for mesh in object mode lattice can be in editmode */ +static float get_vert_def_nr (Object *ob, int def_nr, int vertnum) +{ + MDeformVert *dvert= NULL; + int i; + + /* get the deform vertices corresponding to the + * vertnum + */ + if(ob->type==OB_MESH) { + if( ((Mesh*)ob->data)->dvert ) + dvert = ((Mesh*)ob->data)->dvert + vertnum; + } + else if(ob->type==OB_LATTICE) { + Lattice *lt= ob->data; + + if(ob==G.obedit) + lt= editLatt; + + if(lt->dvert) + dvert = lt->dvert + vertnum; + } + + if(dvert==NULL) + return 0.0f; + + for(i=dvert->totweight-1 ; i>=0 ; i--) + if(dvert->dw[i].def_nr == def_nr) + return dvert->dw[i].weight; + + return 0.0f; +} + +/* mesh object mode, lattice can be in editmode */ +float get_vert_defgroup (Object *ob, bDeformGroup *dg, int vertnum) +{ + int def_nr; + + if(!ob) + return 0.0f; + + def_nr = get_defgroup_num(ob, dg); + if(def_nr < 0) return 0.0f; + + return get_vert_def_nr (ob, def_nr, vertnum); +} + /* Only available in editmode */ /* removes from active defgroup, if allverts==0 only selected vertices */ void remove_verts_defgroup (int allverts) diff --git a/source/blender/src/meshlaplacian.c b/source/blender/src/meshlaplacian.c index 5d15dbf47b0..d711419a927 100644 --- a/source/blender/src/meshlaplacian.c +++ b/source/blender/src/meshlaplacian.c @@ -407,7 +407,7 @@ static int heat_ray_check_func(Isect *is, RayFace *face) if(v4) CalcNormFloat4(v1, v2, v3, v4, nor); else CalcNormFloat(v1, v2, v3, nor); - + return (INPR(nor, is->vec) < 0); } @@ -605,8 +605,9 @@ void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numbones, { LaplacianSystem *sys; MFace *mface; - float solution; - int a, aflip, totface, j, thrownerror = 0; + float solution, weight; + int *vertsflipped = NULL; + int a, totface, j, bbone, firstsegment, lastsegment, thrownerror = 0; /* count triangles */ for(totface=0, a=0, mface=me->mface; atotface; a++, mface++) { @@ -628,11 +629,31 @@ void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numbones, laplacian_system_construct_end(sys); + if(dgroupflip) { + vertsflipped = MEM_callocN(sizeof(int)*me->totvert, "vertsflipped"); + for(a=0; atotvert; a++) + vertsflipped[a] = mesh_get_x_mirror_vert(ob, a); + } + /* compute weights per bone */ for(j=0; jtotvert; a++) { + remove_vert_defgroup(ob, dgrouplist[j], a); + if(vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0) + remove_vert_defgroup(ob, dgroupflip[j], vertsflipped[a]); + } + } + + /* fill right hand side */ laplacian_begin_solve(sys, -1); for(a=0; atotvert; a++) @@ -640,24 +661,39 @@ void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numbones, laplacian_add_right_hand_side(sys, a, sys->heat.H[a]*sys->heat.p[a]); + /* solve */ if(laplacian_system_solve(sys)) { + /* load solution into vertex groups */ for(a=0; atotvert; a++) { solution= laplacian_system_get_solution(a); - - if(solution > WEIGHT_LIMIT) - add_vert_to_defgroup(ob, dgrouplist[j], a, solution, - WEIGHT_REPLACE); - else - remove_vert_defgroup(ob, dgrouplist[j], a); - - /* do same for mirror */ - aflip = (dgroupflip)? mesh_get_x_mirror_vert(ob, a): 0; - if (dgroupflip && dgroupflip[j] && aflip >= 0) { + + if(bbone) { + if(solution > 0.0f) + add_vert_to_defgroup(ob, dgrouplist[j], a, solution, + WEIGHT_ADD); + } + else { if(solution > WEIGHT_LIMIT) - add_vert_to_defgroup(ob, dgroupflip[j], aflip, - solution, WEIGHT_REPLACE); + add_vert_to_defgroup(ob, dgrouplist[j], a, solution, + WEIGHT_REPLACE); else - remove_vert_defgroup(ob, dgroupflip[j], aflip); + remove_vert_defgroup(ob, dgrouplist[j], a); + } + + /* do same for mirror */ + if(vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0) { + if(bbone) { + if(solution > 0.0f) + add_vert_to_defgroup(ob, dgroupflip[j], vertsflipped[a], + solution, WEIGHT_ADD); + } + else { + if(solution > WEIGHT_LIMIT) + add_vert_to_defgroup(ob, dgroupflip[j], vertsflipped[a], + solution, WEIGHT_REPLACE); + else + remove_vert_defgroup(ob, dgroupflip[j], vertsflipped[a]); + } } } } @@ -667,9 +703,26 @@ void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numbones, thrownerror= 1; break; } + + /* remove too small vertex weights */ + if(bbone && lastsegment) { + for(a=0; atotvert; a++) { + weight= get_vert_defgroup(ob, dgrouplist[j], a); + if(weight > 0.0f && weight <= WEIGHT_LIMIT) + remove_vert_defgroup(ob, dgrouplist[j], a); + + if(vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0) { + weight= get_vert_defgroup(ob, dgroupflip[j], vertsflipped[a]); + if(weight > 0.0f && weight <= WEIGHT_LIMIT) + remove_vert_defgroup(ob, dgroupflip[j], vertsflipped[a]); + } + } + } } /* free */ + if(vertsflipped) MEM_freeN(vertsflipped); + RE_ray_tree_free(sys->heat.raytree); MEM_freeN(sys->heat.vface); -- cgit v1.2.3