diff options
author | Henrik Dick <weasel> | 2021-08-17 21:04:27 +0300 |
---|---|---|
committer | Antonio Vazquez <blendergit@gmail.com> | 2021-08-17 21:20:47 +0300 |
commit | 88dc274d0533e3b4427a61718958bf84367b5077 (patch) | |
tree | b37cb6d150dd28419e4bcede23286cfeb8e409ca /source/blender/blenkernel/intern | |
parent | 96d0cd57dcca122657eb14fe071c78cdf9580e0d (diff) |
GPencil: Convert from Mesh copying Vertex Groups
This patch adds the missing ability to keep the vertex groups when converting to a grease pencil object. This is increadible useful to create rigged grease pencil objects which move together with rigged meshes.
Differential Revision: https://developer.blender.org/D12249
Diffstat (limited to 'source/blender/blenkernel/intern')
-rw-r--r-- | source/blender/blenkernel/intern/gpencil_geom.cc | 210 |
1 files changed, 120 insertions, 90 deletions
diff --git a/source/blender/blenkernel/intern/gpencil_geom.cc b/source/blender/blenkernel/intern/gpencil_geom.cc index f8a07939096..f2042d3098c 100644 --- a/source/blender/blenkernel/intern/gpencil_geom.cc +++ b/source/blender/blenkernel/intern/gpencil_geom.cc @@ -2269,7 +2269,8 @@ static void gpencil_generate_edgeloops(Object *ob, const int thickness, const float offset, const float matrix[4][4], - const bool use_seams) + const bool use_seams, + const bool use_vgroups) { Mesh *me = (Mesh *)ob->data; if (me->totedge == 0) { @@ -2278,9 +2279,9 @@ static void gpencil_generate_edgeloops(Object *ob, /* Arrays for all edge vertices (forward and backward) that form a edge loop. * This is reused for each edge-loop to create gpencil stroke. */ - uint *stroke = (uint *)MEM_callocN(sizeof(uint) * me->totedge * 2, __func__); - uint *stroke_fw = (uint *)MEM_callocN(sizeof(uint) * me->totedge, __func__); - uint *stroke_bw = (uint *)MEM_callocN(sizeof(uint) * me->totedge, __func__); + uint *stroke = (uint *)MEM_mallocN(sizeof(uint) * me->totedge * 2, __func__); + uint *stroke_fw = (uint *)MEM_mallocN(sizeof(uint) * me->totedge, __func__); + uint *stroke_bw = (uint *)MEM_mallocN(sizeof(uint) * me->totedge, __func__); /* Create array with all edges. */ GpEdge *gp_edges = (GpEdge *)MEM_callocN(sizeof(GpEdge) * me->totedge, __func__); @@ -2311,11 +2312,6 @@ static void gpencil_generate_edgeloops(Object *ob, 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) { @@ -2330,7 +2326,7 @@ static void gpencil_generate_edgeloops(Object *ob, stroke_bw[0] = e; gped->flag = 1; - /* Hash used to avoid loop over same vertice. */ + /* Hash used to avoid loop over same vertices. */ 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, angle, false); @@ -2354,38 +2350,41 @@ static void gpencil_generate_edgeloops(Object *ob, bGPDstroke *gps_stroke = BKE_gpencil_stroke_add( gpf_stroke, MAX2(stroke_mat_index, 0), array_len + 1, thickness * thickness, false); + /* Create dvert data. */ + MDeformVert *me_dvert = me->dvert; + if (use_vgroups && me_dvert) { + gps_stroke->dvert = (MDeformVert *)MEM_callocN(sizeof(MDeformVert) * (array_len + 1), + "gp_stroke_dverts"); + } + /* Create first segment. */ float fpt[3]; - uint v = stroke[0]; - gped = &gp_edges[v]; - bGPDspoint *pt = &gps_stroke->points[0]; - mul_v3_v3fl(fpt, gped->n1, offset); - add_v3_v3v3(&pt->x, gped->v1_co, fpt); - mul_m4_v3(matrix, &pt->x); - - pt->pressure = 1.0f; - pt->strength = 1.0f; - - pt = &gps_stroke->points[1]; - mul_v3_v3fl(fpt, gped->n2, offset); - add_v3_v3v3(&pt->x, gped->v2_co, fpt); - mul_m4_v3(matrix, &pt->x); - - pt->pressure = 1.0f; - pt->strength = 1.0f; - - /* Add next segments. */ - for (int i = 1; i < array_len; i++) { - v = stroke[i]; - gped = &gp_edges[v]; - - pt = &gps_stroke->points[i + 1]; - mul_v3_v3fl(fpt, gped->n2, offset); - add_v3_v3v3(&pt->x, gped->v2_co, fpt); + for (int i = 0; i < array_len + 1; i++) { + int vertex_index = i == 0 ? gp_edges[stroke[0]].v1 : gp_edges[stroke[i - 1]].v2; + MVert *mv = &me->mvert[vertex_index]; + + /* Add segment. */ + bGPDspoint *pt = &gps_stroke->points[i]; + normal_short_to_float_v3(fpt, mv->no); + mul_v3_v3fl(fpt, fpt, offset); + add_v3_v3v3(&pt->x, mv->co, fpt); mul_m4_v3(matrix, &pt->x); pt->pressure = 1.0f; pt->strength = 1.0f; + + /* Copy vertex groups from mesh. Assuming they already exist in the same order. */ + if (use_vgroups && me_dvert) { + MDeformVert *dv = &gps_stroke->dvert[i]; + MDeformVert *src_dv = &me_dvert[vertex_index]; + dv->totweight = src_dv->totweight; + dv->dw = (MDeformWeight *)MEM_callocN(sizeof(MDeformWeight) * dv->totweight, + "gp_stroke_dverts_dw"); + for (int j = 0; j < dv->totweight; j++) { + dv->dw[j].weight = src_dv->dw[j].weight; + dv->dw[j].def_nr = src_dv->dw[j].def_nr; + } + } } BKE_gpencil_stroke_geometry_update(gpd, gps_stroke); @@ -2488,7 +2487,8 @@ bool BKE_gpencil_convert_mesh(Main *bmain, const float matrix[4][4], const int frame_offset, const bool use_seams, - const bool use_faces) + const bool use_faces, + const bool use_vgroups) { if (ELEM(nullptr, ob_gp, ob_mesh) || (ob_gp->type != OB_GPENCIL) || (ob_gp->data == nullptr)) { return false; @@ -2505,83 +2505,105 @@ bool BKE_gpencil_convert_mesh(Main *bmain, char element_name[200]; /* Need at least an edge. */ - if (me_eval->totvert < 2) { + if (me_eval->totedge < 1) { return false; } + /* Create matching vertex groups. */ + BKE_defgroup_copy_list(&gpd->vertex_group_names, &me_eval->vertex_group_names); + gpd->vertex_group_active_index = me_eval->vertex_group_active_index; + const float default_colors[2][4] = {{0.0f, 0.0f, 0.0f, 1.0f}, {0.7f, 0.7f, 0.7f, 1.0f}}; - /* Create stroke material. */ + /* Lookup existing stroke material on gp object. */ make_element_name(ob_mesh->id.name + 2, "Stroke", 64, element_name); int stroke_mat_index = gpencil_material_find_index_by_name(ob_gp, element_name); if (stroke_mat_index == -1) { + /* Create new default stroke material as there is no existing material. */ gpencil_add_material( bmain, ob_gp, element_name, default_colors[0], true, false, &stroke_mat_index); } /* Export faces as filled strokes. */ - if (use_faces) { - + if (use_faces && mpoly_len > 0) { /* Read all polygons and create fill for each. */ - if (mpoly_len > 0) { - make_element_name(ob_mesh->id.name + 2, "Fills", 128, element_name); - /* Create Layer and Frame. */ - bGPDlayer *gpl_fill = BKE_gpencil_layer_named_get(gpd, element_name); - if (gpl_fill == nullptr) { - gpl_fill = BKE_gpencil_layer_addnew(gpd, element_name, true, false); - } - bGPDframe *gpf_fill = BKE_gpencil_layer_frame_get( - gpl_fill, CFRA + frame_offset, GP_GETFRAME_ADD_NEW); - int i; - for (i = 0; i < mpoly_len; i++) { - const MPoly *mp = &mpoly[i]; - - /* Find material. */ - int mat_idx = 0; - Material *ma = BKE_object_material_get(ob_mesh, mp->mat_nr + 1); - make_element_name( - ob_mesh->id.name + 2, (ma != nullptr) ? ma->id.name + 2 : "Fill", 64, element_name); - mat_idx = BKE_gpencil_material_find_index_by_name_prefix(ob_gp, element_name); - if (mat_idx == -1) { - float color[4]; - if (ma != nullptr) { - copy_v3_v3(color, &ma->r); - color[3] = 1.0f; - } - else { - copy_v4_v4(color, default_colors[1]); - } - gpencil_add_material(bmain, ob_gp, element_name, color, false, true, &mat_idx); + make_element_name(ob_mesh->id.name + 2, "Fills", 128, element_name); + /* Create Layer and Frame. */ + bGPDlayer *gpl_fill = BKE_gpencil_layer_named_get(gpd, element_name); + if (gpl_fill == nullptr) { + gpl_fill = BKE_gpencil_layer_addnew(gpd, element_name, true, false); + } + bGPDframe *gpf_fill = BKE_gpencil_layer_frame_get( + gpl_fill, CFRA + frame_offset, GP_GETFRAME_ADD_NEW); + int i; + for (i = 0; i < mpoly_len; i++) { + const MPoly *mp = &mpoly[i]; + + /* Find material. */ + int mat_idx = 0; + Material *ma = BKE_object_material_get(ob_mesh, mp->mat_nr + 1); + make_element_name( + ob_mesh->id.name + 2, (ma != nullptr) ? ma->id.name + 2 : "Fill", 64, element_name); + mat_idx = BKE_gpencil_material_find_index_by_name_prefix(ob_gp, element_name); + if (mat_idx == -1) { + float color[4]; + if (ma != nullptr) { + copy_v3_v3(color, &ma->r); + color[3] = 1.0f; } + else { + copy_v4_v4(color, default_colors[1]); + } + gpencil_add_material(bmain, ob_gp, element_name, color, false, true, &mat_idx); + } - bGPDstroke *gps_fill = BKE_gpencil_stroke_add(gpf_fill, mat_idx, mp->totloop, 10, false); - gps_fill->flag |= GP_STROKE_CYCLIC; + bGPDstroke *gps_fill = BKE_gpencil_stroke_add(gpf_fill, mat_idx, mp->totloop, 10, false); + gps_fill->flag |= GP_STROKE_CYCLIC; - /* Add points to strokes. */ - for (int j = 0; j < mp->totloop; j++) { - const MLoop *ml = &mloop[mp->loopstart + j]; - const MVert *mv = &me_eval->mvert[ml->v]; + /* Create dvert data. */ + MDeformVert *me_dvert = me_eval->dvert; + if (use_vgroups && me_dvert) { + gps_fill->dvert = (MDeformVert *)MEM_callocN(sizeof(MDeformVert) * mp->totloop, + "gp_fill_dverts"); + } - bGPDspoint *pt = &gps_fill->points[j]; - copy_v3_v3(&pt->x, mv->co); - mul_m4_v3(matrix, &pt->x); - pt->pressure = 1.0f; - pt->strength = 1.0f; - } - /* If has only 3 points subdivide. */ - if (mp->totloop == 3) { - BKE_gpencil_stroke_subdivide(gpd, gps_fill, 1, GP_SUBDIV_SIMPLE); + /* Add points to strokes. */ + for (int j = 0; j < mp->totloop; j++) { + const MLoop *ml = &mloop[mp->loopstart + j]; + const MVert *mv = &me_eval->mvert[ml->v]; + + bGPDspoint *pt = &gps_fill->points[j]; + copy_v3_v3(&pt->x, mv->co); + mul_m4_v3(matrix, &pt->x); + pt->pressure = 1.0f; + pt->strength = 1.0f; + + /* Copy vertex groups from mesh. Assuming they already exist in the same order. */ + if (use_vgroups && me_dvert) { + MDeformVert *dv = &gps_fill->dvert[j]; + MDeformVert *src_dv = &me_dvert[ml->v]; + dv->totweight = src_dv->totweight; + dv->dw = (MDeformWeight *)MEM_callocN(sizeof(MDeformWeight) * dv->totweight, + "gp_fill_dverts_dw"); + for (int k = 0; k < dv->totweight; k++) { + dv->dw[k].weight = src_dv->dw[k].weight; + dv->dw[k].def_nr = src_dv->dw[k].def_nr; + } } - - BKE_gpencil_stroke_geometry_update(gpd, gps_fill); } + /* If has only 3 points subdivide. */ + if (mp->totloop == 3) { + BKE_gpencil_stroke_subdivide(gpd, gps_fill, 1, GP_SUBDIV_SIMPLE); + } + + BKE_gpencil_stroke_geometry_update(gpd, gps_fill); } } /* Create stroke from edges. */ - make_element_name(ob_mesh->id.name + 2, "Lines", 128, element_name); /* Create Layer and Frame. */ + make_element_name(ob_mesh->id.name + 2, "Lines", 128, element_name); bGPDlayer *gpl_stroke = BKE_gpencil_layer_named_get(gpd, element_name); if (gpl_stroke == nullptr) { gpl_stroke = BKE_gpencil_layer_addnew(gpd, element_name, true, false); @@ -2589,8 +2611,16 @@ bool BKE_gpencil_convert_mesh(Main *bmain, bGPDframe *gpf_stroke = BKE_gpencil_layer_frame_get( gpl_stroke, CFRA + frame_offset, GP_GETFRAME_ADD_NEW); - gpencil_generate_edgeloops( - ob_eval, gpd, gpf_stroke, stroke_mat_index, angle, thickness, offset, matrix, use_seams); + gpencil_generate_edgeloops(ob_eval, + gpd, + gpf_stroke, + stroke_mat_index, + angle, + thickness, + offset, + matrix, + use_seams, + use_vgroups); /* Tag for recalculation */ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE); |