diff options
author | Alexander Gavrilov <angavrilov@gmail.com> | 2021-01-06 14:48:42 +0300 |
---|---|---|
committer | Alexander Gavrilov <angavrilov@gmail.com> | 2021-01-08 12:24:50 +0300 |
commit | 4a0b8c9427b57422f47c125a494c4631a6c0bfd1 (patch) | |
tree | e99c8bbffcf978319c78f7342006946878736e30 /source | |
parent | 8877e294dfd680f0ad9c1598b6462dd726cc46f3 (diff) |
Cloth: completely exclude fully pinned triangles from collision.
Currently such triangles are effectively already excluded, because
the calculated forces are not applied to pinned vertices. However
these forces are still being computed, which is inefficient.
This adds an early check for triangles where all vertices are
pinned during BVH overlap detection, which significantly speeds
up certain use cases with big fully pinned areas that happen to
overlap a collider. In case of self collision both triangles must
be fully pinned to exclude safely, because the computation is
symmetric and handles two triangles at the same time.
Differential Revision: https://developer.blender.org/D10041
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/blenkernel/intern/collision.c | 75 |
1 files changed, 57 insertions, 18 deletions
diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c index 72525272254..068216e3159 100644 --- a/source/blender/blenkernel/intern/collision.c +++ b/source/blender/blenkernel/intern/collision.c @@ -1002,6 +1002,23 @@ static int cloth_selfcollision_response_static(ClothModifierData *clmd, # pragma GCC diagnostic pop #endif +static bool cloth_bvh_collision_is_active(const ClothModifierData *UNUSED(clmd), + const Cloth *cloth, + const MVertTri *tri_a) +{ + const ClothVertex *verts = cloth->verts; + + /* Fully pinned triangles don't need collision processing. */ + const int flags_a = verts[tri_a->tri[0]].flags & verts[tri_a->tri[1]].flags & + verts[tri_a->tri[2]].flags; + + if (flags_a & CLOTH_VERT_FLAG_PINNED) { + return false; + } + + return true; +} + static void cloth_collision(void *__restrict userdata, const int index, const TaskParallelTLS *__restrict UNUSED(tls)) @@ -1059,13 +1076,31 @@ static void cloth_collision(void *__restrict userdata, } } -static bool cloth_bvh_selfcollision_is_active(const Cloth *cloth, +static bool cloth_bvh_selfcollision_is_active(const ClothModifierData *clmd, + const Cloth *cloth, const MVertTri *tri_a, - const MVertTri *tri_b, - bool sewing_active) + const MVertTri *tri_b) { const ClothVertex *verts = cloth->verts; + + /* Skip when either triangle is excluded. */ + const int flags_a = verts[tri_a->tri[0]].flags & verts[tri_a->tri[1]].flags & + verts[tri_a->tri[2]].flags; + const int flags_b = verts[tri_b->tri[0]].flags & verts[tri_b->tri[1]].flags & + verts[tri_b->tri[2]].flags; + + if ((flags_a | flags_b) & CLOTH_VERT_FLAG_NOSELFCOLL) { + return false; + } + + /* Skip when both triangles are pinned. */ + if ((flags_a & flags_b) & CLOTH_VERT_FLAG_PINNED) { + return false; + } + /* Ignore overlap of neighboring triangles and triangles connected by a sewing edge. */ + bool sewing_active = (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SEW); + for (uint i = 0; i < 3; i++) { for (uint j = 0; j < 3; j++) { if (tri_a->tri[i] == tri_b->tri[j]) { @@ -1080,12 +1115,6 @@ static bool cloth_bvh_selfcollision_is_active(const Cloth *cloth, } } - if (((verts[tri_a->tri[0]].flags & verts[tri_a->tri[1]].flags & verts[tri_a->tri[2]].flags) | - (verts[tri_b->tri[0]].flags & verts[tri_b->tri[1]].flags & verts[tri_b->tri[2]].flags)) & - CLOTH_VERT_FLAG_NOSELFCOLL) { - return false; - } - return true; } @@ -1106,10 +1135,7 @@ static void cloth_selfcollision(void *__restrict userdata, tri_a = &clmd->clothObject->tri[data->overlap[index].indexA]; tri_b = &clmd->clothObject->tri[data->overlap[index].indexB]; -#ifdef DEBUG - bool sewing_active = (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SEW); - BLI_assert(cloth_bvh_selfcollision_is_active(clmd->clothObject, tri_a, tri_b, sewing_active)); -#endif + BLI_assert(cloth_bvh_selfcollision_is_active(clmd, clmd->clothObject, tri_a, tri_b)); /* Compute distance and normal. */ distance = compute_collision_point_tri_tri(verts1[tri_a->tri[0]].tx, @@ -1508,6 +1534,18 @@ static int cloth_bvh_selfcollisions_resolve(ClothModifierData *clmd, return ret; } +static bool cloth_bvh_obj_overlap_cb(void *userdata, + int index_a, + int UNUSED(index_b), + int UNUSED(thread)) +{ + ClothModifierData *clmd = (ClothModifierData *)userdata; + struct Cloth *clothObject = clmd->clothObject; + const MVertTri *tri_a = &clothObject->tri[index_a]; + + return cloth_bvh_collision_is_active(clmd, clothObject, tri_a); +} + static bool cloth_bvh_self_overlap_cb(void *userdata, int index_a, int index_b, int UNUSED(thread)) { /* No need for equal combinations (eg. (0,1) & (1,0)). */ @@ -1518,9 +1556,7 @@ static bool cloth_bvh_self_overlap_cb(void *userdata, int index_a, int index_b, tri_a = &clothObject->tri[index_a]; tri_b = &clothObject->tri[index_b]; - bool sewing_active = (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SEW); - - if (cloth_bvh_selfcollision_is_active(clothObject, tri_a, tri_b, sewing_active)) { + if (cloth_bvh_selfcollision_is_active(clmd, clothObject, tri_a, tri_b)) { return true; } } @@ -1578,8 +1614,11 @@ int cloth_bvh_collision( /* Move object to position (step) in time. */ collision_move_object(collmd, step + dt, step, false); - overlap_obj[i] = BLI_bvhtree_overlap( - cloth_bvh, collmd->bvhtree, &coll_counts_obj[i], NULL, NULL); + overlap_obj[i] = BLI_bvhtree_overlap(cloth_bvh, + collmd->bvhtree, + &coll_counts_obj[i], + is_hair ? NULL : cloth_bvh_obj_overlap_cb, + clmd); } } } |