[Bf-blender-cvs] [98058973d07] greasepencil-object: GPencil: Improve Mesh to GPencil edge conversion

Antonio Vazquez noreply at git.blender.org
Mon Mar 30 16:47:54 CEST 2020


Commit: 98058973d079b6acff1373fae77ecc0c520790c6
Author: Antonio Vazquez
Date:   Mon Mar 30 16:46:56 2020 +0200
Branches: greasepencil-object
https://developer.blender.org/rB98058973d079b6acff1373fae77ecc0c520790c6

GPencil: Improve Mesh to GPencil edge conversion

Now the strokes are done using edge loop calculated.

===================================================================

M	source/blender/blenkernel/intern/gpencil_geom.c

===================================================================

diff --git a/source/blender/blenkernel/intern/gpencil_geom.c b/source/blender/blenkernel/intern/gpencil_geom.c
index f2344d12fd4..8dd95540b06 100644
--- a/source/blender/blenkernel/intern/gpencil_geom.c
+++ b/source/blender/blenkernel/intern/gpencil_geom.c
@@ -1983,6 +1983,199 @@ void BKE_gpencil_convert_curve(Main *bmain,
   DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
 }
 
+typedef struct GpEdge {
+  uint v1, v2;
+  float v1_co[3], v2_co[3];
+  float vec[3];
+  int flag;
+} GpEdge;
+
+static int gpencil_next_edge(GpEdge *gp_edges, int totedges, GpEdge *gped_init, const bool reverse)
+{
+  int edge = -1;
+  float last_angle = 999999.0f;
+  const float threshold = M_PI / 3.0f;
+  for (int i = 0; i < totedges; i++) {
+    GpEdge *gped = &gp_edges[i];
+    if (gped->flag != 0) {
+      continue;
+    }
+    if (reverse) {
+      if (gped_init->v1 != gped->v2) {
+        continue;
+      }
+    }
+    else {
+      if (gped_init->v2 != gped->v1) {
+        continue;
+      }
+    }
+    /* Look for straight lines. */
+    float angle = angle_v3v3(gped->vec, gped_init->vec);
+    if ((angle < threshold) && (angle <= last_angle)) {
+      edge = i;
+      last_angle = angle;
+    }
+  }
+
+  return edge;
+}
+
+static int gpencil_walk_edge(GHash *v_table,
+                             GpEdge *gp_edges,
+                             int totedges,
+                             uint *stroke_array,
+                             int init_idx,
+                             const bool reverse)
+{
+  GpEdge *gped_init = &gp_edges[init_idx];
+  int idx = 1;
+  int edge = 0;
+  while (edge > -1) {
+    edge = gpencil_next_edge(gp_edges, totedges, gped_init, reverse);
+    if (edge > -1) {
+      GpEdge *gped = &gp_edges[edge];
+      stroke_array[idx] = edge;
+      gped->flag = 1;
+      gped_init = &gp_edges[edge];
+      idx++;
+
+      /* Avoid to follow already visited vertice. */
+      if (reverse) {
+        if (BLI_ghash_haskey(v_table, POINTER_FROM_INT(gped->v1))) {
+          edge = -1;
+        }
+        else {
+          BLI_ghash_insert(v_table, POINTER_FROM_INT(gped->v1), POINTER_FROM_INT(gped->v1));
+        }
+      }
+      else {
+        if (BLI_ghash_haskey(v_table, POINTER_FROM_INT(gped->v2))) {
+          edge = -1;
+        }
+        else {
+          BLI_ghash_insert(v_table, POINTER_FROM_INT(gped->v2), POINTER_FROM_INT(gped->v2));
+        }
+      }
+    }
+  }
+
+  return idx;
+}
+
+static void gpencil_generate_edgeloops(Object *ob, bGPDframe *gpf_stroke)
+{
+  const float vert_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+  Mesh *me = (Mesh *)ob->data;
+  if (me->totedge == 0) {
+    return;
+  }
+  /* Arrays for all edge vertices (forward and backward) that form a edge loop.
+   * This is reused for each edgeloop to create gpencil stroke. */
+  uint *stroke = MEM_callocN(sizeof(uint) * me->totedge * 2, __func__);
+  uint *stroke_fw = MEM_callocN(sizeof(uint) * me->totedge, __func__);
+  uint *stroke_bw = MEM_callocN(sizeof(uint) * me->totedge, __func__);
+
+  /* Create array with all edges. */
+  GpEdge *gp_edges = MEM_callocN(sizeof(GpEdge) * me->totedge, __func__);
+  GpEdge *gped = NULL;
+  for (int i = 0; i < me->totedge; i++) {
+    MEdge *ed = &me->medge[i];
+    gped = &gp_edges[i];
+    MVert *mv1 = &me->mvert[ed->v1];
+    gped->v1 = ed->v1;
+    copy_v3_v3(gped->v1_co, mv1->co);
+
+    MVert *mv2 = &me->mvert[ed->v2];
+    gped->v2 = ed->v2;
+    copy_v3_v3(gped->v2_co, mv2->co);
+
+    sub_v3_v3v3(gped->vec, mv1->co, mv2->co);
+  }
+
+  /* Loop edges to find edgeloops */
+  bool pending = true;
+  int e = 0;
+  while (pending) {
+    /* Clear arrays of stroke. */
+    memset(stroke_fw, 0, sizeof(uint) * me->totedge);
+    memset(stroke_bw, 0, sizeof(uint) * me->totedge);
+    memset(stroke, 0, sizeof(uint) * me->totedge * 2);
+
+    gped = &gp_edges[e];
+    /* Look first unused edge. */
+    if (gped->flag != 0) {
+      e++;
+      if (e == me->totedge) {
+        pending = false;
+      }
+      continue;
+    }
+    /* Add current edge to arrays. */
+    stroke_fw[0] = e;
+    stroke_bw[0] = e;
+    gped->flag = 1;
+
+    /* Hash used to avoid loop over same vertice. */
+    GHash *v_table = BLI_ghash_int_new(__func__);
+    /* Look forward edges. */
+    int totedges = gpencil_walk_edge(v_table, gp_edges, me->totedge, stroke_fw, e, false);
+    /* Look backward edges. */
+    int totbw = gpencil_walk_edge(v_table, gp_edges, me->totedge, stroke_bw, e, true);
+
+    BLI_ghash_free(v_table, NULL, NULL);
+
+    /* Join both arrays. */
+    int array_len = 0;
+    for (int i = totbw - 1; i > 0; i--) {
+      stroke[array_len] = stroke_bw[i];
+      array_len++;
+    }
+    for (int i = 0; i < totedges; i++) {
+      stroke[array_len] = stroke_fw[i];
+      array_len++;
+    }
+
+    /* Create Stroke. */
+    bGPDstroke *gps_stroke = BKE_gpencil_stroke_add(gpf_stroke, 0, array_len + 1, 5, false);
+    copy_v4_v4(gps_stroke->vert_color_fill, vert_color);
+
+    /* Create first segment. */
+    uint v = stroke[0];
+    gped = &gp_edges[v];
+    bGPDspoint *pt = &gps_stroke->points[0];
+    copy_v3_v3(&pt->x, gped->v1_co);
+    pt->pressure = 1.0f;
+    pt->strength = 1.0f;
+    copy_v4_v4(pt->vert_color, vert_color);
+
+    pt = &gps_stroke->points[1];
+    copy_v3_v3(&pt->x, gped->v2_co);
+    pt->pressure = 1.0f;
+    pt->strength = 1.0f;
+    copy_v4_v4(pt->vert_color, vert_color);
+
+    /* Add next segments. */
+    for (int i = 1; i < array_len; i++) {
+      v = stroke[i];
+      gped = &gp_edges[v];
+
+      bGPDspoint *pt = &gps_stroke->points[i + 1];
+      copy_v3_v3(&pt->x, gped->v2_co);
+      pt->pressure = 1.0f;
+      pt->strength = 1.0f;
+      copy_v4_v4(pt->vert_color, vert_color);
+    }
+
+    BKE_gpencil_stroke_geometry_update(gps_stroke);
+  }
+
+  /* Free memory. */
+  MEM_SAFE_FREE(stroke_fw);
+  MEM_SAFE_FREE(stroke_bw);
+  MEM_SAFE_FREE(gp_edges);
+}
+
 /* Convert a mesh object to grease pencil stroke.
  *
  * \param bmain: Main thread pointer
@@ -2005,6 +2198,7 @@ void BKE_gpencil_convert_mesh(Main *bmain,
   if (ELEM(NULL, ob_gp, ob_mesh) || (ob_gp->type != OB_GPENCIL) || (ob_gp->data == NULL)) {
     return;
   }
+
   bGPdata *gpd = (bGPdata *)ob_gp->data;
   /* Set object in 3D mode. */
   gpd->draw_mode = GP_DRAWMODE_3D;
@@ -2017,6 +2211,11 @@ void BKE_gpencil_convert_mesh(Main *bmain,
   int mpoly_len = me->totpoly;
   int i;
 
+  /* Need at least an edge. */
+  if (me->totvert < 2) {
+    return;
+  }
+
   /* Create two materials, one for stroke, one for fill */
   int r_idx;
   const float default_colors[3][4] = {
@@ -2024,60 +2223,50 @@ void BKE_gpencil_convert_mesh(Main *bmain,
   gpencil_add_material(bmain, ob_gp, default_colors[0], true, false, &r_idx);
   gpencil_add_material(bmain, ob_gp, default_colors[1], false, true, &r_idx);
 
-  /* Create two layers. */
-  bGPDlayer *gpl_fill = BKE_gpencil_layer_addnew(gpd, DATA_("Fills"), true);
-  bGPDlayer *gpl_stroke = BKE_gpencil_layer_addnew(gpd, DATA_("Lines"), true);
+  /* Read all polygons and create fill for each. */
+  if (mpoly_len > 0) {
+    bGPDlayer *gpl_fill = BKE_gpencil_layer_addnew(gpd, DATA_("Fills"), true);
+    bGPDframe *gpf_fill = BKE_gpencil_layer_frame_get(gpl_fill, CFRA, GP_GETFRAME_ADD_COPY);
+    for (i = 0, mp = mpoly; i < mpoly_len; i++, mp++) {
+      MLoop *ml = &mloop[mp->loopstart];
+      /* Get color from Material Viewport color. */
+      Material *mat = me->mat != NULL ? me->mat[mp->mat_nr] : NULL;
+      float vert_color[4];
+      if (mat != NULL) {
+        copy_v3_v3(vert_color, &mat->r);
+        vert_color[3] = 1.0f;
+      }
+      else {
+        /* Use default. */
+        copy_v4_v4(vert_color, default_colors[2]);
+      }
 
-  /* Check if there is an active frame and add if needed. */
-  bGPDframe *gpf_stroke = BKE_gpencil_layer_frame_get(gpl_stroke, CFRA, GP_GETFRAME_ADD_COPY);
-  bGPDframe *gpf_fill = BKE_gpencil_layer_frame_get(gpl_fill, CFRA, GP_GETFRAME_ADD_COPY);
-
-  /* Read all polygons and create a stroke and fill for each. */
-  for (i = 0, mp = mpoly; i < mpoly_len; i++, mp++) {
-    MLoop *ml = &mloop[mp->loopstart];
-    /* Get stroke and fill color from Material Viewport color. */
-    Material *mat = me->mat != NULL ? me->mat[mp->mat_nr] : NULL;
-    float vert_color[4];
-    if (mat != NULL) {
-      copy_v3_v3(vert_color, &mat->r);
-      vert_color[3] = 1.0f;
-    }
-    else {
-      /* Use default. */
-      copy_v4_v4(vert_color, default_colors[2]);
-    }
+      /* Create fill stroke. */
+      bGPDstroke *gps_fill = BKE_gpencil_stroke_add(gpf_fill, 1, mp->totloop, 10, false);
+      gps_fill->flag |= GP_STROKE_CYCLIC;
+      copy_v4_v4(gps_fill->vert_color_fill, vert_color);
 
-    /* Create line stroke. */
-    bGPDstroke *gps_stroke = BKE_gpencil_stroke_add(gpf_stroke, 0, mp->totloop, 10, false);
-    gps_stroke->flag |= GP_STROKE_CYCLIC;
-    bGPDstroke *gps_fill = BKE_gpencil_stroke_add(gpf_fill, 1, mp->totloop, 10, false);
-    gps_fill->flag |= GP_STROKE_CYCLIC;
-    copy_v4_v4(gps_stroke->vert_color_fill, vert_color);
-    copy_v4_v4(gps_fill->vert_color_fill, vert_color);
+      /* Add points to strokes. */
+      int j;
+      for (j = 0; j < mp->totloop; j++, ml++) {
+        MVert *mv = &me->mvert[ml->v];
 
-    /* Add points to strokes. */
-    int j;
-    for (j = 0; j < mp->totloop; j++, ml++) {
-      MVert *mv = &me->mvert[ml->v];
+        bGPDspoint *pt = &gps_fill->points[j];
+        copy_v3_v3(&pt->x, mv->co);
+        pt->pressure = 1.0f;
+        pt->strength = 1.0f;
+        copy_v4_v4(pt->vert_color, vert_color);
+      }
 
-      /* Line. */
-      bGPDspoint *pt = &gps_stroke->points[j];
-      copy_v3_v3(&pt->x, mv->co);
-      pt->pressure = 1.0f;
-      pt->strength = 1.0f;
-      copy_v4_v4(pt->vert_color, vert_color);
-      /* Fill. */
-      pt = &gps_fill->points[j];
-      copy_v3_v3(&pt->x, mv->co);
-      pt->pressure = 1.0f;
-      pt->strength = 1.0f;
-      copy_v4_v4(pt->vert_color, vert_color);
+      BKE_gpencil_stroke_geometry_update(gps_fill);
     }
-
-    BKE_gpencil_stroke_geometry_update(gps_stroke);
-    BKE_gpencil_stroke_geometry_update(gps_fill);
   }
 
+  /* Create stroke from edges. */
+  bGPDl

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list