Commit: 47645a8db6223ba31b8128db7502f27876a2586b Author: Pablo Dobarro Date: Tue Nov 26 18:53:38 2019 +0100 Branches: master https://developer.blender.org/rB47645a8db6223ba31b8128db7502f27876a2586b
Sculpt: Sample Voxel Size This adds support to the current sculpt sample detail operator to sample a voxel size for the voxel remesher when sculpting on regular meshes. It provides an approximation of a voxel size that is going to preserve the sampled sculpt details after remeshing. It is not going to be 100% accurate in all cases as it relies on having consistent edge length in the whole sculpt, but it saves a lot of time and avoids guessing the voxel size by trying different values. Reviewed By: jbakker Differential Revision: https://developer.blender.org/D6251 =================================================================== M release/scripts/startup/bl_ui/space_view3d_toolbar.py M source/blender/editors/sculpt_paint/sculpt.c =================================================================== diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index 724264fe494..718365ec99d 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -1193,7 +1193,8 @@ class VIEW3D_PT_sculpt_dyntopo(Panel, View3DPaintPanel): if sculpt.detail_type_method in {'CONSTANT', 'MANUAL'}: row = sub.row(align=True) row.prop(sculpt, "constant_detail_resolution") - row.operator("sculpt.sample_detail_size", text="", icon='EYEDROPPER') + props = row.operator("sculpt.sample_detail_size", text="", icon='EYEDROPPER') + props.mode = 'DYNTOPO' elif (sculpt.detail_type_method == 'BRUSH'): sub.prop(sculpt, "detail_percent") else: @@ -1252,7 +1253,10 @@ class VIEW3D_PT_sculpt_voxel_remesh(Panel, View3DPaintPanel): col = layout.column() mesh = context.active_object.data - col.prop(mesh, "remesh_voxel_size") + row = col.row(align=True) + row.prop(mesh, "remesh_voxel_size") + props = row.operator("sculpt.sample_detail_size", text="", icon='EYEDROPPER') + props.mode = 'VOXEL' col.prop(mesh, "remesh_voxel_adaptivity") col.prop(mesh, "use_remesh_fix_poles") col.prop(mesh, "use_remesh_smooth_normals") diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 38e4d119aa5..63b9949e0ef 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -8445,36 +8445,60 @@ static void SCULPT_OT_detail_flood_fill(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -static void sample_detail(bContext *C, int mx, int my) +typedef enum eSculptSampleDetailModeTypes { + SAMPLE_DETAIL_DYNTOPO = 0, + SAMPLE_DETAIL_VOXEL = 1, +} eSculptSampleDetailModeTypes; + +static EnumPropertyItem prop_sculpt_sample_detail_mode_types[] = { + {SAMPLE_DETAIL_DYNTOPO, "DYNTOPO", 0, "Dyntopo", "Sample dyntopo detail"}, + {SAMPLE_DETAIL_VOXEL, "VOXEL", 0, "Voxel", "Sample mesh voxel size"}, + {0, NULL, 0, NULL, NULL}, +}; + +static void sample_detail_voxel(bContext *C, ViewContext *vc, int mx, int my) { - /* Find 3D view to pick from. */ - bScreen *screen = CTX_wm_screen(C); - ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_VIEW3D, mx, my); - ARegion *ar = (sa) ? BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my) : NULL; - if (ar == NULL) { - return; - } + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); + Object *ob = vc->obact; + Mesh *mesh = ob->data; - /* Set context to 3D view. */ - ScrArea *prev_sa = CTX_wm_area(C); - ARegion *prev_ar = CTX_wm_region(C); - CTX_wm_area_set(C, sa); - CTX_wm_region_set(C, ar); + SculptSession *ss = ob->sculpt; + SculptCursorGeometryInfo sgi; + sculpt_vertex_random_access_init(ss); - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - ViewContext vc; - ED_view3d_viewcontext_init(C, &vc, depsgraph); + /* Update the active vertex */ + float mouse[2] = {mx, my}; + sculpt_cursor_geometry_info_update(C, &sgi, mouse, false); + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false); - /* Pick sample detail. */ + /* Average the edge length of the connected edges to the active vertex */ + int active_vertex = sculpt_active_vertex_get(ss); + const float *active_vertex_co = sculpt_active_vertex_co_get(ss); + float edge_length = 0.0f; + int tot = 0; + SculptVertexNeighborIter ni; + sculpt_vertex_neighbors_iter_begin(ss, active_vertex, ni) + { + edge_length += len_v3v3(active_vertex_co, sculpt_vertex_co_get(ss, ni.index)); + tot += 1; + } + sculpt_vertex_neighbors_iter_end(ni); + if (tot > 0) { + mesh->remesh_voxel_size = edge_length / (float)tot; + } +} + +static void sample_detail_dyntopo(bContext *C, ViewContext *vc, ARegion *ar, int mx, int my) +{ Sculpt *sd = CTX_data_tool_settings(C)->sculpt; - Object *ob = vc.obact; + Object *ob = vc->obact; Brush *brush = BKE_paint_brush(&sd->paint); sculpt_stroke_modifiers_check(C, ob, brush); float mouse[2] = {mx - ar->winrct.xmin, my - ar->winrct.ymin}; float ray_start[3], ray_end[3], ray_normal[3]; - float depth = sculpt_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, false); + float depth = sculpt_raycast_init(vc, mouse, ray_start, ray_end, ray_normal, false); SculptDetailRaycastData srd; srd.hit = 0; @@ -8489,6 +8513,37 @@ static void sample_detail(bContext *C, int mx, int my) /* Convert edge length to world space detail resolution. */ sd->constant_detail = 1 / (srd.edge_length * mat4_to_scale(ob->obmat)); } +} + +static void sample_detail(bContext *C, int mx, int my, int mode) +{ + /* Find 3D view to pick from. */ + bScreen *screen = CTX_wm_screen(C); + ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_VIEW3D, mx, my); + ARegion *ar = (sa) ? BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my) : NULL; + if (ar == NULL) { + return; + } + + /* Set context to 3D view. */ + ScrArea *prev_sa = CTX_wm_area(C); + ARegion *prev_ar = CTX_wm_region(C); + CTX_wm_area_set(C, sa); + CTX_wm_region_set(C, ar); + + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + ViewContext vc; + ED_view3d_viewcontext_init(C, &vc, depsgraph); + + /* Pick sample detail. */ + switch (mode) { + case SAMPLE_DETAIL_DYNTOPO: + sample_detail_dyntopo(C, &vc, ar, mx, my); + break; + case SAMPLE_DETAIL_VOXEL: + sample_detail_voxel(C, &vc, mx, my); + break; + } /* Restore context. */ CTX_wm_area_set(C, prev_sa); @@ -8499,7 +8554,8 @@ static int sculpt_sample_detail_size_exec(bContext *C, wmOperator *op) { int ss_co[2]; RNA_int_get_array(op->ptr, "location", ss_co); - sample_detail(C, ss_co[0], ss_co[1]); + int mode = RNA_enum_get(op->ptr, "mode"); + sample_detail(C, ss_co[0], ss_co[1], mode); return OPERATOR_FINISHED; } @@ -8518,7 +8574,8 @@ static int sculpt_sample_detail_size_modal(bContext *C, wmOperator *op, const wm if (event->val == KM_PRESS) { int ss_co[2] = {event->x, event->y}; - sample_detail(C, ss_co[0], ss_co[1]); + int mode = RNA_enum_get(op->ptr, "mode"); + sample_detail(C, ss_co[0], ss_co[1], mode); RNA_int_set_array(op->ptr, "location", ss_co); WM_cursor_modal_restore(CTX_wm_window(C)); @@ -8551,7 +8608,7 @@ static void SCULPT_OT_sample_detail_size(wmOperatorType *ot) ot->invoke = sculpt_sample_detail_size_invoke; ot->exec = sculpt_sample_detail_size_exec; ot->modal = sculpt_sample_detail_size_modal; - ot->poll = sculpt_and_constant_or_manual_detail_poll; + ot->poll = sculpt_mode_poll; ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -8565,6 +8622,12 @@ static void SCULPT_OT_sample_detail_size(wmOperatorType *ot) "Screen Coordinates of sampling", 0, SHRT_MAX); + RNA_def_enum(ot->srna, + "mode", + prop_sculpt_sample_detail_mode_types, + SAMPLE_DETAIL_DYNTOPO, + "Detail Mode", + "Target sculpting workflow that is going to use the sampled size"); } /* Dynamic-topology detail size _______________________________________________ Bf-blender-cvs mailing list [email protected] https://lists.blender.org/mailman/listinfo/bf-blender-cvs
