Sculpt: move more brush settings to brush channels

This commit is contained in:
Joseph Eagar 2021-09-23 02:13:00 -07:00
parent 7e220dc3f0
commit c6a51c1259
13 changed files with 229 additions and 88 deletions

View File

@ -95,7 +95,7 @@ typedef struct BrushMappingData {
typedef struct BrushEnumDef {
int value;
const char identifier[64];
char icon[32];
char icon[32]; // don't forget when writing literals that icon here is a string, not an int!
const char name[64];
const char description[512];
} BrushEnumDef;

View File

@ -340,6 +340,12 @@ typedef struct SculptClothSimulation {
float damping;
float softbody_strength;
// cache some values here to avoid
// brush channel lookups inside of inner loops
float sim_limit;
int simulation_area_type;
float sim_falloff;
float (*acceleration)[3];
float (*pos)[3];
float (*init_pos)[3];
@ -476,6 +482,8 @@ typedef struct SculptBoundary {
float (*origin)[3];
float *radius;
} circle;
int deform_target;
} SculptBoundary;
/* Array Brush. */

View File

@ -538,7 +538,7 @@ void BKE_pbvh_bmesh_regen_node_verts(PBVH *pbvh);
void BKE_pbvh_bmesh_mark_node_regen(PBVH *pbvh, PBVHNode *node);
// now generated PBVHTris
void BKE_pbvh_bmesh_after_stroke(PBVH *pbvh);
void BKE_pbvh_bmesh_after_stroke(PBVH *pbvh, bool force_balance);
/* Update Bounding Box/Redraw and clear flags */

View File

@ -216,32 +216,28 @@ MAKE_FLOAT(multiplane_scrape_angle, "Plane Angle", "Angle between the planes of
MAKE_BOOL(use_persistent, "Persistent", "Sculpt on a persistent layer of the mesh", false)
MAKE_ENUM(cloth_deform_type, "Deformation", "Deformation type that is used in the brush", BRUSH_CLOTH_DEFORM_DRAG, _({
{BRUSH_CLOTH_DEFORM_DRAG, "DRAG", 0, "Drag", ""},
{BRUSH_CLOTH_DEFORM_PUSH, "PUSH", 0, "Push", ""},
{BRUSH_CLOTH_DEFORM_PINCH_POINT, "PINCH_POINT", 0, "Pinch Point", ""},
{BRUSH_CLOTH_DEFORM_PINCH_PERPENDICULAR,
"PINCH_PERPENDICULAR",
0,
"Pinch Perpendicular",
""},
{BRUSH_CLOTH_DEFORM_INFLATE, "INFLATE", 0, "Inflate", ""},
{BRUSH_CLOTH_DEFORM_GRAB, "GRAB", 0, "Grab", ""},
{BRUSH_CLOTH_DEFORM_EXPAND, "EXPAND", 0, "Expand", ""},
{BRUSH_CLOTH_DEFORM_SNAKE_HOOK, "SNAKE_HOOK", 0, "Snake Hook", ""},
{BRUSH_CLOTH_DEFORM_ELASTIC_DRAG, "ELASTIC", 0, "Elastic Drag", ""},
{BRUSH_CLOTH_DEFORM_DRAG, "DRAG", "NONE", "Drag", ""},
{BRUSH_CLOTH_DEFORM_PUSH, "PUSH", "NONE", "Push", ""},
{BRUSH_CLOTH_DEFORM_PINCH_POINT, "PINCH_POINT", "NONE", "Pinch Point", ""},
{BRUSH_CLOTH_DEFORM_PINCH_PERPENDICULAR, "PINCH_PERPENDICULAR", "NONE", "Pinch Perpendicular", ""},
{BRUSH_CLOTH_DEFORM_INFLATE, "INFLATE", "NONE", "Inflate", ""},
{BRUSH_CLOTH_DEFORM_GRAB, "GRAB", "NONE", "Grab", ""},
{BRUSH_CLOTH_DEFORM_EXPAND, "EXPAND", "NONE", "Expand", ""},
{BRUSH_CLOTH_DEFORM_SNAKE_HOOK, "SNAKE_HOOK", "NONE", "Snake Hook", ""},
{BRUSH_CLOTH_DEFORM_ELASTIC_DRAG, "ELASTIC", "NONE", "Elastic Drag", ""},
{-1}
}))
MAKE_ENUM(cloth_simulation_area_type, "Simulation Area", "Part of the mesh that is going to be simulated when the stroke is active", BRUSH_CLOTH_SIMULATION_AREA_LOCAL, _({
{BRUSH_CLOTH_SIMULATION_AREA_LOCAL,
"LOCAL",
0,
"NONE",
"Local",
"Simulates only a specific area around the brush limited by a fixed radius"},
{BRUSH_CLOTH_SIMULATION_AREA_GLOBAL, "GLOBAL", 0, "Global", "Simulates the entire mesh"},
{BRUSH_CLOTH_SIMULATION_AREA_GLOBAL, "GLOBAL", "NONE", "Global", "Simulates the entire mesh"},
{BRUSH_CLOTH_SIMULATION_AREA_DYNAMIC,
"DYNAMIC",
0,
"NONE",
"Dynamic",
"The active simulation area moves with the brush"},
{-1}
@ -249,8 +245,8 @@ MAKE_ENUM(cloth_simulation_area_type, "Simulation Area", "Part of the mesh that
MAKE_ENUM(cloth_force_falloff_type, "Force Falloff", "Shape used in the brush to apply force to the cloth",
BRUSH_CLOTH_FORCE_FALLOFF_RADIAL, _({
{BRUSH_CLOTH_FORCE_FALLOFF_RADIAL, "RADIAL", 0, "Radial", ""},
{BRUSH_CLOTH_FORCE_FALLOFF_PLANE, "PLANE", 0, "Plane", ""},
{BRUSH_CLOTH_FORCE_FALLOFF_RADIAL, "RADIAL", "NONE", "Radial", ""},
{BRUSH_CLOTH_FORCE_FALLOFF_PLANE, "PLANE", "NONE", "Plane", ""},
{-1}
}))
@ -262,7 +258,64 @@ MAKE_FLOAT(cloth_sim_falloff, "Simulation Falloff",
"Area to apply deformation falloff to the effects of the simulation", 0.75f, 0.0f, 1.0f)
MAKE_FLOAT(cloth_constraint_softbody_strength, "Soft Body Plasticity",
"How much the cloth preserves the original shape, acting as a soft body", 0.0f, 0.0f, 1.0f)
MAKE_BOOL(cloth_use_collision, "Enable Collision", "Collide with objects during the simulation", false)
MAKE_BOOL(use_frontface, "Use Front-Face", "Brush only affects vertexes that face the viewer", false)
MAKE_BOOL(cloth_pin_simulation_boundary, "Pin Simulation Boundary",
"Lock the position of the vertices in the simulation falloff area to avoid artifacts and "
"create a softer transition with unaffected areas", false)
MAKE_FLOAT(boundary_offset, "Boundary Origin Offset",
"Offset of the boundary origin in relation to the brush radius", 0.05f, 0.0f, 1.0f)
MAKE_ENUM(boundary_deform_type, "Deformation", "Deformation type that is used in the brush", BRUSH_BOUNDARY_DEFORM_BEND, _({
{BRUSH_BOUNDARY_DEFORM_BEND, "BEND", "NONE", "Bend", ""},
{BRUSH_BOUNDARY_DEFORM_EXPAND, "EXPAND", "NONE", "Expand", ""},
{BRUSH_BOUNDARY_DEFORM_INFLATE, "INFLATE", "NONE", "Inflate", ""},
{BRUSH_BOUNDARY_DEFORM_GRAB, "GRAB", "NONE", "Grab", ""},
{BRUSH_BOUNDARY_DEFORM_TWIST, "TWIST", "NONE", "Twist", ""},
{BRUSH_BOUNDARY_DEFORM_SMOOTH, "SMOOTH", "NONE", "Smooth", ""},
{BRUSH_BOUNDARY_DEFORM_CIRCLE, "CIRCLE", "NONE", "Circle", ""},
{-1}
}))
MAKE_ENUM(boundary_falloff_type, "Boundary Falloff", "How the brush falloff is applied across the boundary", BRUSH_BOUNDARY_FALLOFF_CONSTANT, _({
{BRUSH_BOUNDARY_FALLOFF_CONSTANT,
"CONSTANT",
"NONE",
"Constant",
"Applies the same deformation in the entire boundary"},
{BRUSH_BOUNDARY_FALLOFF_RADIUS,
"RADIUS",
"NONE",
"Brush Radius",
"Applies the deformation in a localized area limited by the brush radius"},
{BRUSH_BOUNDARY_FALLOFF_LOOP,
"LOOP",
"NONE",
"Loop",
"Applies the brush falloff in a loop pattern"},
{BRUSH_BOUNDARY_FALLOFF_LOOP_INVERT,
"LOOP_INVERT",
"NONE",
"Loop and Invert",
"Applies the falloff radius in a loop pattern, inverting the displacement direction in "
"each pattern repetition"},
{-1}
}))
MAKE_ENUM(deform_target, "Deformation Target", "How the deformation of the brush will affect the object", BRUSH_DEFORM_TARGET_GEOMETRY, _({
{BRUSH_DEFORM_TARGET_GEOMETRY,
"GEOMETRY",
"NONE",
"Geometry",
"Brush deformation displaces the vertices of the mesh"},
{BRUSH_DEFORM_TARGET_CLOTH_SIM,
"CLOTH_SIM",
"NONE",
"Cloth Simulation",
"Brush deforms the mesh by deforming the constraints of a cloth simulation"},
{-1}
}))
/* clang-format on */
#if defined(BRUSH_CHANNEL_DEFINE_TYPES) || defined(BRUSH_CHANNEL_DEFINE_EXTERNAL)

View File

@ -160,6 +160,7 @@ That includes per-brush enums and bitflags!
BrushChannelType brush_builtin_channels[] = {
#include "brush_channel_define.h"
};
/* clang-format on */
@ -270,6 +271,10 @@ static BrushSettingsMap brush_settings_map[] = {
DEF(cloth_sim_limit, cloth_sim_limit, FLOAT, FLOAT)
DEF(cloth_sim_falloff, cloth_sim_falloff, FLOAT, FLOAT)
DEF(cloth_constraint_softbody_strength, cloth_constraint_softbody_strength, FLOAT, FLOAT)
DEF(boundary_offset, boundary_offset, FLOAT, FLOAT)
DEF(boundary_deform_type, boundary_deform_type, INT, INT)
DEF(boundary_falloff_type, boundary_falloff_type, INT, INT)
DEF(deform_target, deform_target, INT, INT)
};
static const int brush_settings_map_len = ARRAY_SIZE(brush_settings_map);
@ -325,6 +330,8 @@ BrushFlagMap brush_flags_map[] = {
DEF(flag2, show_multiplane_scrape_planes_preview, BRUSH_MULTIPLANE_SCRAPE_PLANES_PREVIEW)
DEF(flag, use_persistent, BRUSH_PERSISTENT)
DEF(flag, use_frontface, BRUSH_FRONTFACE)
DEF(flag2, cloth_use_collision, BRUSH_CLOTH_USE_COLLISION)
DEF(flag2, cloth_pin_simulation_boundary, BRUSH_CLOTH_PIN_SIMULATION_BOUNDARY)
};
int brush_flags_map_len = ARRAY_SIZE(brush_flags_map);
@ -669,15 +676,23 @@ void BKE_brush_builtin_patch(Brush *brush, int tool)
ADDCH(fset_slide);
ADDCH(direction);
ADDCH(dash_ratio);
ADDCH(smooth_stroke_factor);
ADDCH(smooth_stroke_radius);
switch (tool) {
case SCULPT_TOOL_DRAW: {
case SCULPT_TOOL_DRAW:
break;
}
case SCULPT_TOOL_PAINT: {
ADDCH(color);
ADDCH(secondary_color);
ADDCH(wet_mix);
ADDCH(wet_persistence);
ADDCH(density);
ADDCH(tip_scale_x);
ADDCH(flow);
ADDCH(rate);
break;
}
case SCULPT_TOOL_SLIDE_RELAX:
@ -692,7 +707,18 @@ void BKE_brush_builtin_patch(Brush *brush, int tool)
ADDCH(cloth_force_falloff_type);
ADDCH(cloth_simulation_area_type);
ADDCH(cloth_deform_type);
ADDCH(cloth_use_collision);
ADDCH(cloth_pin_simulation_boundary);
break;
case SCULPT_TOOL_BOUNDARY:
ADDCH(boundary_offset);
ADDCH(boundary_deform_type);
ADDCH(boundary_falloff_type);
ADDCH(deform_target);
break;
case SCULPT_TOOL_POSE:
ADDCH(deform_target);
break;
}
@ -772,6 +798,20 @@ ATTR_NO_OPT void BKE_brush_channelset_ui_init(Brush *brush, int tool)
SHOWWRK(cloth_deform_type);
SHOWWRK(cloth_force_falloff_type);
SHOWWRK(cloth_simulation_area_type);
SHOWWRK(cloth_mass);
SHOWWRK(cloth_damping);
SHOWWRK(cloth_constraint_softbody_strength);
SHOWWRK(cloth_sim_limit);
SHOWWRK(cloth_sim_falloff);
SHOWWRK(cloth_constraint_softbody_strength);
SHOWWRK(cloth_use_collision);
SHOWWRK(cloth_pin_simulation_boundary);
break;
case SCULPT_TOOL_BOUNDARY:
SHOWWRK(boundary_offset);
SHOWWRK(boundary_deform_type);
SHOWWRK(boundary_falloff_type);
break;
}

View File

@ -2902,7 +2902,7 @@ static void pbvh_bmesh_balance_tree(PBVH *pbvh)
// printf("volume: %.4f overlap: %.4f ratio: %.3f\n", volume, overlap, overlap / volume);
if (overlap > volume * 0.25) {
if (overlap > volume * 0.1) {
modified = true;
// printf(" DELETE!\n");
@ -3186,7 +3186,7 @@ static void pbvh_bmesh_join_nodes(PBVH *bvh)
MEM_freeN(map);
}
void BKE_pbvh_bmesh_after_stroke(PBVH *pbvh)
void BKE_pbvh_bmesh_after_stroke(PBVH *pbvh, bool force_balance)
{
int totnode = pbvh->totnode;
@ -3198,7 +3198,7 @@ void BKE_pbvh_bmesh_after_stroke(PBVH *pbvh)
BKE_pbvh_update_bounds(pbvh, (PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateRedraw));
if (pbvh->balance_counter++ == 10) {
if (force_balance || pbvh->balance_counter++ == 10) {
pbvh_bmesh_balance_tree(pbvh);
pbvh_bmesh_check_nodes(pbvh);
pbvh->balance_counter = 0;

View File

@ -1833,8 +1833,16 @@ static void paint_cursor_draw_3d_view_brush_cursor_inactive(PaintCursorContext *
/* This functions sets its own drawing space in order to draw the simulation limits when the
* cursor is active. When used here, this cursor overlay is already in cursor space, so its
* position and normal should be set to 0. */
SCULPT_cloth_simulation_limits_draw(
pcontext->pos, brush, zero_v, zero_v, pcontext->radius, 1.0f, white, 0.25f);
SCULPT_cloth_simulation_limits_draw(pcontext->ss,
pcontext->sd,
pcontext->pos,
brush,
zero_v,
zero_v,
pcontext->radius,
1.0f,
white,
0.25f);
}
/* Layer brush height. */
@ -1918,7 +1926,9 @@ static void paint_cursor_cursor_draw_3d_view_brush_cursor_active(PaintCursorCont
if (len_v3v3(ss->cache->true_location, ss->cache->true_initial_location) >
ss->cache->radius * (1.0f + brush->cloth_sim_limit)) {
const float red[3] = {1.0f, 0.2f, 0.2f};
SCULPT_cloth_simulation_limits_draw(pcontext->pos,
SCULPT_cloth_simulation_limits_draw(pcontext->ss,
pcontext->sd,
pcontext->pos,
brush,
ss->cache->true_initial_location,
ss->cache->true_initial_normal,

View File

@ -8463,6 +8463,7 @@ void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings
SCULPT_TOOL_CLOTH,
SCULPT_TOOL_SIMPLIFY,
SCULPT_TOOL_SNAKE_HOOK,
SCULPT_TOOL_INFLATE,
SCULPT_TOOL_PAINT,
SCULPT_TOOL_SMEAR)) {
@ -11259,7 +11260,7 @@ void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType up
}
if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
BKE_pbvh_bmesh_after_stroke(ss->pbvh);
BKE_pbvh_bmesh_after_stroke(ss->pbvh, false);
#if 0
if (update_flags & SCULPT_UPDATE_COLOR) {
PBVHNode **nodes;

View File

@ -834,10 +834,8 @@ static void sculpt_boundary_edit_data_init(SculptSession *ss,
/* This functions assigns a falloff factor to each one of the SculptBoundaryEditInfo structs based
* on the brush curve and its propagation steps. The falloff goes from the boundary into the mesh.
*/
static void sculpt_boundary_falloff_factor_init(SculptSession *ss,
SculptBoundary *boundary,
Brush *brush,
const float radius)
static void sculpt_boundary_falloff_factor_init(
SculptSession *ss, Sculpt *sd, SculptBoundary *boundary, Brush *brush, const float radius)
{
const int totvert = SCULPT_vertex_count_get(ss);
BKE_curvemapping_init(brush->curve);
@ -865,7 +863,7 @@ static void sculpt_boundary_falloff_factor_init(SculptSession *ss,
float falloff_distance = 0.0f;
float direction = 1.0f;
switch (brush->boundary_falloff_type) {
switch (SCULPT_get_int(ss, boundary_falloff_type, sd, brush)) {
case BRUSH_BOUNDARY_FALLOFF_RADIUS:
falloff_distance = boundary_distance;
break;
@ -895,7 +893,8 @@ static void sculpt_boundary_falloff_factor_init(SculptSession *ss,
/* Main function to get SculptBoundary data both for brush deformation and viewport preview. Can
* return NULL if there is no boundary from the given vertex using the given radius. */
SculptBoundary *SCULPT_boundary_data_init(Object *object,
SculptBoundary *SCULPT_boundary_data_init(Sculpt *sd,
Object *object,
Brush *brush,
const SculptVertRef initial_vertex,
const float radius)
@ -929,11 +928,17 @@ SculptBoundary *SCULPT_boundary_data_init(Object *object,
SculptBoundary *boundary = MEM_callocN(sizeof(SculptBoundary) * TSTN, "Boundary edit data");
const bool init_boundary_distances = brush ? brush->boundary_falloff_type !=
BRUSH_BOUNDARY_FALLOFF_CONSTANT :
false;
boundary->deform_target = SCULPT_get_int(ss, deform_target, sd, brush);
const float boundary_radius = brush ? radius * (1.0f + brush->boundary_offset) : radius;
const bool init_boundary_distances = brush ?
SCULPT_get_int(ss, boundary_falloff_type, sd, brush) !=
BRUSH_BOUNDARY_FALLOFF_CONSTANT :
false;
const float boundary_radius = brush ?
radius *
(1.0f + SCULPT_get_float(ss, boundary_offset, sd, brush)) :
radius;
sculpt_boundary_indices_init(
object, ss, boundary, init_boundary_distances, boundary_initial_vertex, boundary_radius);
@ -1650,7 +1655,7 @@ static void do_boundary_brush_bend_task_cb_ex(void *__restrict userdata,
const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex);
float t_orig_co[3];
float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, boundary->deform_target, &vd);
sub_v3_v3v3(t_orig_co, orig_data.co, boundary->bend.pivot_positions[vd.index]);
rotate_v3_v3v3fl(target_co,
@ -1698,7 +1703,7 @@ static void do_boundary_brush_slide_task_cb_ex(void *__restrict userdata,
const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex);
float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, boundary->deform_target, &vd);
madd_v3_v3v3fl(target_co,
orig_data.co,
boundary->slide.directions[vd.index],
@ -1746,7 +1751,7 @@ static void do_boundary_brush_inflate_task_cb_ex(void *__restrict userdata,
const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex);
float normal[3];
normal_short_to_float_v3(normal, orig_data.no);
float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, boundary->deform_target, &vd);
madd_v3_v3v3fl(target_co,
orig_data.co,
normal,
@ -1790,7 +1795,7 @@ static void do_boundary_brush_grab_task_cb_ex(void *__restrict userdata,
const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex);
float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, boundary->deform_target, &vd);
madd_v3_v3v3fl(target_co,
orig_data.co,
ss->cache->grab_delta_symmetry,
@ -1842,7 +1847,7 @@ static void do_boundary_brush_twist_task_cb_ex(void *__restrict userdata,
const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex);
float t_orig_co[3];
float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, boundary->deform_target, &vd);
sub_v3_v3v3(t_orig_co, orig_data.co, boundary->twist.pivot_position);
rotate_v3_v3v3fl(target_co,
t_orig_co,
@ -1905,7 +1910,7 @@ static void do_boundary_brush_smooth_task_cb_ex(void *__restrict userdata,
const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
mul_v3_v3fl(avg, coord_accum, 1.0f / total_neighbors);
sub_v3_v3v3(disp, avg, vd.co);
float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, boundary->deform_target, &vd);
madd_v3_v3v3fl(
target_co, vd.co, disp, boundary->edit_info[vd.index].strength_factor * mask * strength);
@ -1955,7 +1960,7 @@ static void do_boundary_brush_circle_task_cb_ex(void *__restrict userdata,
float disp[3];
sub_v3_v3v3(disp, target_circle_co, vd.co);
float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, boundary->deform_target, &vd);
const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex);
madd_v3_v3v3fl(target_co,
@ -2026,8 +2031,7 @@ static void SCULPT_boundary_autosmooth(SculptSession *ss, SculptBoundary *bounda
SCULPT_neighbor_coords_average_interior(
ss, sco, vd.vertex, projection, slide_fset, bound_smooth, NULL, false);
float *co = SCULPT_brush_deform_target_vertex_co_get(
ss, ss->cache->brush->deform_target, &vd);
float *co = SCULPT_brush_deform_target_vertex_co_get(ss, boundary->deform_target, &vd);
interp_v3_v3v3(co, co, sco, strength * fac);
BKE_pbvh_node_mark_update(node);
@ -2068,8 +2072,7 @@ static void SCULPT_boundary_build_smoothco(SculptSession *ss, SculptBoundary *bo
SCULPT_neighbor_coords_average_interior(
ss, sco, vd.vertex, projection, slide_fset, bound_smooth, NULL, false);
float *co = SCULPT_brush_deform_target_vertex_co_get(
ss, ss->cache->brush->deform_target, &vd);
float *co = SCULPT_brush_deform_target_vertex_co_get(ss, boundary->deform_target, &vd);
interp_v3_v3v3(sco, sco, co, 0.25);
BKE_pbvh_node_mark_update(node);
@ -2092,7 +2095,10 @@ void SCULPT_do_boundary_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totn
SCULPT_cotangents_begin(ob, ss);
const float radius = ss->cache->radius;
const float boundary_radius = brush ? radius * (1.0f + brush->boundary_offset) : radius;
const float boundary_radius = brush ?
radius *
(1.0f + SCULPT_get_float(ss, boundary_offset, sd, brush)) :
radius;
const int symm_area = ss->cache->mirror_symmetry_pass;
if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
@ -2110,10 +2116,10 @@ void SCULPT_do_boundary_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totn
}
ss->cache->boundaries[symm_area] = SCULPT_boundary_data_init(
ob, brush, initial_vertex, ss->cache->initial_radius);
sd, ob, brush, initial_vertex, ss->cache->initial_radius);
if (ss->cache->boundaries[symm_area]) {
switch (brush->boundary_deform_type) {
switch (SCULPT_get_int(ss, boundary_deform_type, sd, brush)) {
case BRUSH_BOUNDARY_DEFORM_BEND:
sculpt_boundary_bend_data_init(ss, ss->cache->boundaries[symm_area], boundary_radius);
break;
@ -2133,7 +2139,7 @@ void SCULPT_do_boundary_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totn
}
sculpt_boundary_falloff_factor_init(
ss, ss->cache->boundaries[symm_area], brush, ss->cache->initial_radius);
ss, sd, ss->cache->boundaries[symm_area], brush, ss->cache->initial_radius);
}
if (ss->bm && ss->cache->boundaries[symm_area] &&
@ -2179,7 +2185,7 @@ void SCULPT_do_boundary_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totn
TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
switch (brush->boundary_deform_type) {
switch (SCULPT_get_int(ss, boundary_deform_type, sd, brush)) {
case BRUSH_BOUNDARY_DEFORM_BEND:
BLI_task_parallel_range(0, totnode, &data, do_boundary_brush_bend_task_cb_ex, &settings);
break;
@ -2203,7 +2209,7 @@ void SCULPT_do_boundary_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totn
break;
}
if (brush->autosmooth_factor > 0.0f) {
if (SCULPT_get_float(ss, autosmooth, sd, brush) > 0.0f) {
BKE_pbvh_update_normals(ss->pbvh, ss->subdiv_ccg);
SCULPT_boundary_autosmooth(ss, ss->cache->boundaries[symm_area]);

View File

@ -116,7 +116,8 @@ static void cloth_brush_simulation_location_get(SculptSession *ss,
return;
}
if (brush->cloth_simulation_area_type == BRUSH_CLOTH_SIMULATION_AREA_LOCAL) {
if (SCULPT_get_int(ss, cloth_simulation_area_type, NULL, brush) ==
BRUSH_CLOTH_SIMULATION_AREA_LOCAL) {
copy_v3_v3(r_location, ss->cache->initial_location);
return;
}
@ -128,14 +129,15 @@ PBVHNode **SCULPT_cloth_brush_affected_nodes_gather(SculptSession *ss,
int *r_totnode)
{
BLI_assert(ss->cache);
BLI_assert(brush->sculpt_tool == SCULPT_TOOL_CLOTH);
// BLI_assert(brush->sculpt_tool == SCULPT_TOOL_CLOTH);
PBVHNode **nodes = NULL;
switch (brush->cloth_simulation_area_type) {
switch (SCULPT_get_int(ss, cloth_simulation_area_type, NULL, brush)) {
case BRUSH_CLOTH_SIMULATION_AREA_LOCAL: {
SculptSearchSphereData data = {
.ss = ss,
.radius_squared = square_f(ss->cache->initial_radius * (1.0 + brush->cloth_sim_limit)),
.radius_squared = square_f(ss->cache->initial_radius *
(1.0 + SCULPT_get_float(ss, cloth_sim_limit, NULL, brush))),
.original = false,
.ignore_fully_ineffective = false,
.center = ss->cache->initial_location,
@ -148,7 +150,8 @@ PBVHNode **SCULPT_cloth_brush_affected_nodes_gather(SculptSession *ss,
case BRUSH_CLOTH_SIMULATION_AREA_DYNAMIC: {
SculptSearchSphereData data = {
.ss = ss,
.radius_squared = square_f(ss->cache->radius * (1.0 + brush->cloth_sim_limit)),
.radius_squared = square_f(ss->cache->radius *
(1.0 + SCULPT_get_float(ss, cloth_sim_limit, NULL, brush))),
.original = false,
.ignore_fully_ineffective = false,
.center = ss->cache->location,
@ -160,24 +163,27 @@ PBVHNode **SCULPT_cloth_brush_affected_nodes_gather(SculptSession *ss,
return nodes;
}
static float cloth_brush_simulation_falloff_get(const Brush *brush,
static float cloth_brush_simulation_falloff_get(const SculptClothSimulation *cloth_sim,
const Brush *brush,
const float radius,
const float location[3],
const float co[3])
{
if (brush->sculpt_tool != SCULPT_TOOL_CLOTH) {
/* All brushes that are not the cloth brush do not use simulation areas. */
/* All brushes that are not the cloth brush do not use simulation areas.
TODO: new command list situation may change this, investigate
*/
return 1.0f;
}
/* Global simulation does not have any falloff as the entire mesh is being simulated. */
if (brush->cloth_simulation_area_type == BRUSH_CLOTH_SIMULATION_AREA_GLOBAL) {
if (cloth_sim->simulation_area_type == BRUSH_CLOTH_SIMULATION_AREA_GLOBAL) {
return 1.0f;
}
const float distance = len_v3v3(location, co);
const float limit = radius + (radius * brush->cloth_sim_limit);
const float falloff = radius + (radius * brush->cloth_sim_limit * brush->cloth_sim_falloff);
const float limit = radius + (radius * cloth_sim->sim_limit);
const float falloff = radius + (radius * cloth_sim->sim_limit * cloth_sim->sim_falloff);
if (distance > limit) {
/* Outside the limits. */
@ -462,7 +468,7 @@ static void do_cloth_brush_build_constraints_task_cb_ex(
if (pin_simulation_boundary) {
const float sim_falloff = cloth_brush_simulation_falloff_get(
brush, ss->cache->initial_radius, ss->cache->location, vd.co);
data->cloth_sim, brush, ss->cache->initial_radius, ss->cache->location, vd.co);
/* Vertex is inside the area of the simulation without any falloff applied. */
if (sim_falloff < 1.0f) {
/* Create constraints with more strength the closer the vertex is to the simulation
@ -554,7 +560,7 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
float sim_location[3];
cloth_brush_simulation_location_get(ss, brush, sim_location);
const float sim_factor = cloth_brush_simulation_falloff_get(
brush, ss->cache->radius, sim_location, cloth_sim->init_pos[vd.index]);
cloth_sim, brush, ss->cache->radius, sim_location, cloth_sim->init_pos[vd.index]);
float current_vertex_location[3];
if (brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB) {
@ -848,9 +854,10 @@ static void do_cloth_brush_solve_simulation_task_cb_ex(
float sim_location[3];
cloth_brush_simulation_location_get(ss, brush, sim_location);
const float sim_factor =
ss->cache ? cloth_brush_simulation_falloff_get(
brush, ss->cache->radius, sim_location, cloth_sim->init_pos[vd.index]) :
1.0f;
ss->cache ?
cloth_brush_simulation_falloff_get(
cloth_sim, brush, ss->cache->radius, sim_location, cloth_sim->init_pos[vd.index]) :
1.0f;
if (sim_factor <= 0.0f) {
continue;
}
@ -956,13 +963,15 @@ static void cloth_brush_satisfy_constraints(SculptSession *ss,
cloth_brush_simulation_location_get(ss, brush, sim_location);
const float sim_factor_v1 = ss->cache ?
cloth_brush_simulation_falloff_get(brush,
cloth_brush_simulation_falloff_get(cloth_sim,
brush,
ss->cache->radius,
sim_location,
cloth_sim->init_pos[v1]) :
1.0f;
const float sim_factor_v2 = ss->cache ?
cloth_brush_simulation_falloff_get(brush,
cloth_brush_simulation_falloff_get(cloth_sim,
brush,
ss->cache->radius,
sim_location,
cloth_sim->init_pos[v2]) :
@ -1145,6 +1154,10 @@ SculptClothSimulation *SCULPT_cloth_brush_simulation_create(SculptSession *ss,
cloth_sim = MEM_callocN(sizeof(SculptClothSimulation), "cloth constraints");
cloth_sim->simulation_area_type = SCULPT_get_int(ss, cloth_simulation_area_type, NULL, NULL);
cloth_sim->sim_falloff = SCULPT_get_float(ss, cloth_sim_falloff, NULL, NULL);
cloth_sim->sim_limit = SCULPT_get_float(ss, cloth_sim_limit, NULL, NULL);
if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
cloth_sim->cd_pers_co = SCULPT_dyntopo_get_templayer(ss, CD_PROP_FLOAT3, SCULPT_LAYER_PERS_CO);
cloth_sim->cd_pers_no = SCULPT_dyntopo_get_templayer(ss, CD_PROP_FLOAT3, SCULPT_LAYER_PERS_NO);
@ -1291,7 +1304,7 @@ static void sculpt_cloth_ensure_constraints_in_simulation_area(Sculpt *sd,
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
const float radius = ss->cache->initial_radius;
const float limit = radius + (radius * brush->cloth_sim_limit);
const float limit = radius + (radius * SCULPT_get_float(ss, cloth_sim_limit, sd, brush));
float sim_location[3];
cloth_brush_simulation_location_get(ss, brush, sim_location);
SCULPT_cloth_brush_ensure_nodes_constraints(
@ -1313,15 +1326,16 @@ void SCULPT_do_cloth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
if (SCULPT_stroke_is_first_brush_step(ss->cache) || !ss->cache->cloth_sim) {
ss->cache->cloth_sim = SCULPT_cloth_brush_simulation_create(
ss,
brush->cloth_mass,
brush->cloth_damping,
brush->cloth_constraint_softbody_strength,
(brush->flag2 & BRUSH_CLOTH_USE_COLLISION),
SCULPT_get_float(ss, cloth_mass, sd, brush),
SCULPT_get_float(ss, cloth_damping, sd, brush),
SCULPT_get_float(ss, cloth_constraint_softbody_strength, sd, brush),
SCULPT_get_bool(ss, cloth_use_collision, sd, brush),
SCULPT_is_cloth_deform_brush(brush));
SCULPT_cloth_brush_simulation_init(ss, ss->cache->cloth_sim);
}
if (brush->cloth_simulation_area_type == BRUSH_CLOTH_SIMULATION_AREA_LOCAL) {
if (SCULPT_get_int(ss, cloth_simulation_area_type, sd, brush) ==
BRUSH_CLOTH_SIMULATION_AREA_LOCAL) {
/* When using simulation a fixed local simulation area, constraints are created only using
* the initial stroke position and initial radius (per symmetry pass) instead of per node.
* This allows to skip unnecessary constraints that will never be simulated, making the
@ -1376,7 +1390,9 @@ void SCULPT_cloth_simulation_free(struct SculptClothSimulation *cloth_sim)
}
/* Cursor drawing function. */
void SCULPT_cloth_simulation_limits_draw(const uint gpuattr,
void SCULPT_cloth_simulation_limits_draw(const SculptSession *ss,
const Sculpt *sd,
const uint gpuattr,
const Brush *brush,
const float location[3],
const float normal[3],
@ -1398,10 +1414,15 @@ void SCULPT_cloth_simulation_limits_draw(const uint gpuattr,
GPU_line_width(line_width);
immUniformColor3fvAlpha(outline_col, alpha * 0.5f);
imm_draw_circle_dashed_3d(
gpuattr, 0, 0, rds + (rds * brush->cloth_sim_limit * brush->cloth_sim_falloff), 320);
imm_draw_circle_dashed_3d(gpuattr,
0,
0,
rds + (rds * SCULPT_get_float(ss, cloth_sim_limit, sd, brush) *
SCULPT_get_float(ss, cloth_sim_falloff, sd, brush)),
320);
immUniformColor3fvAlpha(outline_col, alpha * 0.7f);
imm_draw_circle_wire_3d(gpuattr, 0, 0, rds + rds * brush->cloth_sim_limit, 80);
imm_draw_circle_wire_3d(
gpuattr, 0, 0, rds + rds * SCULPT_get_float(ss, cloth_sim_limit, sd, brush), 80);
GPU_matrix_pop();
}
@ -1413,7 +1434,7 @@ void SCULPT_cloth_plane_falloff_preview_draw(const uint gpuattr,
float local_mat[4][4];
copy_m4_m4(local_mat, ss->cache->stroke_local_mat);
if (ss->cache->brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB) {
if (SCULPT_get_int(ss, cloth_deform_type, NULL, ss->cache->brush) == BRUSH_CLOTH_DEFORM_GRAB) {
add_v3_v3v3(local_mat[3], ss->cache->true_location, ss->cache->grab_delta);
}

View File

@ -272,6 +272,7 @@ int SCULPT_get_int_intern(const SculptSession *ss,
const Brush *br);
#define SCULPT_get_int(ss, idname, sd, br) \
SCULPT_get_int_intern(ss, BRUSH_BUILTIN_##idname, sd, br)
#define SCULPT_get_bool(ss, idname, sd, br) SCULPT_get_int(ss, idname, sd, br)
SculptCornerType SCULPT_vertex_is_corner(const SculptSession *ss,
const SculptVertRef index,
@ -553,7 +554,9 @@ void SCULPT_cloth_brush_ensure_nodes_constraints(struct Sculpt *sd,
float initial_location[3],
const float radius);
void SCULPT_cloth_simulation_limits_draw(const uint gpuattr,
void SCULPT_cloth_simulation_limits_draw(const SculptSession *ss,
const Sculpt *sd,
const uint gpuattr,
const struct Brush *brush,
const float location[3],
const float normal[3],

View File

@ -696,7 +696,7 @@ static void sculpt_undo_bmesh_restore_generic(SculptUndoNode *unode, Object *ob,
}
if (data.balance_pbvh) {
BKE_pbvh_bmesh_after_stroke(ss->pbvh);
BKE_pbvh_bmesh_after_stroke(ss->pbvh, true);
}
pbvh_bmesh_check_nodes(ss->pbvh);

View File

@ -884,7 +884,6 @@ static void rna_def_sculpt(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flags", SCULPT_DYNTOPO_ENABLED);
RNA_def_property_ui_text(prop, "DynTopo", "Enable DynTopo remesher in dynamic topology mode.");
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Sculpt_update");
prop = RNA_def_property(srna, "detail_size", PROP_FLOAT, PROP_PIXEL);
RNA_def_property_ui_range(prop, 0.5, 40.0, 0.1, 2);