Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--release/scripts/startup/bl_ui/properties_paint_common.py2
-rw-r--r--release/scripts/startup/bl_ui/space_toolsystem_toolbar.py1
-rw-r--r--source/blender/blenkernel/BKE_paint.h6
-rw-r--r--source/blender/blenkernel/intern/paint.c2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_cloth.c170
-rw-r--r--source/blender/makesdna/DNA_brush_types.h1
-rw-r--r--source/blender/makesrna/intern/rna_brush.c6
7 files changed, 179 insertions, 9 deletions
diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py
index d2b02c4c40b..8afd47f5da6 100644
--- a/release/scripts/startup/bl_ui/properties_paint_common.py
+++ b/release/scripts/startup/bl_ui/properties_paint_common.py
@@ -667,6 +667,8 @@ def brush_settings(layout, context, brush, popover=False):
layout.prop(brush, "cloth_damping")
layout.prop(brush, "cloth_constraint_softbody_strength")
layout.separator()
+ layout.prop(brush, "use_cloth_collisions")
+ layout.separator()
elif sculpt_tool == 'SCRAPE':
row = layout.row()
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
index c9fb89ffad9..00ae884eeb9 100644
--- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
@@ -1278,6 +1278,7 @@ class _defs_sculpt:
layout.prop(props, "cloth_mass")
layout.prop(props, "cloth_damping")
layout.prop(props, "use_face_sets")
+ layout.prop(props, "use_collisions")
return dict(
idname="builtin.cloth_filter",
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index e2b8a4d72e6..d5b09cff293 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -42,6 +42,7 @@ struct EdgeSet;
struct GHash;
struct GridPaintMask;
struct ImagePool;
+struct ListBase;
struct MLoop;
struct MLoopTri;
struct MVert;
@@ -295,7 +296,9 @@ typedef struct SculptClothSimulation {
float (*pos)[3];
float (*init_pos)[3];
float (*prev_pos)[3];
+ float (*last_iteration_pos)[3];
+ struct ListBase *collider_list;
} SculptClothSimulation;
typedef struct SculptPersistentBase {
@@ -333,6 +336,9 @@ typedef struct SculptSession {
int level;
} multires;
+ /* Depsgraph for the Cloth Brush solver to get the colliders. */
+ struct Depsgraph *depsgraph;
+
/* These are always assigned to base mesh data when using PBVH_FACES and PBVH_GRIDS. */
struct MVert *mvert;
struct MPoly *mpoly;
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 15d5b0cbf53..e7ff53f27b6 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -1493,6 +1493,8 @@ static void sculpt_update_object(Depsgraph *depsgraph,
MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
const bool use_face_sets = (ob->mode & OB_MODE_SCULPT) != 0;
+ ss->depsgraph = depsgraph;
+
ss->deform_modifiers_active = sculpt_modifiers_active(scene, sd, ob);
ss->show_mask = (sd->flags & SCULPT_HIDE_MASK) == 0;
ss->show_face_sets = (sd->flags & SCULPT_HIDE_FACE_SETS) == 0;
diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c
index 51b2d50e73b..c6feef0808c 100644
--- a/source/blender/editors/sculpt_paint/sculpt_cloth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c
@@ -43,7 +43,9 @@
#include "DNA_scene_types.h"
#include "BKE_brush.h"
+#include "BKE_bvhutils.h"
#include "BKE_ccg.h"
+#include "BKE_collision.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_image.h"
@@ -69,6 +71,7 @@
#include "BKE_subsurf.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "WM_api.h"
#include "WM_message.h"
@@ -468,10 +471,36 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
BKE_pbvh_vertex_iter_end;
}
+static ListBase *cloth_brush_collider_cache_create(Depsgraph *depsgraph)
+{
+ ListBase *cache = NULL;
+ DEG_OBJECT_ITER_BEGIN (depsgraph,
+ ob,
+ DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | DEG_ITER_OBJECT_FLAG_VISIBLE |
+ DEG_ITER_OBJECT_FLAG_DUPLI) {
+ CollisionModifierData *cmd = (CollisionModifierData *)BKE_modifiers_findby_type(
+ ob, eModifierType_Collision);
+ if (cmd && cmd->bvhtree) {
+ if (cache == NULL) {
+ cache = MEM_callocN(sizeof(ListBase), "ColliderCache array");
+ }
+
+ ColliderCache *col = MEM_callocN(sizeof(ColliderCache), "ColliderCache");
+ col->ob = ob;
+ col->collmd = cmd;
+ collision_move_object(cmd, 1.0, 0.0, true);
+ BLI_addtail(cache, col);
+ }
+ }
+ DEG_OBJECT_ITER_END;
+ return cache;
+}
+
static SculptClothSimulation *cloth_brush_simulation_create(SculptSession *ss,
Brush *brush,
const float cloth_mass,
- const float cloth_damping)
+ const float cloth_damping,
+ const bool use_collisions)
{
const int totverts = SCULPT_vertex_count_get(ss);
SculptClothSimulation *cloth_sim;
@@ -487,6 +516,8 @@ static SculptClothSimulation *cloth_brush_simulation_create(SculptSession *ss,
totverts, 3 * sizeof(float), "cloth sim acceleration");
cloth_sim->pos = MEM_calloc_arrayN(totverts, 3 * sizeof(float), "cloth sim pos");
cloth_sim->prev_pos = MEM_calloc_arrayN(totverts, 3 * sizeof(float), "cloth sim prev pos");
+ cloth_sim->last_iteration_pos = MEM_calloc_arrayN(
+ totverts, sizeof(float) * 3, "cloth sim last iteration pos");
cloth_sim->init_pos = MEM_calloc_arrayN(totverts, 3 * sizeof(float), "cloth sim init pos");
cloth_sim->length_constraint_tweak = MEM_calloc_arrayN(
totverts, sizeof(float), "cloth sim length tweak");
@@ -501,9 +532,110 @@ static SculptClothSimulation *cloth_brush_simulation_create(SculptSession *ss,
cloth_sim->mass = cloth_mass;
cloth_sim->damping = cloth_damping;
+ if (use_collisions) {
+ cloth_sim->collider_list = cloth_brush_collider_cache_create(ss->depsgraph);
+ }
+
return cloth_sim;
}
+typedef struct ClothBrushCollision {
+ CollisionModifierData *col_data;
+ struct IsectRayPrecalc isect_precalc;
+} ClothBrushCollision;
+
+static void cloth_brush_collision_cb(void *userdata,
+ int index,
+ const BVHTreeRay *ray,
+ BVHTreeRayHit *hit)
+{
+ ClothBrushCollision *col = (ClothBrushCollision *)userdata;
+ CollisionModifierData *col_data = col->col_data;
+ MVertTri *verttri = &col_data->tri[index];
+ MVert *mverts = col_data->x;
+ float *tri[3], no[3], co[3];
+
+ tri[0] = mverts[verttri->tri[0]].co;
+ tri[1] = mverts[verttri->tri[1]].co;
+ tri[2] = mverts[verttri->tri[2]].co;
+ float dist = 0.0f;
+
+ bool tri_hit = isect_ray_tri_watertight_v3(
+ ray->origin, &col->isect_precalc, UNPACK3(tri), &dist, NULL);
+ normal_tri_v3(no, UNPACK3(tri));
+ madd_v3_v3v3fl(co, ray->origin, ray->direction, dist);
+
+ if (tri_hit && dist < hit->dist) {
+ hit->index = index;
+ hit->dist = dist;
+
+ copy_v3_v3(hit->co, co);
+ copy_v3_v3(hit->no, no);
+ }
+}
+
+static void cloth_brush_solve_collision(Object *object,
+ SculptClothSimulation *cloth_sim,
+ const int i)
+{
+ const int raycast_flag = BVH_RAYCAST_DEFAULT & ~(BVH_RAYCAST_WATERTIGHT);
+
+ ColliderCache *collider_cache;
+ BVHTreeRayHit hit;
+
+ float obmat_inv[4][4];
+ invert_m4_m4(obmat_inv, object->obmat);
+
+ for (collider_cache = cloth_sim->collider_list->first; collider_cache;
+ collider_cache = collider_cache->next) {
+ float ray_start[3], ray_normal[3];
+ float pos_world_space[3], prev_pos_world_space[3];
+
+ mul_v3_m4v3(pos_world_space, object->obmat, cloth_sim->pos[i]);
+ mul_v3_m4v3(prev_pos_world_space, object->obmat, cloth_sim->last_iteration_pos[i]);
+ sub_v3_v3v3(ray_normal, pos_world_space, prev_pos_world_space);
+ copy_v3_v3(ray_start, prev_pos_world_space);
+ hit.index = -1;
+ hit.dist = len_v3(ray_normal);
+ normalize_v3(ray_normal);
+
+ ClothBrushCollision col;
+ CollisionModifierData *collmd = collider_cache->collmd;
+ col.col_data = collmd;
+ isect_ray_tri_watertight_v3_precalc(&col.isect_precalc, ray_normal);
+
+ BLI_bvhtree_ray_cast_ex(collmd->bvhtree,
+ ray_start,
+ ray_normal,
+ 0.3f,
+ &hit,
+ cloth_brush_collision_cb,
+ &col,
+ raycast_flag);
+
+ if (hit.index != -1) {
+
+ float collision_disp[3];
+ float movement_disp[3];
+ mul_v3_v3fl(collision_disp, hit.no, 0.005f);
+ sub_v3_v3v3(movement_disp, pos_world_space, prev_pos_world_space);
+ float friction_plane[4];
+ float pos_on_friction_plane[3];
+ plane_from_point_normal_v3(friction_plane, hit.co, hit.no);
+ closest_to_plane_v3(pos_on_friction_plane, friction_plane, pos_world_space);
+ sub_v3_v3v3(movement_disp, pos_on_friction_plane, hit.co);
+
+ /* TODO(pablodp606): This can be exposed in a brush/filter property as friction. */
+ mul_v3_fl(movement_disp, 0.35f);
+
+ copy_v3_v3(cloth_sim->pos[i], hit.co);
+ add_v3_v3(cloth_sim->pos[i], movement_disp);
+ add_v3_v3(cloth_sim->pos[i], collision_disp);
+ mul_v3_m4v3(cloth_sim->pos[i], obmat_inv, cloth_sim->pos[i]);
+ }
+ }
+}
+
static void do_cloth_brush_solve_simulation_task_cb_ex(
void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
{
@@ -534,14 +666,22 @@ static void do_cloth_brush_solve_simulation_task_cb_ex(
const float mask_v = (1.0f - (vd.mask ? *vd.mask : 0.0f)) *
SCULPT_automasking_factor_get(ss, vd.index);
+
madd_v3_v3fl(cloth_sim->pos[i], pos_diff, mask_v);
madd_v3_v3fl(cloth_sim->pos[i], cloth_sim->acceleration[i], mask_v);
- copy_v3_v3(cloth_sim->prev_pos[i], temp);
+ if (cloth_sim->collider_list != NULL) {
+ cloth_brush_solve_collision(data->ob, cloth_sim, i);
+ }
+ copy_v3_v3(cloth_sim->last_iteration_pos[i], cloth_sim->pos[i]);
+
+ copy_v3_v3(cloth_sim->prev_pos[i], temp);
+ copy_v3_v3(cloth_sim->last_iteration_pos[i], cloth_sim->pos[i]);
copy_v3_fl(cloth_sim->acceleration[i], 0.0f);
copy_v3_v3(vd.co, cloth_sim->pos[vd.index]);
+
if (vd.mvert) {
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
@@ -765,14 +905,13 @@ void SCULPT_do_cloth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
/* The simulation structure only needs to be created on the first symmetry pass. */
if (SCULPT_stroke_is_first_brush_step(ss->cache) || !ss->cache->cloth_sim) {
- ss->cache->cloth_sim = cloth_brush_simulation_create(
- ss, brush, brush->cloth_mass, brush->cloth_damping);
-
const bool is_cloth_deform_brush = SCULPT_is_cloth_deform_brush(brush);
-
+ ss->cache->cloth_sim = cloth_brush_simulation_create(
+ ss, brush, brush->cloth_mass, brush->cloth_damping, brush->flag2 & BRUSH_CLOTH_USE_COLLISIONS);
for (int i = 0; i < totverts; i++) {
- copy_v3_v3(ss->cache->cloth_sim->prev_pos[i], SCULPT_vertex_co_get(ss, i));
+ copy_v3_v3(ss->cache->cloth_sim->last_iteration_pos[i], SCULPT_vertex_co_get(ss, i));
copy_v3_v3(ss->cache->cloth_sim->init_pos[i], SCULPT_vertex_co_get(ss, i));
+ copy_v3_v3(ss->cache->cloth_sim->prev_pos[i], SCULPT_vertex_co_get(ss, i));
if (is_cloth_deform_brush) {
copy_v3_v3(ss->cache->cloth_sim->deformation_pos[i], SCULPT_vertex_co_get(ss, i));
}
@@ -803,12 +942,16 @@ void SCULPT_do_cloth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
void SCULPT_cloth_simulation_free(struct SculptClothSimulation *cloth_sim)
{
MEM_SAFE_FREE(cloth_sim->pos);
+ MEM_SAFE_FREE(cloth_sim->last_iteration_pos);
MEM_SAFE_FREE(cloth_sim->prev_pos);
MEM_SAFE_FREE(cloth_sim->acceleration);
MEM_SAFE_FREE(cloth_sim->length_constraints);
MEM_SAFE_FREE(cloth_sim->length_constraint_tweak);
MEM_SAFE_FREE(cloth_sim->deformation_pos);
MEM_SAFE_FREE(cloth_sim->init_pos);
+ if (cloth_sim->collider_list) {
+ BKE_collider_cache_free(&cloth_sim->collider_list);
+ }
MEM_SAFE_FREE(cloth_sim);
}
@@ -985,6 +1128,7 @@ static int sculpt_cloth_filter_modal(bContext *C, wmOperator *op, const wmEvent
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
const int totverts = SCULPT_vertex_count_get(ss);
+
for (int i = 0; i < totverts; i++) {
copy_v3_v3(ss->filter_cache->cloth_sim->pos[i], SCULPT_vertex_co_get(ss, i));
}
@@ -1016,7 +1160,7 @@ static int sculpt_cloth_filter_modal(bContext *C, wmOperator *op, const wmEvent
static int sculpt_cloth_filter_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Object *ob = CTX_data_active_object(C);
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
SculptSession *ss = ob->sculpt;
@@ -1037,11 +1181,14 @@ static int sculpt_cloth_filter_invoke(bContext *C, wmOperator *op, const wmEvent
const float cloth_mass = RNA_float_get(op->ptr, "cloth_mass");
const float cloth_damping = RNA_float_get(op->ptr, "cloth_damping");
- ss->filter_cache->cloth_sim = cloth_brush_simulation_create(ss, NULL, cloth_mass, cloth_damping);
+ const bool use_collisions = RNA_boolean_get(op->ptr, "use_collisions");
+ ss->filter_cache->cloth_sim = cloth_brush_simulation_create(ss, NULL, cloth_mass, cloth_damping, use_collisions);
+
copy_v3_v3(ss->filter_cache->cloth_sim_pinch_point, SCULPT_active_vertex_co_get(ss));
const int totverts = SCULPT_vertex_count_get(ss);
for (int i = 0; i < totverts; i++) {
+ copy_v3_v3(ss->filter_cache->cloth_sim->last_iteration_pos[i], SCULPT_vertex_co_get(ss, i));
copy_v3_v3(ss->filter_cache->cloth_sim->prev_pos[i], SCULPT_vertex_co_get(ss, i));
copy_v3_v3(ss->filter_cache->cloth_sim->init_pos[i], SCULPT_vertex_co_get(ss, i));
}
@@ -1113,4 +1260,9 @@ void SCULPT_OT_cloth_filter(struct wmOperatorType *ot)
false,
"Use Face Sets",
"Apply the filter only to the Face Set under the cursor");
+ ot->prop = RNA_def_boolean(ot->srna,
+ "use_collisions",
+ false,
+ "Use Collisions",
+ "Collide with other collider objects in the scene");
}
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index 5cd7443900f..72f205685b9 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -740,6 +740,7 @@ typedef enum eBrushFlags2 {
BRUSH_USE_CONNECTED_ONLY = (1 << 3),
BRUSH_CLOTH_PIN_SIMULATION_BOUNDARY = (1 << 4),
BRUSH_POSE_USE_LOCK_ROTATION = (1 << 5),
+ BRUSH_CLOTH_USE_COLLISIONS = (1 << 6),
} eBrushFlags2;
typedef enum {
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 87a85215208..ccd2919ab98 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -2824,6 +2824,12 @@ static void rna_def_brush(BlenderRNA *brna)
"create a softer transitionwith with unnafected areas");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop = RNA_def_property(srna, "use_cloth_collisions", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag2", BRUSH_CLOTH_USE_COLLISIONS);
+ RNA_def_property_ui_text(
+ prop, "Enable Collisions", "Collide with objects during the simulation");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop = RNA_def_property(srna, "invert_to_scrape_fill", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_INVERT_TO_SCRAPE_FILL);
RNA_def_property_ui_text(prop,