Commit: dfdf4514a52b7dad740b75c380bbd4ed6ac05fd7 Author: Antonioya Date: Sun Aug 19 17:22:35 2018 +0200 Branches: greasepencil-object https://developer.blender.org/rBdfdf4514a52b7dad740b75c380bbd4ed6ac05fd7
New operator to generate automatic weights =================================================================== M source/blender/editors/gpencil/gpencil_armature.c M source/blender/editors/gpencil/gpencil_data.c =================================================================== diff --git a/source/blender/editors/gpencil/gpencil_armature.c b/source/blender/editors/gpencil/gpencil_armature.c index 0ee25c58603..0f0b176dbb3 100644 --- a/source/blender/editors/gpencil/gpencil_armature.c +++ b/source/blender/editors/gpencil/gpencil_armature.c @@ -48,6 +48,7 @@ #include "DNA_armature_types.h" #include "DNA_gpencil_types.h" +#include "DNA_meshdata_types.h" #include "DNA_scene_types.h" #include "BKE_action.h" @@ -78,6 +79,50 @@ enum { GP_ARMATURE_AUTO = 1 }; +/* test if a point is inside cylinder + * Return: -1.0 if point is outside the cylinder + * o distance squared from cylinder axis if point is inside. + */ +static float test_point_in_cylynder(float pt1[3], float pt2[3], + float lengthsq, float radius_sq, bGPDspoint *pt) +{ + float dx[3]; /* vector from line segment point 1 to point 2 */ + float pdx[3]; /* vector pd from point 1 to test point */ + float dot, dsq; + + sub_v3_v3v3(dx, pt2, pt1); + sub_v3_v3v3(pdx, &pt->x, pt1); + + /* Dot the d and pd vectors to see if point lies behind the */ + dot = dot_v3v3(pdx, dx); + + /* If dot is less than zero the point is behind the pt1 cap. + * If greater than the cylinder axis line segment length squared + * then the point is outside the other end cap at pt2. + */ + if (dot < 0.0f || dot > lengthsq) + { + return(-1.0f); + } + else + { + /* Point lies within the parallel caps, so find, + * distance squared from point to line */ + + /* distance squared to the cylinder axis */ + dsq = (pdx[0] * pdx[0] + pdx[1] * pdx[1] + pdx[2] * pdx[2]) - dot * dot / lengthsq; + + if (dsq > radius_sq) + { + return(-1.0f); + } + else + { + return(dsq); // return distance squared to axis + } + } +} + static int gpencil_bone_looper(Object *ob, Bone *bone, void *data, int(*bone_func)(Object *, Bone *, void *)) { @@ -196,17 +241,18 @@ static int dgroup_skinnable_cb(Object *ob, Bone *bone, void *datap) */ bDeformGroup ***hgroup, *defgroup = NULL; int a, segments; - struct { Object *armob; void *list; int heat; bool is_weight_paint; } *data = datap; + struct { Object *armob; void *list; int heat; } *data = datap; bArmature *arm = data->armob->data; - if (!data->is_weight_paint || !(bone->flag & BONE_HIDDEN_P)) { + if (!(bone->flag & BONE_HIDDEN_P)) { if (!(bone->flag & BONE_NO_DEFORM)) { if (data->heat && data->armob->pose && BKE_pose_channel_find_name(data->armob->pose, bone->name)) segments = bone->segments; else segments = 1; - if (!data->is_weight_paint || ((arm->layer & bone->layer) && (bone->flag & BONE_SELECTED))) { + //if (((arm->layer & bone->layer) && (bone->flag & BONE_SELECTED))) { + if (arm->layer & bone->layer) { if (!(defgroup = defgroup_find_name(ob, bone->name))) { defgroup = BKE_object_defgroup_add_name(ob, bone->name); } @@ -230,36 +276,28 @@ static int dgroup_skinnable_cb(Object *ob, Bone *bone, void *datap) return 0; } -static void add_verts_to_dgroups( - ReportList *reports, Depsgraph *depsgraph, Scene *scene, Object *ob, Object *par, - int heat, const bool mirror) +/* This functions implements the automatic computation of vertex group weights */ +static void gpencil_add_verts_to_dgroups(bContext *C, + ReportList *reports, Depsgraph *depsgraph, Scene *scene, Object *ob, Object *ob_arm) { - /* This functions implements the automatic computation of vertex group - * weights, either through envelopes or using a heat equilibrium. - * - * This function can be called both when parenting a mesh to an armature, - * or in weightpaint + posemode. In the latter case selection is taken - * into account and vertex weights can be mirrored. - * - * The mesh vertex positions used are either the final deformed coords - * from the evaluated mesh in weightpaint mode, the final subsurf coords - * when parenting, or simply the original mesh coords. - */ - - bArmature *arm = par->data; + bArmature *arm = ob_arm->data; Bone **bonelist, *bone; - bDeformGroup **dgrouplist, **dgroupflip; + bDeformGroup **dgrouplist; bDeformGroup *dgroup; bPoseChannel *pchan; - bGPdata *gpd; + bGPdata *gpd = (bGPdata *)ob->data; + bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); + Mat4 bbone_array[MAX_BBONE_SUBDIV], *bbone = NULL; float(*root)[3], (*tip)[3], (*verts)[3]; + float *lensqr, *radsqr; int *selected; - int numbones, vertsfilled = 0, i, j, segments = 0; + float weight; + int numbones, i, j, segments = 0; struct { Object *armob; void *list; int heat; } looper_data; - looper_data.armob = par; - looper_data.heat = heat; + looper_data.armob = ob_arm; + looper_data.heat = true; looper_data.list = NULL; /* count the number of skinnable bones */ @@ -268,9 +306,6 @@ static void add_verts_to_dgroups( if (numbones == 0) return; - if (BKE_object_defgroup_data_create(ob->data) == NULL) - 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"); @@ -281,7 +316,6 @@ static void add_verts_to_dgroups( * correspond to the skinnable bones (creating them * as necessary. */ dgrouplist = MEM_callocN(numbones * sizeof(bDeformGroup *), "dgrouplist"); - dgroupflip = MEM_callocN(numbones * sizeof(bDeformGroup *), "dgroupflip"); looper_data.list = dgrouplist; gpencil_bone_looper(ob, arm->bonebase.first, &looper_data, dgroup_skinnable_cb); @@ -291,29 +325,29 @@ static void add_verts_to_dgroups( root = MEM_callocN(numbones * sizeof(float) * 3, "root"); tip = MEM_callocN(numbones * sizeof(float) * 3, "tip"); selected = MEM_callocN(numbones * sizeof(int), "selected"); + lensqr = MEM_callocN(numbones * sizeof(float), "lensqr"); + radsqr = MEM_callocN(numbones * sizeof(float), "radsqr"); 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 = BKE_pose_channel_find_name(par->pose, bone->name))) { - if (bone->segments > 1) { - segments = bone->segments; - b_bone_spline_setup(pchan, 1, bbone_array); - bbone = bbone_array; - } + if (segments == 0) { + segments = 1; + bbone = NULL; + + if ((ob_arm->pose) && (pchan = BKE_pose_channel_find_name(ob_arm->pose, bone->name))) { + if (bone->segments > 1) { + segments = bone->segments; + b_bone_spline_setup(pchan, 1, bbone_array); + bbone = bbone_array; } } - - segments--; } + segments--; + /* compute root and tip */ if (bbone) { mul_v3_m4v3(root[j], bone->arm_mat, bbone[segments].mat[3]); @@ -329,85 +363,136 @@ static void add_verts_to_dgroups( copy_v3_v3(tip[j], bone->arm_tail); } - mul_m4_v3(par->obmat, root[j]); - mul_m4_v3(par->obmat, tip[j]); + mul_m4_v3(ob_arm->obmat, root[j]); + mul_m4_v3(ob_arm->obmat, tip[j]); selected[j] = 1; - /* find flipped group */ - if (dgroup && mirror) { - char name_flip[MAXBONENAME]; + /* calculate len of bone squared */ + lensqr[j] = len_squared_v3v3(root[j], tip[j]); - BLI_string_flip_side_name(name_flip, dgroup->name, false, sizeof(name_flip)); - dgroupflip[j] = defgroup_find_name(ob, name_flip); - } + /* calculate radius squared */ + radsqr[j] = lensqr[j] / 6.0f; } - /* create verts */ - gpd = (bGPdata *)ob->data; -#if 0 - verts = MEM_callocN(mesh->totvert * sizeof(*verts), "closestboneverts"); + /* loop all strokes */ + CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) + { + bGPDframe *init_gpf = gpl->actframe; + bGPDspoint *pt = NULL; + if (is_multiedit) { + init_gpf = gpl->frames.first; + } - /* transform verts to global space */ - for (i = 0; i < mesh->totvert; i++) { - if (!vertsfilled) - copy_v3_v3(verts[i], mesh->mvert[i].co); - mul_m4_v3(ob->obmat, verts[i]); - } + for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { + if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) { + + if (gpf == NULL) + continue; + + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps) == false) + continue; + + /* create verts array */ + verts = MEM_callocN(gps->totpoints * sizeof(*verts), __func__); - /* compute the weights based on gathered vertices and bones */ - if (heat) { - const char *error = NULL; + /* transform stroke points to global space */ + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + copy_v3_v3(verts[i], &pt->x); + mul_m4_v3(ob->obmat, verts[i]); + } + + /* loop groups and assign weight */ + for (j = 0; j < numbones; j++) { + int def_nr = BLI_findindex(&ob->defbase, dgrouplist[j]); + if (def_nr < 0) { + continue; + } + + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + MDeformVert *dvert = &gps->dvert[i]; + float dist = test_point_in_cylynder(root[j], tip[j], + lensqr[j], radsqr[j], + pt); + if (dist < 0) { + /* if not in cylinder, check if inside sphere of extremes */ + weight = 0.0f; + float rad = radsqr[j] * 0.75f; + dist = len_squared_v3v3(root[j], &pt->x); + if (dist < rad) { + weight = interpf(0.0f, 0.9f, dist / rad); + } + else { + dist = len_squared_v3v3(tip[j], &pt->x); + if (dist < rad) { + weight = interpf(0.0f, 0.9f, dist / rad); + } + } + } + else { + /* inside bone cylinder */ + weight = 1.0f; + } + + /* assign weight */ + BKE_gpencil_vgroup_add_point_weight(dvert, def_nr, weight); + } + } + MEM_SAFE_FREE(verts); + + } + } - heat_bone_weighting( - ob, mesh, verts, numbones, dgrouplist, dgroupflip, - root, tip, selected, &error); - if (error) { - BKE_report(reports, RPT_WARNING, error); + /* if not multiedit, exit loop*/ + if (!is_multiedit) { + break; + } } } -#endif + CTX_DATA_END; /* free the memory allocated */ MEM_SAFE_FREE(bonelist); MEM_SAFE_FREE @@ Diff output truncated at 10240 characters. @@ _______________________________________________ Bf-blender-cvs mailing list Bf-blender-cvs@blender.org https://lists.blender.org/mailman/listinfo/bf-blender-cvs