[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