static void envelope_bone_weighting(Object *ob, Mesh *mesh, float (*verts)[3], int numbones, Bone **bonelist, bDeformGroup **dgrouplist, bDeformGroup **dgroupflip, float (*root)[3], float (*tip)[3], const int *selected, float scale) { /* Create vertex group weights from envelopes */ Bone *bone; bDeformGroup *dgroup; float distance; int i, iflip, j; bool use_topology = (mesh->editflag & ME_EDIT_MIRROR_TOPO) != 0; bool use_mask = false; if ((ob->mode & OB_MODE_WEIGHT_PAINT) && (mesh->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL))) { use_mask = true; } /* for each vertex in the mesh */ for (i = 0; i < mesh->totvert; i++) { if (use_mask && !(mesh->mvert[i].flag & SELECT)) { continue; } iflip = (dgroupflip) ? mesh_get_x_mirror_vert(ob, NULL, i, use_topology) : -1; /* for each skinnable bone */ for (j = 0; j < numbones; ++j) { if (!selected[j]) continue; bone = bonelist[j]; dgroup = dgrouplist[j]; /* store the distance-factor from the vertex to the bone */ distance = distfactor_to_bone(verts[i], root[j], tip[j], bone->rad_head * scale, bone->rad_tail * scale, bone->dist * scale); /* add the vert to the deform group if (weight != 0.0) */ if (distance != 0.0f) ED_vgroup_vert_add(ob, dgroup, i, distance, WEIGHT_REPLACE); else ED_vgroup_vert_remove(ob, dgroup, i); /* do same for mirror */ if (dgroupflip && dgroupflip[j] && iflip != -1) { if (distance != 0.0f) ED_vgroup_vert_add(ob, dgroupflip[j], iflip, distance, WEIGHT_REPLACE); else ED_vgroup_vert_remove(ob, dgroupflip[j], iflip); } } } }
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); }
static int object_shape_key_mirror(bContext *C, Object *ob) { KeyBlock *kb; Key *key; key= ob_get_key(ob); if(key==NULL) return 0; kb= BLI_findlink(&key->block, ob->shapenr-1); if(kb) { int i1, i2; float *fp1, *fp2; float tvec[3]; char *tag_elem= MEM_callocN(sizeof(char) * kb->totelem, "shape_key_mirror"); if(ob->type==OB_MESH) { Mesh *me= ob->data; MVert *mv; mesh_octree_table(ob, NULL, NULL, 's'); for(i1=0, mv=me->mvert; i1<me->totvert; i1++, mv++) { i2= mesh_get_x_mirror_vert(ob, i1); if(i2==i1) { fp1= ((float *)kb->data) + i1*3; fp1[0] = -fp1[0]; tag_elem[i1]= 1; } else if(i2 != -1) { if(tag_elem[i1]==0 && tag_elem[i2]==0) { fp1= ((float *)kb->data) + i1*3; fp2= ((float *)kb->data) + i2*3; copy_v3_v3(tvec, fp1); copy_v3_v3(fp1, fp2); copy_v3_v3(fp2, tvec); /* flip x axis */ fp1[0] = -fp1[0]; fp2[0] = -fp2[0]; } tag_elem[i1]= tag_elem[i2]= 1; } } mesh_octree_table(ob, NULL, NULL, 'e'); } else if (ob->type == OB_LATTICE) { Lattice *lt= ob->data; int i1, i2; float *fp1, *fp2; int u, v, w; /* half but found up odd value */ const int pntsu_half = (((lt->pntsu / 2) + (lt->pntsu % 2))) ; /* currently editmode isnt supported by mesh so * ignore here for now too */ /* if(lt->editlatt) lt= lt->editlatt->latt; */ for(w=0; w<lt->pntsw; w++) { for(v=0; v<lt->pntsv; v++) { for(u=0; u<pntsu_half; u++) { int u_inv= (lt->pntsu - 1) - u; float tvec[3]; if(u == u_inv) { i1= LT_INDEX(lt, u, v, w); fp1= ((float *)kb->data) + i1*3; fp1[0]= -fp1[0]; } else { i1= LT_INDEX(lt, u, v, w); i2= LT_INDEX(lt, u_inv, v, w); fp1= ((float *)kb->data) + i1*3; fp2= ((float *)kb->data) + i2*3; copy_v3_v3(tvec, fp1); copy_v3_v3(fp1, fp2); copy_v3_v3(fp2, tvec); fp1[0]= -fp1[0]; fp2[0]= -fp2[0]; } } } } } MEM_freeN(tag_elem); } DAG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob); return 1; }
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); }
static bool object_shape_key_mirror( bContext *C, Object *ob, int *r_totmirr, int *r_totfail, bool use_topology) { KeyBlock *kb; Key *key; int totmirr = 0, totfail = 0; *r_totmirr = *r_totfail = 0; key = BKE_key_from_object(ob); if (key == NULL) { return 0; } kb = BLI_findlink(&key->block, ob->shapenr - 1); if (kb) { char *tag_elem = MEM_callocN(sizeof(char) * kb->totelem, "shape_key_mirror"); if (ob->type == OB_MESH) { Mesh *me = ob->data; MVert *mv; int i1, i2; float *fp1, *fp2; float tvec[3]; ED_mesh_mirror_spatial_table(ob, NULL, NULL, NULL, 's'); for (i1 = 0, mv = me->mvert; i1 < me->totvert; i1++, mv++) { i2 = mesh_get_x_mirror_vert(ob, NULL, i1, use_topology); if (i2 == i1) { fp1 = ((float *)kb->data) + i1 * 3; fp1[0] = -fp1[0]; tag_elem[i1] = 1; totmirr++; } else if (i2 != -1) { if (tag_elem[i1] == 0 && tag_elem[i2] == 0) { fp1 = ((float *)kb->data) + i1 * 3; fp2 = ((float *)kb->data) + i2 * 3; copy_v3_v3(tvec, fp1); copy_v3_v3(fp1, fp2); copy_v3_v3(fp2, tvec); /* flip x axis */ fp1[0] = -fp1[0]; fp2[0] = -fp2[0]; totmirr++; } tag_elem[i1] = tag_elem[i2] = 1; } else { totfail++; } } ED_mesh_mirror_spatial_table(ob, NULL, NULL, NULL, 'e'); } else if (ob->type == OB_LATTICE) { Lattice *lt = ob->data; int i1, i2; float *fp1, *fp2; int u, v, w; /* half but found up odd value */ const int pntsu_half = (lt->pntsu / 2) + (lt->pntsu % 2); /* currently editmode isn't supported by mesh so * ignore here for now too */ /* if (lt->editlatt) lt = lt->editlatt->latt; */ for (w = 0; w < lt->pntsw; w++) { for (v = 0; v < lt->pntsv; v++) { for (u = 0; u < pntsu_half; u++) { int u_inv = (lt->pntsu - 1) - u; float tvec[3]; if (u == u_inv) { i1 = BKE_lattice_index_from_uvw(lt, u, v, w); fp1 = ((float *)kb->data) + i1 * 3; fp1[0] = -fp1[0]; totmirr++; } else { i1 = BKE_lattice_index_from_uvw(lt, u, v, w); i2 = BKE_lattice_index_from_uvw(lt, u_inv, v, w); fp1 = ((float *)kb->data) + i1 * 3; fp2 = ((float *)kb->data) + i2 * 3; copy_v3_v3(tvec, fp1); copy_v3_v3(fp1, fp2); copy_v3_v3(fp2, tvec); fp1[0] = -fp1[0]; fp2[0] = -fp2[0]; totmirr++; } } } } } MEM_freeN(tag_elem); } *r_totmirr = totmirr; *r_totfail = totfail; DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); return 1; }