diff options
-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", ""}, |