Sculpt: Scale Cloth Filter

This filter scales the mesh as it was a softbody, producing folds in the
surface. The orientation of the folds can be controlled using the filter
axis and orientation.

This is an example of a cloth filter that uses deform coordinates instead
of forces, but probably it does not make much sense to expose it to the
user in a different way and with different parameters. I'll remove
FilterCache->enabled_force_axis in a later commit and use always
enabled_axis in SCULPT_filter_zero_disabled_axis_components
for both forces and deformation filters, so this function can also be used
in the mesh filter.

Reviewed By: sergey

Differential Revision: https://developer.blender.org/D8661
This commit is contained in:
Pablo Dobarro 2020-09-18 01:17:33 +02:00
parent 8ac1ca13c8
commit 5d728d38b9
4 changed files with 82 additions and 19 deletions

View File

@ -5716,7 +5716,8 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
if (brush->deform_target == BRUSH_DEFORM_TARGET_CLOTH_SIM) {
if (!ss->cache->cloth_sim) {
ss->cache->cloth_sim = SCULPT_cloth_brush_simulation_create(ss, brush, 1.0f, 0.0f, false);
ss->cache->cloth_sim = SCULPT_cloth_brush_simulation_create(
ss, brush, 1.0f, 0.0f, false, true);
SCULPT_cloth_brush_simulation_init(ss, ss->cache->cloth_sim);
SCULPT_cloth_brush_build_nodes_constraints(
sd, ob, nodes, totnode, ss->cache->cloth_sim, ss->cache->location, FLT_MAX);

View File

@ -876,7 +876,8 @@ SculptClothSimulation *SCULPT_cloth_brush_simulation_create(SculptSession *ss,
Brush *brush,
const float cloth_mass,
const float cloth_damping,
const bool use_collisions)
const bool use_collisions,
const bool needs_deform_coords)
{
const int totverts = SCULPT_vertex_count_get(ss);
SculptClothSimulation *cloth_sim;
@ -898,9 +899,7 @@ SculptClothSimulation *SCULPT_cloth_brush_simulation_create(SculptSession *ss,
cloth_sim->length_constraint_tweak = MEM_calloc_arrayN(
totverts, sizeof(float), "cloth sim length tweak");
/* Brush can be NULL for tools that need the solver but don't rely on constraint to deformation
* positions. */
if (brush && SCULPT_is_cloth_deform_brush(brush)) {
if (needs_deform_coords) {
cloth_sim->deformation_pos = MEM_calloc_arrayN(
totverts, sizeof(float[3]), "cloth sim deformation positions");
cloth_sim->deformation_strength = MEM_calloc_arrayN(
@ -997,7 +996,8 @@ void SCULPT_do_cloth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
brush,
brush->cloth_mass,
brush->cloth_damping,
(brush->flag2 & BRUSH_CLOTH_USE_COLLISION));
(brush->flag2 & BRUSH_CLOTH_USE_COLLISION),
SCULPT_is_cloth_deform_brush(brush));
SCULPT_cloth_brush_simulation_init(ss, ss->cache->cloth_sim);
}
@ -1106,6 +1106,7 @@ typedef enum eSculpClothFilterType {
CLOTH_FILTER_INFLATE,
CLOTH_FILTER_EXPAND,
CLOTH_FILTER_PINCH,
CLOTH_FILTER_SCALE,
} eSculptClothFilterType;
static EnumPropertyItem prop_cloth_filter_type[] = {
@ -1113,6 +1114,11 @@ static EnumPropertyItem prop_cloth_filter_type[] = {
{CLOTH_FILTER_INFLATE, "INFLATE", 0, "Inflate", "Inflates the cloth"},
{CLOTH_FILTER_EXPAND, "EXPAND", 0, "Expand", "Expands the cloth's dimensions"},
{CLOTH_FILTER_PINCH, "PINCH", 0, "Pinch", "Pulls the cloth to the cursor's start position"},
{CLOTH_FILTER_SCALE,
"SCALE",
0,
"Scale",
"Scales the mesh as a softbody using the origin of the object as scale"},
{0, NULL, 0, NULL, NULL},
};
@ -1148,6 +1154,35 @@ static EnumPropertyItem prop_cloth_filter_force_axis_items[] = {
{0, NULL, 0, NULL, NULL},
};
static bool cloth_filter_is_deformation_filter(eSculptClothFilterType filter_type)
{
return ELEM(filter_type, CLOTH_FILTER_SCALE);
}
static void cloth_filter_apply_displacement_to_deform_co(const int v_index,
const float disp[3],
FilterCache *filter_cache)
{
float final_disp[3];
copy_v3_v3(final_disp, disp);
SCULPT_filter_zero_disabled_axis_components(final_disp, filter_cache);
add_v3_v3v3(filter_cache->cloth_sim->deformation_pos[v_index],
filter_cache->cloth_sim->init_pos[v_index],
final_disp);
}
static void cloth_filter_apply_forces_to_vertices(const int v_index,
const float force[3],
const float gravity[3],
FilterCache *filter_cache)
{
float final_force[3];
copy_v3_v3(final_force, force);
SCULPT_filter_zero_disabled_axis_components(final_force, filter_cache);
add_v3_v3(final_force, gravity);
cloth_brush_apply_force_to_vertex(NULL, filter_cache->cloth_sim, final_force, v_index);
}
static void cloth_filter_apply_forces_task_cb(void *__restrict userdata,
const int i,
const TaskParallelTLS *__restrict UNUSED(tls))
@ -1158,7 +1193,9 @@ static void cloth_filter_apply_forces_task_cb(void *__restrict userdata,
PBVHNode *node = data->nodes[i];
SculptClothSimulation *cloth_sim = ss->filter_cache->cloth_sim;
const int filter_type = data->filter_type;
const eSculptClothFilterType filter_type = data->filter_type;
const bool is_deformation_filter = cloth_filter_is_deformation_filter(filter_type);
float sculpt_gravity[3] = {0.0f};
if (sd->gravity_object) {
@ -1175,6 +1212,7 @@ static void cloth_filter_apply_forces_task_cb(void *__restrict userdata,
float fade = vd.mask ? *vd.mask : 0.0f;
fade = 1.0f - fade;
float force[3] = {0.0f, 0.0f, 0.0f};
float disp[3], temp[3], transform[3][3];
if (ss->filter_cache->active_face_set != SCULPT_FACE_SET_NONE) {
if (!SCULPT_vertex_has_face_set(ss, vd.index, ss->filter_cache->active_face_set)) {
@ -1207,20 +1245,24 @@ static void cloth_filter_apply_forces_task_cb(void *__restrict userdata,
sub_v3_v3v3(force, ss->filter_cache->cloth_sim_pinch_point, vd.co);
normalize_v3(force);
mul_v3_fl(force, fade * data->filter_strength);
break;
case CLOTH_FILTER_SCALE:
unit_m3(transform);
scale_m3_fl(transform, 1.0f + (fade * data->filter_strength));
copy_v3_v3(temp, cloth_sim->init_pos[vd.index]);
mul_m3_v3(transform, temp);
sub_v3_v3v3(disp, temp, cloth_sim->init_pos[vd.index]);
zero_v3(force);
break;
}
SCULPT_filter_to_orientation_space(force, ss->filter_cache);
for (int axis = 0; axis < 3; axis++) {
if (!ss->filter_cache->enabled_force_axis[axis]) {
force[axis] = 0.0f;
}
if (is_deformation_filter) {
cloth_filter_apply_displacement_to_deform_co(vd.index, disp, ss->filter_cache);
}
else {
cloth_filter_apply_forces_to_vertices(vd.index, force, sculpt_gravity, ss->filter_cache);
}
SCULPT_filter_to_object_space(force, ss->filter_cache);
add_v3_v3(force, sculpt_gravity);
cloth_brush_apply_force_to_vertex(ss, cloth_sim, force, vd.index);
}
BKE_pbvh_vertex_iter_end;
@ -1291,6 +1333,8 @@ static int sculpt_cloth_filter_invoke(bContext *C, wmOperator *op, const wmEvent
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
SculptSession *ss = ob->sculpt;
const eSculptClothFilterType filter_type = RNA_enum_get(op->ptr, "type");
/* Update the active vertex */
float mouse[2];
SculptCursorGeometryInfo sgi;
@ -1310,7 +1354,12 @@ static int sculpt_cloth_filter_invoke(bContext *C, wmOperator *op, const wmEvent
const float cloth_damping = RNA_float_get(op->ptr, "cloth_damping");
const bool use_collisions = RNA_boolean_get(op->ptr, "use_collisions");
ss->filter_cache->cloth_sim = SCULPT_cloth_brush_simulation_create(
ss, NULL, cloth_mass, cloth_damping, use_collisions);
ss,
NULL,
cloth_mass,
cloth_damping,
use_collisions,
cloth_filter_is_deformation_filter(filter_type));
copy_v3_v3(ss->filter_cache->cloth_sim_pinch_point, SCULPT_active_vertex_co_get(ss));

View File

@ -97,6 +97,17 @@ void SCULPT_filter_to_object_space(float r_v[3], struct FilterCache *filter_cach
}
}
void SCULPT_filter_zero_disabled_axis_components(float r_v[3], struct FilterCache *filter_cache)
{
SCULPT_filter_to_orientation_space(r_v, filter_cache);
for (int axis = 0; axis < 3; axis++) {
if (!filter_cache->enabled_force_axis[axis]) {
r_v[axis] = 0.0f;
}
}
SCULPT_filter_to_object_space(r_v, filter_cache);
}
static void filter_cache_init_task_cb(void *__restrict userdata,
const int i,
const TaskParallelTLS *__restrict UNUSED(tls))

View File

@ -366,7 +366,8 @@ struct SculptClothSimulation *SCULPT_cloth_brush_simulation_create(struct Sculpt
struct Brush *brush,
const float cloth_mass,
const float cloth_damping,
const bool use_collisions);
const bool use_collisions,
const bool needs_deform_coords);
void SCULPT_cloth_brush_simulation_init(struct SculptSession *ss,
struct SculptClothSimulation *cloth_sim);
void SCULPT_cloth_brush_store_simulation_state(struct SculptSession *ss,
@ -971,6 +972,7 @@ typedef enum SculptFilterOrientation {
void SCULPT_filter_to_orientation_space(float r_v[3], struct FilterCache *filter_cache);
void SCULPT_filter_to_object_space(float r_v[3], struct FilterCache *filter_cache);
void SCULPT_filter_zero_disabled_axis_components(float r_v[3], struct FilterCache *filter_cache);
typedef struct FilterCache {
bool enabled_axis[3];