void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource, bDeformGroup **dgrouplist, bDeformGroup **dgroupflip, float (*root)[3], float (*tip)[3], int *selected, const char **err_str) { LaplacianSystem *sys; MLoopTri *mlooptri; MPoly *mp; MLoop *ml; float solution, weight; int *vertsflipped = NULL, *mask = NULL; int a, tottri, j, bbone, firstsegment, lastsegment; bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; MVert *mvert = me->mvert; bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; *err_str = NULL; /* bone heat needs triangulated faces */ tottri = poly_to_tri_count(me->totpoly, me->totloop); /* count triangles and create mask */ if (ob->mode & OB_MODE_WEIGHT_PAINT && (use_face_sel || use_vert_sel)) { mask = MEM_callocN(sizeof(int) * me->totvert, "heat_bone_weighting mask"); /* (added selectedVerts content for vertex mask, they used to just equal 1) */ if (use_vert_sel) { for (a = 0, mp = me->mpoly; a < me->totpoly; mp++, a++) { for (j = 0, ml = me->mloop + mp->loopstart; j < mp->totloop; j++, ml++) { mask[ml->v] = (mvert[ml->v].flag & SELECT) != 0; } } } else if (use_face_sel) { for (a = 0, mp = me->mpoly; a < me->totpoly; mp++, a++) { if (mp->flag & ME_FACE_SEL) { for (j = 0, ml = me->mloop + mp->loopstart; j < mp->totloop; j++, ml++) { mask[ml->v] = 1; } } } } } /* create laplacian */ sys = laplacian_system_construct_begin(me->totvert, tottri, 1); sys->heat.tottri = poly_to_tri_count(me->totpoly, me->totloop); mlooptri = MEM_mallocN(sizeof(*sys->heat.mlooptri) * sys->heat.tottri, __func__); BKE_mesh_recalc_looptri( me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, mlooptri); sys->heat.mlooptri = mlooptri; sys->heat.mloop = me->mloop; sys->heat.totvert = me->totvert; sys->heat.verts = verts; sys->heat.root = root; sys->heat.tip = tip; sys->heat.numsource = numsource; heat_ray_tree_create(sys); heat_laplacian_create(sys); laplacian_system_construct_end(sys); if (dgroupflip) { vertsflipped = MEM_callocN(sizeof(int) * me->totvert, "vertsflipped"); for (a = 0; a < me->totvert; a++) vertsflipped[a] = mesh_get_x_mirror_vert(ob, NULL, a, use_topology); } /* compute weights per bone */ for (j = 0; j < numsource; j++) { if (!selected[j]) continue; firstsegment = (j == 0 || dgrouplist[j - 1] != dgrouplist[j]); lastsegment = (j == numsource - 1 || dgrouplist[j] != dgrouplist[j + 1]); bbone = !(firstsegment && lastsegment); /* clear weights */ if (bbone && firstsegment) { for (a = 0; a < me->totvert; a++) { if (mask && !mask[a]) continue; ED_vgroup_vert_remove(ob, dgrouplist[j], a); if (vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0) ED_vgroup_vert_remove(ob, dgroupflip[j], vertsflipped[a]); } } /* fill right hand side */ laplacian_begin_solve(sys, -1); for (a = 0; a < me->totvert; a++) if (heat_source_closest(sys, a, j)) 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; a < me->totvert; a++) { if (mask && !mask[a]) continue; solution = laplacian_system_get_solution(sys, a); if (bbone) { if (solution > 0.0f) ED_vgroup_vert_add(ob, dgrouplist[j], a, solution, WEIGHT_ADD); } else { weight = heat_limit_weight(solution); if (weight > 0.0f) ED_vgroup_vert_add(ob, dgrouplist[j], a, weight, WEIGHT_REPLACE); else ED_vgroup_vert_remove(ob, dgrouplist[j], a); } /* do same for mirror */ if (vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0) { if (bbone) { if (solution > 0.0f) ED_vgroup_vert_add(ob, dgroupflip[j], vertsflipped[a], solution, WEIGHT_ADD); } else { weight = heat_limit_weight(solution); if (weight > 0.0f) ED_vgroup_vert_add(ob, dgroupflip[j], vertsflipped[a], weight, WEIGHT_REPLACE); else ED_vgroup_vert_remove(ob, dgroupflip[j], vertsflipped[a]); } } } } else if (*err_str == NULL) { *err_str = N_("Bone Heat Weighting: failed to find solution for one or more bones"); break; } /* remove too small vertex weights */ if (bbone && lastsegment) { for (a = 0; a < me->totvert; a++) { if (mask && !mask[a]) continue; weight = ED_vgroup_vert_weight(ob, dgrouplist[j], a); weight = heat_limit_weight(weight); if (weight <= 0.0f) ED_vgroup_vert_remove(ob, dgrouplist[j], a); if (vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0) { weight = ED_vgroup_vert_weight(ob, dgroupflip[j], vertsflipped[a]); weight = heat_limit_weight(weight); if (weight <= 0.0f) ED_vgroup_vert_remove(ob, dgroupflip[j], vertsflipped[a]); } } } } /* free */ if (vertsflipped) MEM_freeN(vertsflipped); if (mask) MEM_freeN(mask); heat_system_free(sys); laplacian_system_delete(sys); }
void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource, bDeformGroup **dgrouplist, bDeformGroup **dgroupflip, float (*root)[3], float (*tip)[3], int *selected, const char **err_str) { LaplacianSystem *sys; MFace *mface; float solution, weight; int *vertsflipped = NULL, *mask= NULL; int a, totface, j, bbone, firstsegment, lastsegment; *err_str= NULL; /* count triangles and create mask */ if(me->editflag & ME_EDIT_PAINT_MASK) mask= MEM_callocN(sizeof(int)*me->totvert, "heat_bone_weighting mask"); for(totface=0, a=0, mface=me->mface; a<me->totface; a++, mface++) { totface++; if(mface->v4) totface++; if(mask && (mface->flag & ME_FACE_SEL)) { mask[mface->v1]= 1; mask[mface->v2]= 1; mask[mface->v3]= 1; if(mface->v4) mask[mface->v4]= 1; } } /* create laplacian */ sys = laplacian_system_construct_begin(me->totvert, totface, 1); sys->heat.mface= me->mface; sys->heat.totface= me->totface; sys->heat.totvert= me->totvert; sys->heat.verts= verts; sys->heat.root= root; sys->heat.tip= tip; sys->heat.numsource= numsource; heat_ray_tree_create(sys); heat_laplacian_create(sys); laplacian_system_construct_end(sys); if(dgroupflip) { vertsflipped = MEM_callocN(sizeof(int)*me->totvert, "vertsflipped"); for(a=0; a<me->totvert; a++) vertsflipped[a] = mesh_get_x_mirror_vert(ob, a); } /* compute weights per bone */ for(j=0; j<numsource; j++) { if(!selected[j]) continue; firstsegment= (j == 0 || dgrouplist[j-1] != dgrouplist[j]); lastsegment= (j == numsource-1 || dgrouplist[j] != dgrouplist[j+1]); bbone= !(firstsegment && lastsegment); /* clear weights */ if(bbone && firstsegment) { for(a=0; a<me->totvert; a++) { if(mask && !mask[a]) continue; ED_vgroup_vert_remove(ob, dgrouplist[j], a); if(vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0) ED_vgroup_vert_remove(ob, dgroupflip[j], vertsflipped[a]); } } /* fill right hand side */ laplacian_begin_solve(sys, -1); for(a=0; a<me->totvert; a++) if(heat_source_closest(sys, a, j)) 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; a<me->totvert; a++) { if(mask && !mask[a]) continue; solution= laplacian_system_get_solution(a); if(bbone) { if(solution > 0.0f) ED_vgroup_vert_add(ob, dgrouplist[j], a, solution, WEIGHT_ADD); } else { weight= heat_limit_weight(solution); if(weight > 0.0f) ED_vgroup_vert_add(ob, dgrouplist[j], a, weight, WEIGHT_REPLACE); else ED_vgroup_vert_remove(ob, dgrouplist[j], a); } /* do same for mirror */ if(vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0) { if(bbone) { if(solution > 0.0f) ED_vgroup_vert_add(ob, dgroupflip[j], vertsflipped[a], solution, WEIGHT_ADD); } else { weight= heat_limit_weight(solution); if(weight > 0.0f) ED_vgroup_vert_add(ob, dgroupflip[j], vertsflipped[a], weight, WEIGHT_REPLACE); else ED_vgroup_vert_remove(ob, dgroupflip[j], vertsflipped[a]); } } } } else if(*err_str == NULL) { *err_str= "Bone Heat Weighting: failed to find solution for one or more bones"; break; } /* remove too small vertex weights */ if(bbone && lastsegment) { for(a=0; a<me->totvert; a++) { if(mask && !mask[a]) continue; weight= ED_vgroup_vert_weight(ob, dgrouplist[j], a); weight= heat_limit_weight(weight); if(weight <= 0.0f) ED_vgroup_vert_remove(ob, dgrouplist[j], a); if(vertsflipped && dgroupflip[j] && vertsflipped[a] >= 0) { weight= ED_vgroup_vert_weight(ob, dgroupflip[j], vertsflipped[a]); weight= heat_limit_weight(weight); if(weight <= 0.0f) ED_vgroup_vert_remove(ob, dgroupflip[j], vertsflipped[a]); } } } } /* free */ if(vertsflipped) MEM_freeN(vertsflipped); if(mask) MEM_freeN(mask); heat_system_free(sys); laplacian_system_delete(sys); }