From 4f616c93f7cb8c8c8e038bc0c949c931242971c2 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 28 Sep 2017 01:38:17 +1000 Subject: Vertex/Weight Paint: Use PBVH for painting 2016 GSOC project by @nathanvollmer, see D2150 - Mirrored painting and radial symmetry, like in sculpt mode. - Volume based splash prevention, which avoids painting vertices far away from the 3D brush location. - Normal based splash prevention, which avoids painting vertices with normals opposite the normal at the 3D brush location. - Blur mode now uses a nearest neighbor average. - Average mode, which averages the color/weight of the vertices within the brush - Smudge mode, which pulls the colors/weights along the direction of the brush - RGB^2 color blending, which gives a more accurate blend between two colors - multithreading support. (PBVH leaves are painted in parallel.) - Foreground/background color picker in vertex paint --- source/blender/blenkernel/intern/DerivedMesh.c | 2 +- source/blender/blenkernel/intern/cdderivedmesh.c | 5 ++++ source/blender/blenkernel/intern/object.c | 5 +++- source/blender/blenkernel/intern/paint.c | 35 ++++++++++++++++++++---- source/blender/blenkernel/intern/pbvh.c | 14 ++++++++-- source/blender/blenkernel/intern/pbvh_intern.h | 2 ++ source/blender/blenkernel/intern/scene.c | 12 -------- source/blender/blenkernel/intern/subsurf_ccg.c | 20 ++++++++++++-- 8 files changed, 72 insertions(+), 23 deletions(-) (limited to 'source/blender/blenkernel/intern') diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index ace79f4125b..9dae4c5eae7 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -2663,7 +2663,7 @@ static void mesh_build_data( ob->lastDataMask = dataMask; ob->lastNeedMapping = need_mapping; - if ((ob->mode & OB_MODE_SCULPT) && ob->sculpt) { + if ((ob->mode & OB_MODE_ALL_SCULPT) && ob->sculpt) { /* create PBVH immediately (would be created on the fly too, * but this avoids waiting on first stroke) */ diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index 2c61cf28691..e97de07752e 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -662,6 +662,11 @@ static void cdDM_drawMappedFaces( const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX); + if (cddm->pbvh) { + if (G.debug_value == 14) + BKE_pbvh_draw_BB(cddm->pbvh); + } + /* fist, setup common buffers */ GPU_vertex_setup(dm); GPU_triangle_setup(dm); diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index d76ef613023..44058c989ff 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -2682,7 +2682,7 @@ void BKE_object_sculpt_modifiers_changed(Object *ob) { SculptSession *ss = ob->sculpt; - if (ss) { + if (ss && ss->building_vp_handle == false) { if (!ss->cache) { /* we free pbvh on changes, except during sculpt since it can't deal with * changing PVBH node organization, we hope topology does not change in @@ -2693,6 +2693,9 @@ void BKE_object_sculpt_modifiers_changed(Object *ob) } BKE_sculptsession_free_deformMats(ob->sculpt); + + /* In vertex/weight paint, force maps to be rebuilt. */ + BKE_sculptsession_free_vwpaint_data(ob->sculpt); } else { PBVHNode **nodes; diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 9fc2136df86..25ea6ad079f 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -673,6 +673,29 @@ void BKE_sculptsession_free_deformMats(SculptSession *ss) MEM_SAFE_FREE(ss->deform_imats); } +void BKE_sculptsession_free_vwpaint_data(struct SculptSession *ss) +{ + struct SculptVertexPaintGeomMap *gmap = NULL; + if (ss->mode_type == OB_MODE_VERTEX_PAINT) { + gmap = &ss->mode.vpaint.gmap; + + MEM_SAFE_FREE(ss->mode.vpaint.previous_color); + } + else if (ss->mode_type == OB_MODE_WEIGHT_PAINT) { + gmap = &ss->mode.wpaint.gmap; + + MEM_SAFE_FREE(ss->mode.wpaint.alpha_weight); + MEM_SAFE_FREE(ss->mode.wpaint.previous_weight); + } + else { + return; + } + MEM_SAFE_FREE(gmap->vert_to_loop); + MEM_SAFE_FREE(gmap->vert_map_mem); + MEM_SAFE_FREE(gmap->vert_to_poly); + MEM_SAFE_FREE(gmap->poly_map_mem); +} + /* Write out the sculpt dynamic-topology BMesh to the Mesh */ static void sculptsession_bm_to_me_update_data_only(Object *ob, bool reorder) { @@ -714,10 +737,7 @@ void BKE_sculptsession_bm_to_me_for_render(Object *object) */ BKE_object_free_derived_caches(object); - if (object->sculpt->pbvh) { - BKE_pbvh_free(object->sculpt->pbvh); - object->sculpt->pbvh = NULL; - } + MEM_SAFE_FREE(object->sculpt->pbvh); sculptsession_bm_to_me_update_data_only(object, false); @@ -764,6 +784,8 @@ void BKE_sculptsession_free(Object *ob) if (ss->deform_imats) MEM_freeN(ss->deform_imats); + BKE_sculptsession_free_vwpaint_data(ob->sculpt); + MEM_freeN(ss); ob->sculpt = NULL; @@ -848,6 +870,8 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob, ss->modifiers_active = sculpt_modifiers_active(scene, sd, ob); ss->show_diffuse_color = (sd->flags & SCULPT_SHOW_DIFFUSE) != 0; + ss->building_vp_handle = false; + if (need_mask) { if (mmd == NULL) { if (!CustomData_has_layer(&me->vdata, CD_PAINT_MASK)) { @@ -876,7 +900,8 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob, dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); - if (mmd) { + /* VWPaint require mesh info for loop lookup, so require sculpt mode here */ + if (mmd && ob->mode & OB_MODE_SCULPT) { ss->multires = mmd; ss->totvert = dm->getNumVerts(dm); ss->totpoly = dm->getNumPolys(dm); diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 53dfffe2b97..4b154d3301c 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -34,6 +34,7 @@ #include "BKE_pbvh.h" #include "BKE_ccg.h" +#include "BKE_subsurf.h" #include "BKE_DerivedMesh.h" #include "BKE_global.h" #include "BKE_mesh.h" /* for BKE_mesh_calc_normals */ @@ -606,6 +607,10 @@ void BKE_pbvh_build_grids(PBVH *bvh, CCGElem **grids, MEM_freeN(prim_bbc); } +void BKE_pbvh_set_ccgdm(PBVH *bvh, CCGDerivedMesh *ccgdm) { + bvh->ccgdm = ccgdm; +} + PBVH *BKE_pbvh_new(void) { PBVH *bvh = MEM_callocN(sizeof(PBVH), "pbvh"); @@ -1156,7 +1161,7 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode) } } -static void pbvh_draw_BB(PBVH *bvh) +void BKE_pbvh_draw_BB(PBVH *bvh) { GPU_pbvh_BB_draw_init(); @@ -1329,6 +1334,11 @@ void BKE_pbvh_get_grid_key(const PBVH *bvh, CCGKey *key) *key = bvh->gridkey; } +CCGDerivedMesh *BKE_pbvh_get_ccgdm(const PBVH *bvh) { + return bvh->ccgdm; +} + + BMesh *BKE_pbvh_get_bmesh(PBVH *bvh) { BLI_assert(bvh->type == PBVH_BMESH); @@ -1860,7 +1870,7 @@ void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*fnors)[3], } if (G.debug_value == 14) - pbvh_draw_BB(bvh); + BKE_pbvh_draw_BB(bvh); } void BKE_pbvh_grids_update(PBVH *bvh, CCGElem **grids, void **gridfaces, diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h index 19d3b31bd31..01057318568 100644 --- a/source/blender/blenkernel/intern/pbvh_intern.h +++ b/source/blender/blenkernel/intern/pbvh_intern.h @@ -149,6 +149,8 @@ struct PBVH { * objects in sculpt mode with different sizes at the same time, so now storing that common gpu buffer * in an opaque pointer per pbvh. See T47637. */ struct GridCommonGPUBuffer *grid_common_gpu_buffer; + /* The ccgdm is required for CD_ORIGINDEX lookup in vertex paint + multires */ + struct CCGDerivedMesh *ccgdm; /* Only used during BVH build and update, * don't need to remain valid after */ diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 5b809386267..c0dcac33656 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -217,16 +217,10 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons ToolSettings *ts = sce_dst->toolsettings = MEM_dupallocN(sce_dst->toolsettings); if (ts->vpaint) { ts->vpaint = MEM_dupallocN(ts->vpaint); - ts->vpaint->paintcursor = NULL; - ts->vpaint->vpaint_prev = NULL; - ts->vpaint->wpaint_prev = NULL; BKE_paint_copy(&ts->vpaint->paint, &ts->vpaint->paint, flag_subdata); } if (ts->wpaint) { ts->wpaint = MEM_dupallocN(ts->wpaint); - ts->wpaint->paintcursor = NULL; - ts->wpaint->vpaint_prev = NULL; - ts->wpaint->wpaint_prev = NULL; BKE_paint_copy(&ts->wpaint->paint, &ts->wpaint->paint, flag_subdata); } if (ts->sculpt) { @@ -335,16 +329,10 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) if (ts) { if (ts->vpaint) { ts->vpaint = MEM_dupallocN(ts->vpaint); - ts->vpaint->paintcursor = NULL; - ts->vpaint->vpaint_prev = NULL; - ts->vpaint->wpaint_prev = NULL; BKE_paint_copy(&ts->vpaint->paint, &ts->vpaint->paint, 0); } if (ts->wpaint) { ts->wpaint = MEM_dupallocN(ts->wpaint); - ts->wpaint->paintcursor = NULL; - ts->wpaint->vpaint_prev = NULL; - ts->wpaint->wpaint_prev = NULL; BKE_paint_copy(&ts->wpaint->paint, &ts->wpaint->paint, 0); } if (ts->sculpt) { diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index f4ff4dfa019..7c5ee42b7bc 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -3683,6 +3683,11 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm, int gridFaces = gridSize - 1, totface; int prev_mat_nr = -1; + if (ccgdm->pbvh) { + if (G.debug_value == 14) + BKE_pbvh_draw_BB(ccgdm->pbvh); + } + #ifdef WITH_OPENSUBDIV if (ccgdm->useGpuBackend) { int new_matnr; @@ -4416,7 +4421,8 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm) if (!ob->sculpt) return NULL; - grid_pbvh = ccgDM_use_grid_pbvh(ccgdm); + /* In vwpaint, we always use a grid_pbvh for multires/subsurf */ + grid_pbvh = (!(ob->mode & OB_MODE_SCULPT) || ccgDM_use_grid_pbvh(ccgdm)); if (ob->sculpt->pbvh) { if (grid_pbvh) { @@ -4432,12 +4438,18 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm) ccgdm->pbvh = ob->sculpt->pbvh; } - if (ccgdm->pbvh) + if (ccgdm->pbvh) { + /* For vertex paint, keep track of ccgdm */ + if (!(ob->mode & OB_MODE_SCULPT)) { + BKE_pbvh_set_ccgdm(ccgdm->pbvh, ccgdm); + } return ccgdm->pbvh; + } /* no pbvh exists yet, we need to create one. only in case of multires * we build a pbvh over the modified mesh, in other cases the base mesh * is being sculpted, so we build a pbvh from that. */ + /* Note: vwpaint always builds a pbvh over the modified mesh. */ if (grid_pbvh) { ccgdm_create_grids(dm); @@ -4468,6 +4480,10 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm) if (ccgdm->pbvh) pbvh_show_diffuse_color_set(ccgdm->pbvh, ob->sculpt->show_diffuse_color); + /* For vertex paint, keep track of ccgdm */ + if (!(ob->mode & OB_MODE_SCULPT) && ccgdm->pbvh) { + BKE_pbvh_set_ccgdm(ccgdm->pbvh, ccgdm); + } return ccgdm->pbvh; } -- cgit v1.2.3