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

Reply via email to