diff options
author | Pablo Dobarro <pablodp606@gmail.com> | 2020-08-12 17:57:36 +0300 |
---|---|---|
committer | Pablo Dobarro <pablodp606@gmail.com> | 2020-08-12 19:26:56 +0300 |
commit | 478ea4c8988b924800937094e55e3e21ef5a16a5 (patch) | |
tree | e0a76b6899f97672b2ce54c54d6cbab05fca10dd /source/blender | |
parent | 6a95f05d65b5fc192d9689ca653e5b4e19a50cad (diff) |
Sculpt: Multires Displacement Eraser Brush
This brush deletes displacement information of the Multires Modifier,
resetting the mesh to the subdivision limit surface.
This can be use to easily delete parts of the sculpt or to fix
reprojection artifacts after applying a shrinkwrap.
Reviewed By: sergey
Differential Revision: https://developer.blender.org/D8543
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/blenkernel/BKE_subdiv_ccg.h | 3 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/brush.c | 6 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/subdiv_ccg.c | 43 | ||||
-rw-r--r-- | source/blender/blenloader/intern/versioning_defaults.c | 8 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt.c | 104 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_intern.h | 4 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_brush_types.h | 3 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_brush.c | 1 |
8 files changed, 169 insertions, 3 deletions
diff --git a/source/blender/blenkernel/BKE_subdiv_ccg.h b/source/blender/blenkernel/BKE_subdiv_ccg.h index 2277eb27ef1..7833ba9c046 100644 --- a/source/blender/blenkernel/BKE_subdiv_ccg.h +++ b/source/blender/blenkernel/BKE_subdiv_ccg.h @@ -311,6 +311,9 @@ void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG *subdiv_ccg, SubdivCCGNeighbors *r_neighbors); int BKE_subdiv_ccg_grid_to_face_index(const SubdivCCG *subdiv_ccg, const int grid_index); +void BKE_subdiv_ccg_eval_limit_point(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + float r_point[3]); typedef enum SubdivCCGAdjacencyType { SUBDIV_CCG_ADJACENT_NONE, diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index af186dc4940..8cd30c2241f 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -1481,6 +1481,11 @@ void BKE_brush_sculpt_reset(Brush *br) br->curve_preset = BRUSH_CURVE_POW4; br->spacing = 5; break; + case SCULPT_TOOL_DISPLACEMENT_ERASER: + br->curve_preset = BRUSH_CURVE_SMOOTHER; + br->spacing = 10; + br->alpha = 1.0f; + break; case SCULPT_TOOL_SLIDE_RELAX: br->spacing = 10; br->alpha = 1.0f; @@ -1680,6 +1685,7 @@ void BKE_brush_sculpt_reset(Brush *br) case SCULPT_TOOL_PAINT: case SCULPT_TOOL_MASK: case SCULPT_TOOL_DRAW_FACE_SETS: + case SCULPT_TOOL_DISPLACEMENT_ERASER: br->add_col[0] = 0.75f; br->add_col[1] = 0.75f; br->add_col[2] = 0.75f; diff --git a/source/blender/blenkernel/intern/subdiv_ccg.c b/source/blender/blenkernel/intern/subdiv_ccg.c index ea8bae4737a..0997b42a19f 100644 --- a/source/blender/blenkernel/intern/subdiv_ccg.c +++ b/source/blender/blenkernel/intern/subdiv_ccg.c @@ -1933,4 +1933,47 @@ void BKE_subdiv_ccg_grid_hidden_ensure(SubdivCCG *subdiv_ccg, int grid_index) subdiv_ccg->grid_hidden[grid_index] = BLI_BITMAP_NEW(key.grid_area, __func__); } +static void subdiv_ccg_coord_to_ptex_coord(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + int *r_ptex_face_index, + float *r_u, + float *r_v) +{ + Subdiv *subdiv = subdiv_ccg->subdiv; + + const float grid_size = subdiv_ccg->grid_size; + const float grid_size_1_inv = 1.0f / (grid_size - 1); + + const float grid_u = coord->x * grid_size_1_inv; + const float grid_v = coord->y * grid_size_1_inv; + + const int face_index = BKE_subdiv_ccg_grid_to_face_index(subdiv_ccg, coord->grid_index); + const SubdivCCGFace *faces = subdiv_ccg->faces; + const SubdivCCGFace *face = &faces[face_index]; + const int *face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv); + *r_ptex_face_index = face_ptex_offset[face_index]; + + const float corner = coord->grid_index - face->start_grid_index; + + if (face->num_grids == 4) { + BKE_subdiv_rotate_grid_to_quad(corner, grid_u, grid_v, r_u, r_v); + } + else { + *r_ptex_face_index += corner; + *r_u = 1.0f - grid_v; + *r_v = 1.0f - grid_u; + } +} + +void BKE_subdiv_ccg_eval_limit_point(const SubdivCCG *subdiv_ccg, + const SubdivCCGCoord *coord, + float r_point[3]) +{ + Subdiv *subdiv = subdiv_ccg->subdiv; + int ptex_face_index; + float u, v; + subdiv_ccg_coord_to_ptex_coord(subdiv_ccg, coord, &ptex_face_index, &u, &v); + BKE_subdiv_eval_limit_point(subdiv, ptex_face_index, u, v, r_point); +} + /** \} */ diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c index 631961e342d..df0b2b380fa 100644 --- a/source/blender/blenloader/intern/versioning_defaults.c +++ b/source/blender/blenloader/intern/versioning_defaults.c @@ -722,6 +722,14 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) brush->sculpt_tool = SCULPT_TOOL_DRAW_FACE_SETS; } + brush_name = "Multires Displacement Eraser"; + brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2); + if (!brush) { + brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); + id_us_min(&brush->id); + brush->sculpt_tool = SCULPT_TOOL_DISPLACEMENT_ERASER; + } + /* Use the same tool icon color in the brush cursor */ for (brush = bmain->brushes.first; brush; brush = brush->id.next) { if (brush->ob_mode & OB_MODE_SCULPT) { diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 36f227d6cc7..d68b1226b40 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -204,6 +204,27 @@ const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, int index) return SCULPT_vertex_co_get(ss, index); } +void SCULPT_vertex_limit_surface_get(SculptSession *ss, int index, float r_co[3]) +{ + switch (BKE_pbvh_type(ss->pbvh)) { + case PBVH_FACES: + case PBVH_BMESH: + copy_v3_v3(r_co, SCULPT_vertex_co_get(ss, index)); + break; + case PBVH_GRIDS: { + const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); + const int grid_index = index / key->grid_area; + const int vertex_index = index - grid_index * key->grid_area; + + SubdivCCGCoord coord = {.grid_index = grid_index, + .x = vertex_index % key->grid_size, + .y = vertex_index / key->grid_size}; + BKE_subdiv_ccg_eval_limit_point(ss->subdiv_ccg, &coord, r_co); + break; + } + } +} + void SCULPT_vertex_persistent_normal_get(SculptSession *ss, int index, float no[3]) { if (ss->persistent_base) { @@ -2236,6 +2257,8 @@ static float brush_strength(const Sculpt *sd, case SCULPT_TOOL_DRAW_SHARP: case SCULPT_TOOL_LAYER: return alpha * flip * pressure * overlap * feather; + case SCULPT_TOOL_DISPLACEMENT_ERASER: + return alpha * pressure * overlap * feather; case SCULPT_TOOL_CLOTH: if (brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB) { /* Grab deform uses the same falloff as a regular grab brush. */ @@ -2908,6 +2931,73 @@ static void do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) } } +/** \name Sculpt Multires Displacement Eraser Brush + * \{ */ + +static void do_displacement_eraser_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float bstrength = clamp_f(ss->cache->bstrength, 0.0f, 1.0f); + + float(*proxy)[3] = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) + { + if (sculpt_brush_test_sq_fn(&test, vd.co)) { + const float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + float limit_co[3]; + float disp[3]; + SCULPT_vertex_limit_surface_get(ss, vd.index, limit_co); + sub_v3_v3v3(disp, limit_co, vd.co); + mul_v3_v3fl(proxy[vd.i], disp, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + } + BKE_pbvh_vertex_iter_end; +} + +static void do_displacement_eraser_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + Brush *brush = BKE_paint_brush(&sd->paint); + BKE_curvemapping_init(brush->curve); + + /* Threaded loop over nodes. */ + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_displacement_eraser_brush_task_cb_ex, &settings); +} + +/** \} */ + static void do_draw_brush_task_cb_ex(void *__restrict userdata, const int n, const TaskParallelTLS *__restrict tls) @@ -5700,6 +5790,9 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe case SCULPT_TOOL_DRAW_FACE_SETS: SCULPT_do_draw_face_sets_brush(sd, ob, nodes, totnode); break; + case SCULPT_TOOL_DISPLACEMENT_ERASER: + do_displacement_eraser_brush(sd, ob, nodes, totnode); + break; case SCULPT_TOOL_PAINT: SCULPT_do_paint_brush(sd, ob, nodes, totnode); break; @@ -6251,6 +6344,8 @@ static const char *sculpt_tool_name(Sculpt *sd) return "Cloth Brush"; case SCULPT_TOOL_DRAW_FACE_SETS: return "Draw Face Sets"; + case SCULPT_TOOL_DISPLACEMENT_ERASER: + return "Multires Displacement Eraser"; case SCULPT_TOOL_PAINT: return "Paint Brush"; case SCULPT_TOOL_SMEAR: @@ -6436,9 +6531,12 @@ static void sculpt_update_cache_invariants( mul_m3_v3(mat, viewDir); normalize_v3_v3(cache->true_view_normal, viewDir); - cache->supports_gravity = - (!ELEM(brush->sculpt_tool, SCULPT_TOOL_MASK, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_SIMPLIFY) && - (sd->gravity_factor > 0.0f)); + cache->supports_gravity = (!ELEM(brush->sculpt_tool, + SCULPT_TOOL_MASK, + SCULPT_TOOL_SMOOTH, + SCULPT_TOOL_SIMPLIFY, + SCULPT_TOOL_DISPLACEMENT_ERASER) && + (sd->gravity_factor > 0.0f)); /* Get gravity vector in world space. */ if (cache->supports_gravity) { if (sd->gravity_object) { diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index caa858a5372..b11a7005fb5 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -100,6 +100,10 @@ const float *SCULPT_vertex_color_get(SculptSession *ss, int index); const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, int index); void SCULPT_vertex_persistent_normal_get(SculptSession *ss, int index, float no[3]); +/* Returs the info of the limit surface when Multires is available, otherwise it returns the + * current coordinate of the vertex. */ +void SCULPT_vertex_limit_surface_get(SculptSession *ss, int index, float r_co[3]); + #define SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY 256 typedef struct SculptVertexNeighborIter { /* Storage */ diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h index 503dba776a7..5d8eddaf5e1 100644 --- a/source/blender/makesdna/DNA_brush_types.h +++ b/source/blender/makesdna/DNA_brush_types.h @@ -810,6 +810,7 @@ typedef enum eBrushSculptTool { SCULPT_TOOL_PAINT = 28, SCULPT_TOOL_SMEAR = 29, SCULPT_TOOL_BOUNDARY = 30, + SCULPT_TOOL_DISPLACEMENT_ERASER = 31, } eBrushSculptTool; /* Brush.uv_sculpt_tool */ @@ -847,6 +848,7 @@ typedef enum eBrushUVSculptTool { SCULPT_TOOL_CLOTH, \ SCULPT_TOOL_THUMB, \ SCULPT_TOOL_LAYER, \ + SCULPT_TOOL_DISPLACEMENT_ERASER, \ SCULPT_TOOL_DRAW_SHARP, \ SCULPT_TOOL_SLIDE_RELAX, \ SCULPT_TOOL_ELASTIC_DEFORM, \ @@ -866,6 +868,7 @@ typedef enum eBrushUVSculptTool { SCULPT_TOOL_ROTATE, \ SCULPT_TOOL_THUMB, \ SCULPT_TOOL_DRAW_SHARP, \ + SCULPT_TOOL_DISPLACEMENT_ERASER, \ SCULPT_TOOL_SLIDE_RELAX, \ SCULPT_TOOL_MASK) == 0) diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index 852ddf32607..38916e2a45a 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -100,6 +100,7 @@ const EnumPropertyItem rna_enum_brush_sculpt_tool_items[] = { {SCULPT_TOOL_CLOTH, "CLOTH", ICON_BRUSH_SCULPT_DRAW, "Cloth", ""}, {SCULPT_TOOL_SIMPLIFY, "SIMPLIFY", ICON_BRUSH_DATA, "Simplify", ""}, {SCULPT_TOOL_MASK, "MASK", ICON_BRUSH_MASK, "Mask", ""}, + {SCULPT_TOOL_DISPLACEMENT_ERASER, "DISPLACEMENT_ERASER", ICON_BRUSH_SCULPT_DRAW, "Multires Displacement Eraser", ""}, {SCULPT_TOOL_PAINT, "PAINT", ICON_BRUSH_SCULPT_DRAW, "Paint", ""}, {SCULPT_TOOL_SMEAR, "SMEAR", ICON_BRUSH_SCULPT_DRAW, "Smear", ""}, {SCULPT_TOOL_DRAW_FACE_SETS, "DRAW_FACE_SETS", ICON_BRUSH_MASK, "Draw Face Sets", ""}, |