* Dyntopo now has its own brush spacing. This is a huge performance

boost for brushes with fine spacing, e.g. the clay brush.
This commit is contained in:
Joseph Eagar 2021-04-01 14:51:10 -07:00
parent 0dc09668ce
commit 7bba304c57
13 changed files with 141 additions and 78 deletions

View File

@ -807,6 +807,8 @@ class VIEW3D_PT_sculpt_dyntopo(Panel, View3DPaintPanel):
col.prop(sculpt, "use_smooth_shading")
col.prop(sculpt, "use_flat_vcol_shading")
col.prop(sculpt, "dyntopo_spacing")
class VIEW3D_PT_sculpt_voxel_remesh(Panel, View3DPaintPanel):
bl_context = ".sculpt_mode" # dot on purpose (access from topbar)

View File

@ -2595,7 +2595,7 @@ void BKE_brush_get_dyntopo(Brush *brush, Sculpt *sd, DynTopoSettings *out)
int inherit = out->inherit;
if (out->inherit & DYNTOPO_INHERIT_ALL) {
inherit = 0x7FFF;
inherit = 0x7FFFFFF;
}
if (inherit & DYNTOPO_INHERIT_MODE) {
@ -2621,6 +2621,10 @@ void BKE_brush_get_dyntopo(Brush *brush, Sculpt *sd, DynTopoSettings *out)
out->detail_percent = sd->detail_percent;
}
if (inherit & DYNTOPO_INHERIT_SPACING) {
out->spacing = sd->dyntopo_spacing;
}
if (inherit & DYNTOPO_INHERIT_CONSTANT_DETAIL) {
out->constant_detail = sd->constant_detail;
}

View File

@ -1913,6 +1913,11 @@ void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene)
if (!sd->detail_percent) {
sd->detail_percent = 25;
}
if (!sd->dyntopo_spacing) {
sd->dyntopo_spacing = 25;
}
if (sd->constant_detail == 0.0f) {
sd->constant_detail = 3.0f;
}

View File

@ -51,6 +51,10 @@ typedef struct CoNo {
float no[3];
} CoNo;
#include "ED_view3d.h"
#include "DNA_listBase.h"
#include "DNA_scene_types.h"
/* paint_stroke.c */
typedef bool (*StrokeGetLocation)(struct bContext *C, float location[3], const float mouse[2]);
typedef bool (*StrokeTestStart)(struct bContext *C, struct wmOperator *op, const float mouse[2]);
@ -60,6 +64,81 @@ typedef void (*StrokeUpdateStep)(struct bContext *C,
typedef void (*StrokeRedraw)(const struct bContext *C, struct PaintStroke *stroke, bool final);
typedef void (*StrokeDone)(const struct bContext *C, struct PaintStroke *stroke);
typedef struct PaintSample {
float mouse[2];
float pressure;
} PaintSample;
typedef struct PaintStroke {
void *mode_data;
void *stroke_cursor;
struct wmTimer *timer;
struct RNG *rng;
/* Cached values */
struct ViewContext vc;
struct Brush *brush;
struct UnifiedPaintSettings *ups;
/* used for lines and curves */
ListBase line;
/* Paint stroke can use up to PAINT_MAX_INPUT_SAMPLES prior inputs
* to smooth the stroke */
PaintSample samples[PAINT_MAX_INPUT_SAMPLES];
int num_samples;
int cur_sample;
int tot_samples;
float last_mouse_position[2];
float last_world_space_position[3];
bool stroke_over_mesh;
/* space distance covered so far */
float stroke_distance;
float stroke_distance_t; //divided by brush radius
/* Set whether any stroke step has yet occurred
* e.g. in sculpt mode, stroke doesn't start until cursor
* passes over the mesh */
bool stroke_started;
/* Set when enough motion was found for rake rotation */
bool rake_started;
/* event that started stroke, for modal() return */
int event_type;
/* check if stroke variables have been initialized */
bool stroke_init;
/* check if various brush mapping variables have been initialized */
bool brush_init;
float initial_mouse[2];
/* cached_pressure stores initial pressure for size pressure influence mainly */
float cached_size_pressure;
/* last pressure will store last pressure value for use in interpolation for space strokes */
float last_pressure;
int stroke_mode;
float last_tablet_event_pressure;
float zoom_2d;
int pen_flip;
/* Tilt, as read from the event. */
float x_tilt;
float y_tilt;
/* line constraint */
bool constrain_line;
float constrained_pos[2];
StrokeGetLocation get_location;
StrokeTestStart test_start;
StrokeUpdateStep update_step;
StrokeRedraw redraw;
StrokeDone done;
float spacing;
} PaintStroke;
struct PaintStroke *paint_stroke_new(struct bContext *C,
struct wmOperator *op,
StrokeGetLocation get_location,

View File

@ -67,77 +67,6 @@
# include "PIL_time_utildefines.h"
#endif
typedef struct PaintSample {
float mouse[2];
float pressure;
} PaintSample;
typedef struct PaintStroke {
void *mode_data;
void *stroke_cursor;
wmTimer *timer;
struct RNG *rng;
/* Cached values */
ViewContext vc;
Brush *brush;
UnifiedPaintSettings *ups;
/* used for lines and curves */
ListBase line;
/* Paint stroke can use up to PAINT_MAX_INPUT_SAMPLES prior inputs
* to smooth the stroke */
PaintSample samples[PAINT_MAX_INPUT_SAMPLES];
int num_samples;
int cur_sample;
int tot_samples;
float last_mouse_position[2];
float last_world_space_position[3];
bool stroke_over_mesh;
/* space distance covered so far */
float stroke_distance;
/* Set whether any stroke step has yet occurred
* e.g. in sculpt mode, stroke doesn't start until cursor
* passes over the mesh */
bool stroke_started;
/* Set when enough motion was found for rake rotation */
bool rake_started;
/* event that started stroke, for modal() return */
int event_type;
/* check if stroke variables have been initialized */
bool stroke_init;
/* check if various brush mapping variables have been initialized */
bool brush_init;
float initial_mouse[2];
/* cached_pressure stores initial pressure for size pressure influence mainly */
float cached_size_pressure;
/* last pressure will store last pressure value for use in interpolation for space strokes */
float last_pressure;
int stroke_mode;
float last_tablet_event_pressure;
float zoom_2d;
int pen_flip;
/* Tilt, as read from the event. */
float x_tilt;
float y_tilt;
/* line constraint */
bool constrain_line;
float constrained_pos[2];
StrokeGetLocation get_location;
StrokeTestStart test_start;
StrokeUpdateStep update_step;
StrokeRedraw redraw;
StrokeDone done;
} PaintStroke;
/*** Cursors ***/
static void paint_draw_smooth_cursor(bContext *C, int x, int y, void *customdata)
{
@ -430,11 +359,13 @@ static bool paint_brush_update(bContext *C,
ups->anchored_size /= 2.0f;
ups->pixel_radius /= 2.0f;
stroke->stroke_distance = ups->pixel_radius;
stroke->stroke_distance_t = 1.0f;
}
else {
copy_v2_v2(ups->anchored_initial_mouse, stroke->initial_mouse);
copy_v2_v2(mouse, stroke->initial_mouse);
stroke->stroke_distance = ups->pixel_radius;
stroke->stroke_distance_t = 1.0f;
}
ups->pixel_radius /= stroke->zoom_2d;
ups->draw_anchored = true;
@ -868,6 +799,8 @@ static int paint_space_stroke(bContext *C,
spacing / no_pressure_spacing);
stroke->stroke_distance += spacing / stroke->zoom_2d;
stroke->stroke_distance_t += (spacing / stroke->zoom_2d) / stroke->ups->pixel_radius;
paint_brush_stroke_add_step(C, op, mouse, pressure);
length -= spacing;
@ -1204,6 +1137,8 @@ static void paint_line_strokes_spacing(bContext *C,
length += *length_residue;
*length_residue = 0.0;
stroke->spacing = spacing;
if (length >= spacing) {
mouse[0] = stroke->last_mouse_position[0] + dmouse[0] * spacing_final;
mouse[1] = stroke->last_mouse_position[1] + dmouse[1] * spacing_final;
@ -1211,6 +1146,8 @@ static void paint_line_strokes_spacing(bContext *C,
ups->overlap_factor = paint_stroke_integrate_overlap(stroke->brush, 1.0);
stroke->stroke_distance += spacing / stroke->zoom_2d;
stroke->stroke_distance_t += (spacing / stroke->zoom_2d) / stroke->ups->pixel_radius;
paint_brush_stroke_add_step(C, op, mouse, 1.0);
length -= spacing;
@ -1426,6 +1363,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* one time stroke initialization */
if (!stroke->stroke_started) {
stroke->last_pressure = sample_average.pressure;
copy_v2_v2(stroke->last_mouse_position, sample_average.mouse);
if (paint_stroke_use_scene_spacing(br, mode)) {
stroke->stroke_over_mesh = SCULPT_stroke_get_location(
@ -1512,6 +1450,8 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
float dmouse[2];
sub_v2_v2v2(dmouse, mouse, stroke->last_mouse_position);
stroke->stroke_distance += len_v2(dmouse);
stroke->stroke_distance_t += len_v2(dmouse) / stroke->ups->pixel_radius;
paint_brush_stroke_add_step(C, op, mouse, pressure);
redraw = true;
}

View File

@ -6204,6 +6204,16 @@ static void sculpt_topology_update(Sculpt *sd,
{
SculptSession *ss = ob->sculpt;
if (paint_space_stroke_enabled(brush, PAINT_MODE_SCULPT)) {
float spacing = (float) brush->cached_dyntopo.spacing / 100.0f;
if (ss->cache->stroke_distance_t < ss->cache->last_dyntopo_t + spacing) {
return;
}
ss->cache->last_dyntopo_t = ss->cache->stroke_distance_t;
}
int n, totnode;
/* Build a list of all nodes that are potentially within the brush's area of influence. */
const bool use_original = sculpt_tool_needs_original(brush->sculpt_tool) ? true :
@ -8398,7 +8408,7 @@ static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op, const f
}
static void sculpt_stroke_update_step(bContext *C,
struct PaintStroke *UNUSED(stroke),
struct PaintStroke *stroke,
PointerRNA *itemptr)
{
UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
@ -8407,6 +8417,9 @@ static void sculpt_stroke_update_step(bContext *C,
SculptSession *ss = ob->sculpt;
const Brush *brush = BKE_paint_brush(&sd->paint);
ss->cache->stroke_distance = stroke->stroke_distance;
ss->cache->stroke_distance_t = stroke->stroke_distance_t;
BKE_brush_get_dyntopo(brush, sd, &brush->cached_dyntopo);
SCULPT_stroke_modifiers_check(C, ob, brush);

View File

@ -1092,6 +1092,9 @@ typedef struct StrokeCache {
rcti previous_r; /* previous redraw rectangle */
rcti current_r; /* current redraw rectangle */
float stroke_distance; //copy of PaintStroke->stroke_distance
float stroke_distance_t;
float last_dyntopo_t;
} StrokeCache;
/* Sculpt Filters */

View File

@ -111,7 +111,7 @@
\
.mtex = _DNA_DEFAULT_MTex, \
.mask_mtex = _DNA_DEFAULT_MTex, \
.dyntopo = {0.4f, 25.0f, 3.0f, DYNTOPO_COLLAPSE|DYNTOPO_SUBDIVIDE, DYNTOPO_DETAIL_RELATIVE, DYNTOPO_INHERIT_ALL}\
.dyntopo = {0.4f, 25.0f, 3.0f, DYNTOPO_COLLAPSE|DYNTOPO_SUBDIVIDE, DYNTOPO_DETAIL_RELATIVE, DYNTOPO_INHERIT_ALL, 25}\
}
/** \} */

View File

@ -528,7 +528,6 @@ typedef enum eBrushUVSculptTool {
SCULPT_TOOL_ELASTIC_DEFORM, \
SCULPT_TOOL_ROTATE, \
SCULPT_TOOL_THUMB, \
SCULPT_TOOL_DRAW_SHARP, \
SCULPT_TOOL_DISPLACEMENT_ERASER, \
SCULPT_TOOL_SLIDE_RELAX, \
SCULPT_TOOL_MASK) == 0)
@ -633,7 +632,8 @@ enum {
DYNTOPO_INHERIT_DETAIL_RANGE = 1<<11,
DYNTOPO_INHERIT_DETAIL_PERCENT = 1<<12,
DYNTOPO_INHERIT_MODE = 1<<13,
DYNTOPO_INHERIT_CONSTANT_DETAIL = 1<<14
DYNTOPO_INHERIT_CONSTANT_DETAIL = 1<<14,
DYNTOPO_INHERIT_SPACING = 1<<15
};
//dyntopo mode

View File

@ -155,7 +155,8 @@ typedef struct DynTopoSettings {
float detail_percent;
float constant_detail;
short flag, mode;
int inherit, _pad[1];
int inherit;
int spacing;
} DynTopoSettings;
typedef struct Brush {

View File

@ -995,7 +995,7 @@ typedef struct Sculpt {
/** Constant detail resolution (Blender unit / constant_detail). */
float constant_detail;
float detail_percent;
int _pad[1];
int dyntopo_spacing;
struct Object *gravity_object;
} Sculpt;

View File

@ -1172,6 +1172,14 @@ static void rna_def_dyntopo_settings(BlenderRNA *brna) {
"Dyntopo Settings",
"");
prop = RNA_def_property(srna, "spacing", PROP_INT, PROP_PERCENTAGE);
RNA_def_property_int_sdna(prop, NULL, "spacing");
RNA_def_property_range(prop, 1, 1000);
RNA_def_property_ui_range(prop, 1, 500, 5, -1);
RNA_def_property_ui_text(
prop, "Spacing", "Spacing between DynTopo daubs as a percentage of brush diameter");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop = RNA_def_property(srna, "subdivide", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", DYNTOPO_SUBDIVIDE);
RNA_def_property_ui_icon(prop, ICON_NONE, 0);

View File

@ -803,6 +803,14 @@ static void rna_def_sculpt(BlenderRNA *brna)
"Maximum edge length for dynamic topology sculpting (in brush percenage)");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
prop = RNA_def_property(srna, "dyntopo_spacing", PROP_INT, PROP_PERCENTAGE);
RNA_def_property_int_sdna(prop, NULL, "dyntopo_spacing");
RNA_def_property_range(prop, 1, 1000);
RNA_def_property_ui_range(prop, 1, 500, 5, -1);
RNA_def_property_ui_text(
prop, "DynTopo Spacing", "Spacing between DynTopo daubs as a percentage of brush diameter");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
prop = RNA_def_property(srna, "constant_detail_resolution", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "constant_detail");
RNA_def_property_range(prop, 0.0001, FLT_MAX);