diff options
-rw-r--r-- | source/blender/blenkernel/BKE_cloth.h | 20 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/cloth.c | 118 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/collision.c | 673 | ||||
-rw-r--r-- | source/blender/physics/intern/BPH_mass_spring.cpp | 156 |
4 files changed, 425 insertions, 542 deletions
diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h index 17de53be42a..2862dda8ead 100644 --- a/source/blender/blenkernel/BKE_cloth.h +++ b/source/blender/blenkernel/BKE_cloth.h @@ -74,11 +74,11 @@ typedef struct ClothSolverResult { * own connectivity of the mesh based on the actual edges in the mesh. */ typedef struct Cloth { - struct ClothVertex *verts; /* The vertices that represent this cloth. */ - struct LinkNode *springs; /* The springs connecting the mesh. */ - unsigned int numsprings; /* The count of springs. */ - unsigned int mvert_num; /* The number of verts == m * n. */ - unsigned int tri_num; + struct ClothVertex *verts; /* The vertices that represent this cloth. */ + struct LinkNode *springs; /* The springs connecting the mesh. */ + unsigned int numsprings; /* The count of springs. */ + unsigned int mvert_num; /* The number of verts == m * n. */ + unsigned int primitive_num; /* Number of triangles for cloth and edges for hair. */ unsigned char old_solver_type; /* unused, only 1 solver here */ unsigned char pad2; short pad3; @@ -89,6 +89,7 @@ typedef struct Cloth { struct EdgeSet *edgeset; /* used for selfcollisions */ int last_frame; float initial_mesh_volume; /* Initial volume of the mesh. Used for pressure */ + struct MEdge *edges; /* Used for hair collisions. */ } Cloth; /** @@ -265,15 +266,6 @@ int cloth_bvh_collision(struct Depsgraph *depsgraph, float step, float dt); -void cloth_find_point_contacts(struct Depsgraph *depsgraph, - struct Object *ob, - struct ClothModifierData *clmd, - float step, - float dt, - ColliderContacts **r_collider_contacts, - int *r_totcolliders); -void cloth_free_contacts(ColliderContacts *collider_contacts, int totcolliders); - //////////////////////////////////////////////// ///////////////////////////////////////////////// diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index c26800aefba..7332c3e0d43 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -190,22 +190,36 @@ static BVHTree *bvhtree_build_from_cloth(ClothModifierData *clmd, float epsilon) vt = cloth->tri; /* in the moment, return zero if no faces there */ - if (!cloth->tri_num) { + if (!cloth->primitive_num) { return NULL; } /* create quadtree with k=26 */ - bvhtree = BLI_bvhtree_new(cloth->tri_num, epsilon, 4, 26); + bvhtree = BLI_bvhtree_new(cloth->primitive_num, epsilon, 4, 26); /* fill tree */ - for (i = 0; i < cloth->tri_num; i++, vt++) { - float co[3][3]; + if (clmd->hairdata == NULL) { + for (i = 0; i < cloth->primitive_num; i++, vt++) { + float co[3][3]; - copy_v3_v3(co[0], verts[vt->tri[0]].xold); - copy_v3_v3(co[1], verts[vt->tri[1]].xold); - copy_v3_v3(co[2], verts[vt->tri[2]].xold); + copy_v3_v3(co[0], verts[vt->tri[0]].xold); + copy_v3_v3(co[1], verts[vt->tri[1]].xold); + copy_v3_v3(co[2], verts[vt->tri[2]].xold); - BLI_bvhtree_insert(bvhtree, i, co[0], 3); + BLI_bvhtree_insert(bvhtree, i, co[0], 3); + } + } + else { + MEdge *edges = cloth->edges; + + for (i = 0; i < cloth->primitive_num; i++) { + float co[2][3]; + + copy_v3_v3(co[0], verts[edges[i].v1].xold); + copy_v3_v3(co[1], verts[edges[i].v2].xold); + + BLI_bvhtree_insert(bvhtree, i, co[0], 2); + } } /* balance tree */ @@ -222,6 +236,8 @@ void bvhtree_update_from_cloth(ClothModifierData *clmd, bool moving, bool self) ClothVertex *verts = cloth->verts; const MVertTri *vt; + BLI_assert(!(clmd->hairdata != NULL && self)); + if (self) { bvhtree = cloth->bvhselftree; } @@ -236,39 +252,59 @@ void bvhtree_update_from_cloth(ClothModifierData *clmd, bool moving, bool self) vt = cloth->tri; /* update vertex position in bvh tree */ - if (verts && vt) { - for (i = 0; i < cloth->tri_num; i++, vt++) { - float co[3][3], co_moving[3][3]; - bool ret; - - /* copy new locations into array */ - if (moving) { - copy_v3_v3(co[0], verts[vt->tri[0]].txold); - copy_v3_v3(co[1], verts[vt->tri[1]].txold); - copy_v3_v3(co[2], verts[vt->tri[2]].txold); - - /* update moving positions */ - copy_v3_v3(co_moving[0], verts[vt->tri[0]].tx); - copy_v3_v3(co_moving[1], verts[vt->tri[1]].tx); - copy_v3_v3(co_moving[2], verts[vt->tri[2]].tx); - - ret = BLI_bvhtree_update_node(bvhtree, i, co[0], co_moving[0], 3); - } - else { - copy_v3_v3(co[0], verts[vt->tri[0]].tx); - copy_v3_v3(co[1], verts[vt->tri[1]].tx); - copy_v3_v3(co[2], verts[vt->tri[2]].tx); + if (clmd->hairdata == NULL) { + if (verts && vt) { + for (i = 0; i < cloth->primitive_num; i++, vt++) { + float co[3][3], co_moving[3][3]; + bool ret; + + /* copy new locations into array */ + if (moving) { + copy_v3_v3(co[0], verts[vt->tri[0]].txold); + copy_v3_v3(co[1], verts[vt->tri[1]].txold); + copy_v3_v3(co[2], verts[vt->tri[2]].txold); + + /* update moving positions */ + copy_v3_v3(co_moving[0], verts[vt->tri[0]].tx); + copy_v3_v3(co_moving[1], verts[vt->tri[1]].tx); + copy_v3_v3(co_moving[2], verts[vt->tri[2]].tx); + + ret = BLI_bvhtree_update_node(bvhtree, i, co[0], co_moving[0], 3); + } + else { + copy_v3_v3(co[0], verts[vt->tri[0]].tx); + copy_v3_v3(co[1], verts[vt->tri[1]].tx); + copy_v3_v3(co[2], verts[vt->tri[2]].tx); - ret = BLI_bvhtree_update_node(bvhtree, i, co[0], NULL, 3); - } + ret = BLI_bvhtree_update_node(bvhtree, i, co[0], NULL, 3); + } - /* check if tree is already full */ - if (ret == false) { - break; + /* check if tree is already full */ + if (ret == false) { + break; + } } + + BLI_bvhtree_update_tree(bvhtree); } + } + else { + if (verts) { + MEdge *edges = cloth->edges; + + for (i = 0; i < cloth->primitive_num; i++) { + float co[2][3]; - BLI_bvhtree_update_tree(bvhtree); + copy_v3_v3(co[0], verts[edges[i].v1].tx); + copy_v3_v3(co[1], verts[edges[i].v2].tx); + + if (!BLI_bvhtree_update_node(bvhtree, i, co[0], NULL, 2)) { + break; + } + } + + BLI_bvhtree_update_tree(bvhtree); + } } } @@ -900,7 +936,13 @@ static void cloth_from_mesh(ClothModifierData *clmd, Mesh *mesh) } /* save face information */ - clmd->clothObject->tri_num = looptri_num; + if (clmd->hairdata == NULL) { + clmd->clothObject->primitive_num = looptri_num; + } + else { + clmd->clothObject->primitive_num = mesh->totedge; + } + clmd->clothObject->tri = MEM_mallocN(sizeof(MVertTri) * looptri_num, "clothLoopTris"); if (clmd->clothObject->tri == NULL) { cloth_free_modifier(clmd); @@ -910,6 +952,8 @@ static void cloth_from_mesh(ClothModifierData *clmd, Mesh *mesh) } BKE_mesh_runtime_verttri_from_looptri(clmd->clothObject->tri, mloop, looptri, looptri_num); + clmd->clothObject->edges = mesh->medge; + /* Free the springs since they can't be correct if the vertices * changed. */ diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c index 220b9417a6c..5db42618a9e 100644 --- a/source/blender/blenkernel/intern/collision.c +++ b/source/blender/blenkernel/intern/collision.c @@ -33,6 +33,7 @@ #include "BLI_utildefines.h" #include "BLI_blenlib.h" +#include "BLI_linklist.h" #include "BLI_math.h" #include "BLI_task.h" #include "BLI_threads.h" @@ -193,17 +194,17 @@ BLI_INLINE int next_ind(int i) return (++i < 3) ? i : 0; } -static float compute_collision_point(float a1[3], - const float a2[3], - const float a3[3], - const float b1[3], - const float b2[3], - const float b3[3], - bool culling, - bool use_normal, - float r_a[3], - float r_b[3], - float r_vec[3]) +static float compute_collision_point_tri_tri(const float a1[3], + const float a2[3], + const float a3[3], + const float b1[3], + const float b2[3], + const float b3[3], + bool culling, + bool use_normal, + float r_a[3], + float r_b[3], + float r_vec[3]) { float a[3][3]; float b[3][3]; @@ -423,6 +424,179 @@ static float compute_collision_point(float a1[3], return dist; } +static float compute_collision_point_edge_tri(const float a1[3], + const float a2[3], + const float b1[3], + const float b2[3], + const float b3[3], + bool culling, + bool use_normal, + float r_a[3], + float r_b[3], + float r_vec[3]) +{ + float a[2][3]; + float b[3][3]; + float dist = FLT_MAX; + float tmp_co1[3], tmp_co2[3]; + float isect_a[3]; + bool isect = false; + float tmp, tmp_vec[3]; + float normal[3], cent[3]; + bool backside = false; + + copy_v3_v3(a[0], a1); + copy_v3_v3(a[1], a2); + + copy_v3_v3(b[0], b1); + copy_v3_v3(b[1], b2); + copy_v3_v3(b[2], b3); + + normal_tri_v3(normal, b[0], b[1], b[2]); + + /* Find intersection. */ + if (isect_line_segment_tri_v3(a[0], a[1], b[0], b[1], b[2], &tmp, NULL)) { + interp_v3_v3v3(isect_a, a[0], a[1], tmp); + isect = true; + } + + /* Determine collision side. */ + if (culling) { + if (isect) { + backside = true; + } + else { + mid_v3_v3v3v3(cent, b[0], b[1], b[2]); + + for (int i = 0; i < 2; i++) { + sub_v3_v3v3(tmp_vec, a[i], cent); + if (dot_v3v3(tmp_vec, normal) < 0.0f) { + backside = true; + break; + } + } + } + } + + if (isect) { + /* Edge intersection. */ + copy_v3_v3(r_a, isect_a); + copy_v3_v3(r_b, isect_a); + + copy_v3_v3(r_vec, normal); + + return 0.0f; + } + + if (backside) { + float maxdist = 0.0f; + bool found = false; + + /* Point projections. */ + for (int i = 0; i < 2; i++) { + if (isect_ray_tri_v3(a[i], normal, b[0], b[1], b[2], &tmp, NULL)) { + if (tmp > maxdist) { + maxdist = tmp; + copy_v3_v3(r_a, a[i]); + madd_v3_v3v3fl(r_b, a[i], normal, tmp); + found = true; + } + } + } + + /* Edge projections. */ + for (int i = 0; i < 3; i++) { + float dir[3]; + + sub_v3_v3v3(tmp_vec, b[next_ind(i)], b[i]); + cross_v3_v3v3(dir, tmp_vec, normal); + + if (isect_line_plane_v3(tmp_co1, a[0], a[1], b[i], dir) && + point_in_slice_seg(tmp_co1, a[0], a[1]) && + point_in_slice_seg(tmp_co1, b[i], b[next_ind(i)])) { + closest_to_line_v3(tmp_co2, tmp_co1, b[i], b[next_ind(i)]); + sub_v3_v3v3(tmp_vec, tmp_co1, tmp_co2); + tmp = len_v3(tmp_vec); + + if ((tmp > maxdist) && (dot_v3v3(tmp_vec, normal) < 0.0f)) { + maxdist = tmp; + copy_v3_v3(r_a, tmp_co1); + copy_v3_v3(r_b, tmp_co2); + found = true; + } + } + } + + /* If no point is found, will fallback onto regular proximity test below. */ + if (found) { + sub_v3_v3v3(r_vec, r_b, r_a); + + if (use_normal) { + if (dot_v3v3(normal, r_vec) >= 0.0f) { + copy_v3_v3(r_vec, normal); + } + else { + negate_v3_v3(r_vec, normal); + } + } + + return 0.0f; + } + } + + /* Closest point. */ + for (int i = 0; i < 2; i++) { + closest_on_tri_to_point_v3(tmp_co1, a[i], b[0], b[1], b[2]); + tmp = len_squared_v3v3(tmp_co1, a[i]); + + if (tmp < dist) { + dist = tmp; + copy_v3_v3(r_a, a[i]); + copy_v3_v3(r_b, tmp_co1); + } + } + + /* Closest edge. */ + if (!isect) { + for (int j = 0; j < 3; j++) { + isect_seg_seg_v3(a[0], a[1], b[j], b[next_ind(j)], tmp_co1, tmp_co2); + tmp = len_squared_v3v3(tmp_co1, tmp_co2); + + if (tmp < dist) { + dist = tmp; + copy_v3_v3(r_a, tmp_co1); + copy_v3_v3(r_b, tmp_co2); + } + } + } + + if (isect) { + sub_v3_v3v3(r_vec, r_b, r_a); + dist = 0.0f; + } + else { + sub_v3_v3v3(r_vec, r_a, r_b); + dist = sqrtf(dist); + } + + if (culling && use_normal) { + copy_v3_v3(r_vec, normal); + } + else if (use_normal) { + if (dot_v3v3(normal, r_vec) >= 0.0f) { + copy_v3_v3(r_vec, normal); + } + else { + negate_v3_v3(r_vec, normal); + } + } + else if (culling && (dot_v3v3(r_vec, normal) < 0.0f)) { + return FLT_MAX; + } + + return dist; +} + // w3 is not perfect static void collision_compute_barycentric( const float pv[3], float p1[3], float p2[3], float p3[3], float *w1, float *w2, float *w3) @@ -494,6 +668,7 @@ static int cloth_collision_response_static(ClothModifierData *clmd, float v1[3], v2[3], relativeVelocity[3]; float magrelVel; float epsilon2 = BLI_bvhtree_get_epsilon(collmd->bvhtree); + const bool is_hair = (clmd->hairdata != NULL); cloth1 = clmd->clothObject; @@ -509,14 +684,32 @@ static int cloth_collision_response_static(ClothModifierData *clmd, continue; } - /* Compute barycentric coordinates for both collision points. */ - collision_compute_barycentric(collpair->pa, - cloth1->verts[collpair->ap1].tx, - cloth1->verts[collpair->ap2].tx, - cloth1->verts[collpair->ap3].tx, - &w1, - &w2, - &w3); + /* Compute barycentric coordinates and relative "velocity" for both collision points. */ + if (is_hair) { + w2 = line_point_factor_v3( + collpair->pa, cloth1->verts[collpair->ap1].tx, cloth1->verts[collpair->ap2].tx); + + w1 = 1.0f - w2; + + interp_v3_v3v3(v1, cloth1->verts[collpair->ap1].tv, cloth1->verts[collpair->ap2].tv, w2); + } + else { + collision_compute_barycentric(collpair->pa, + cloth1->verts[collpair->ap1].tx, + cloth1->verts[collpair->ap2].tx, + cloth1->verts[collpair->ap3].tx, + &w1, + &w2, + &w3); + + collision_interpolateOnTriangle(v1, + cloth1->verts[collpair->ap1].tv, + cloth1->verts[collpair->ap2].tv, + cloth1->verts[collpair->ap3].tv, + w1, + w2, + w3); + } collision_compute_barycentric(collpair->pb, collmd->current_xnew[collpair->bp1].co, @@ -526,15 +719,6 @@ static int cloth_collision_response_static(ClothModifierData *clmd, &u2, &u3); - /* Calculate relative "velocity". */ - collision_interpolateOnTriangle(v1, - cloth1->verts[collpair->ap1].tv, - cloth1->verts[collpair->ap2].tv, - cloth1->verts[collpair->ap3].tv, - w1, - w2, - w3); - collision_interpolateOnTriangle(v2, collmd->current_v[collpair->bp1].co, collmd->current_v[collpair->bp2].co, @@ -576,7 +760,10 @@ static int cloth_collision_response_static(ClothModifierData *clmd, VECADDMUL(i1, vrel_t_pre, w1 * impulse); VECADDMUL(i2, vrel_t_pre, w2 * impulse); - VECADDMUL(i3, vrel_t_pre, w3 * impulse); + + if (!is_hair) { + VECADDMUL(i3, vrel_t_pre, w3 * impulse); + } } /* Apply velocity stopping impulse. */ @@ -588,8 +775,10 @@ static int cloth_collision_response_static(ClothModifierData *clmd, VECADDMUL(i2, collpair->normal, w2 * impulse); cloth1->verts[collpair->ap2].impulse_count++; - VECADDMUL(i3, collpair->normal, w3 * impulse); - cloth1->verts[collpair->ap3].impulse_count++; + if (!is_hair) { + VECADDMUL(i3, collpair->normal, w3 * impulse); + cloth1->verts[collpair->ap3].impulse_count++; + } time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale); @@ -609,7 +798,10 @@ static int cloth_collision_response_static(ClothModifierData *clmd, VECADDMUL(i1, collpair->normal, impulse); VECADDMUL(i2, collpair->normal, impulse); - VECADDMUL(i3, collpair->normal, impulse); + + if (!is_hair) { + VECADDMUL(i3, collpair->normal, impulse); + } } result = 1; @@ -627,11 +819,17 @@ static int cloth_collision_response_static(ClothModifierData *clmd, VECADDMUL(i1, collpair->normal, w1 * impulse); VECADDMUL(i2, collpair->normal, w2 * impulse); - VECADDMUL(i3, collpair->normal, w3 * impulse); + + if (!is_hair) { + VECADDMUL(i3, collpair->normal, w3 * impulse); + } cloth1->verts[collpair->ap1].impulse_count++; cloth1->verts[collpair->ap2].impulse_count++; - cloth1->verts[collpair->ap3].impulse_count++; + + if (!is_hair) { + cloth1->verts[collpair->ap3].impulse_count++; + } result = 1; } @@ -656,9 +854,11 @@ static int cloth_collision_response_static(ClothModifierData *clmd, cloth1->verts[collpair->ap2].impulse[j] = i2[j]; } - if (cloth1->verts[collpair->ap3].impulse_count > 0 && - ABS(cloth1->verts[collpair->ap3].impulse[j]) < ABS(i3[j])) { - cloth1->verts[collpair->ap3].impulse[j] = i3[j]; + if (!is_hair) { + if (cloth1->verts[collpair->ap3].impulse_count > 0 && + ABS(cloth1->verts[collpair->ap3].impulse[j]) < ABS(i3[j])) { + cloth1->verts[collpair->ap3].impulse[j] = i3[j]; + } } } } @@ -875,17 +1075,17 @@ static void cloth_collision(void *__restrict userdata, tri_b = &collmd->tri[data->overlap[index].indexB]; /* Compute distance and normal. */ - distance = compute_collision_point(verts1[tri_a->tri[0]].tx, - verts1[tri_a->tri[1]].tx, - verts1[tri_a->tri[2]].tx, - collmd->current_xnew[tri_b->tri[0]].co, - collmd->current_xnew[tri_b->tri[1]].co, - collmd->current_xnew[tri_b->tri[2]].co, - data->culling, - data->use_normal, - pa, - pb, - vect); + distance = compute_collision_point_tri_tri(verts1[tri_a->tri[0]].tx, + verts1[tri_a->tri[1]].tx, + verts1[tri_a->tri[2]].tx, + collmd->current_xnew[tri_b->tri[0]].co, + collmd->current_xnew[tri_b->tri[1]].co, + collmd->current_xnew[tri_b->tri[2]].co, + data->culling, + data->use_normal, + pa, + pb, + vect); if ((distance <= (epsilon1 + epsilon2 + ALMOST_ZERO)) && (len_squared_v3(vect) > ALMOST_ZERO)) { collpair[index].ap1 = tri_a->tri[0]; @@ -946,17 +1146,17 @@ static void cloth_selfcollision(void *__restrict userdata, } /* Compute distance and normal. */ - distance = compute_collision_point(verts1[tri_a->tri[0]].tx, - verts1[tri_a->tri[1]].tx, - verts1[tri_a->tri[2]].tx, - verts1[tri_b->tri[0]].tx, - verts1[tri_b->tri[1]].tx, - verts1[tri_b->tri[2]].tx, - false, - false, - pa, - pb, - vect); + distance = compute_collision_point_tri_tri(verts1[tri_a->tri[0]].tx, + verts1[tri_a->tri[1]].tx, + verts1[tri_a->tri[2]].tx, + verts1[tri_b->tri[0]].tx, + verts1[tri_b->tri[1]].tx, + verts1[tri_b->tri[2]].tx, + false, + false, + pa, + pb, + vect); if ((distance <= (epsilon * 2.0f + ALMOST_ZERO)) && (len_squared_v3(vect) > ALMOST_ZERO)) { collpair[index].ap1 = tri_a->tri[0]; @@ -983,6 +1183,64 @@ static void cloth_selfcollision(void *__restrict userdata, } } +static void hair_collision(void *__restrict userdata, + const int index, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + ColDetectData *data = (ColDetectData *)userdata; + + ClothModifierData *clmd = data->clmd; + CollisionModifierData *collmd = data->collmd; + CollPair *collpair = data->collisions; + const MVertTri *tri_coll; + const MEdge *edge_coll; + ClothVertex *verts1 = clmd->clothObject->verts; + float distance = 0.0f; + float epsilon1 = clmd->coll_parms->epsilon; + float epsilon2 = BLI_bvhtree_get_epsilon(collmd->bvhtree); + float pa[3], pb[3], vect[3]; + + /* TODO: This is not efficient. Might be wise to instead build an array before iterating, to + * avoid walking the list every time. */ + edge_coll = &clmd->clothObject->edges[data->overlap[index].indexA]; + tri_coll = &collmd->tri[data->overlap[index].indexB]; + + /* Compute distance and normal. */ + distance = compute_collision_point_edge_tri(verts1[edge_coll->v1].tx, + verts1[edge_coll->v2].tx, + collmd->current_x[tri_coll->tri[0]].co, + collmd->current_x[tri_coll->tri[1]].co, + collmd->current_x[tri_coll->tri[2]].co, + data->culling, + data->use_normal, + pa, + pb, + vect); + + if ((distance <= (epsilon1 + epsilon2 + ALMOST_ZERO)) && (len_squared_v3(vect) > ALMOST_ZERO)) { + collpair[index].ap1 = edge_coll->v1; + collpair[index].ap2 = edge_coll->v2; + + collpair[index].bp1 = tri_coll->tri[0]; + collpair[index].bp2 = tri_coll->tri[1]; + collpair[index].bp3 = tri_coll->tri[2]; + + copy_v3_v3(collpair[index].pa, pa); + copy_v3_v3(collpair[index].pb, pb); + copy_v3_v3(collpair[index].vector, vect); + + normalize_v3_v3(collpair[index].normal, collpair[index].vector); + + collpair[index].distance = distance; + collpair[index].flag = 0; + + data->collided = true; + } + else { + collpair[index].flag = COLLISION_INACTIVE; + } +} + static void add_collision_object(ListBase *relations, Object *ob, int level, @@ -1148,6 +1406,7 @@ static bool cloth_bvh_objcollisions_nearcheck(ClothModifierData *clmd, bool culling, bool use_normal) { + const bool is_hair = (clmd->hairdata != NULL); *collisions = (CollPair *)MEM_mallocN(sizeof(CollPair) * numresult, "collision array"); ColDetectData data = { @@ -1163,7 +1422,8 @@ static bool cloth_bvh_objcollisions_nearcheck(ClothModifierData *clmd, TaskParallelSettings settings; BLI_parallel_range_settings_defaults(&settings); settings.use_threading = true; - BLI_task_parallel_range(0, numresult, &data, cloth_collision, &settings); + BLI_task_parallel_range( + 0, numresult, &data, is_hair ? hair_collision : cloth_collision, &settings); return data.collided; } @@ -1308,8 +1568,14 @@ int cloth_bvh_collision( if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED) { bvhtree_update_from_cloth(clmd, false, false); - collobjs = BKE_collision_objects_create( - depsgraph, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision); + /* Enable self collision if this is a hair sim */ + const bool is_hair = (clmd->hairdata != NULL); + + collobjs = BKE_collision_objects_create(depsgraph, + is_hair ? NULL : ob, + clmd->coll_parms->group, + &numcollobj, + eModifierType_Collision); if (collobjs) { coll_counts_obj = MEM_callocN(sizeof(uint) * numcollobj, "CollCounts"); @@ -1474,286 +1740,3 @@ void collision_get_collider_velocity(float vel_old[3], /* XXX assume constant velocity of the collider for now */ copy_v3_v3(vel_old, vel_new); } - -BLI_INLINE bool cloth_point_face_collision_params(const float p1[3], - const float p2[3], - const float v0[3], - const float v1[3], - const float v2[3], - float r_nor[3], - float *r_lambda, - float r_w[3]) -{ - float edge1[3], edge2[3], p2face[3], p1p2[3], v0p2[3]; - float nor_v0p2, nor_p1p2; - - sub_v3_v3v3(edge1, v1, v0); - sub_v3_v3v3(edge2, v2, v0); - cross_v3_v3v3(r_nor, edge1, edge2); - normalize_v3(r_nor); - - sub_v3_v3v3(v0p2, p2, v0); - nor_v0p2 = dot_v3v3(v0p2, r_nor); - madd_v3_v3v3fl(p2face, p2, r_nor, -nor_v0p2); - interp_weights_tri_v3(r_w, v0, v1, v2, p2face); - - sub_v3_v3v3(p1p2, p2, p1); - nor_p1p2 = dot_v3v3(p1p2, r_nor); - *r_lambda = (nor_p1p2 != 0.0f ? nor_v0p2 / nor_p1p2 : 0.0f); - - return r_w[1] >= 0.0f && r_w[2] >= 0.0f && r_w[1] + r_w[2] <= 1.0f; -} - -static CollPair *cloth_point_collpair(float p1[3], - const float p2[3], - const MVert *mverts, - int bp1, - int bp2, - int bp3, - int index_cloth, - int index_coll, - float epsilon, - CollPair *collpair) -{ - const float *co1 = mverts[bp1].co, *co2 = mverts[bp2].co, *co3 = mverts[bp3].co; - float lambda /*, distance1 */, distance2; - float facenor[3], v1p1[3], v1p2[3]; - float w[3]; - - if (!cloth_point_face_collision_params(p1, p2, co1, co2, co3, facenor, &lambda, w)) { - return collpair; - } - - sub_v3_v3v3(v1p1, p1, co1); - // distance1 = dot_v3v3(v1p1, facenor); - sub_v3_v3v3(v1p2, p2, co1); - distance2 = dot_v3v3(v1p2, facenor); - // if (distance2 > epsilon || (distance1 < 0.0f && distance2 < 0.0f)) - if (distance2 > epsilon) { - return collpair; - } - - collpair->face1 = index_cloth; /* XXX actually not a face, but equivalent index for point */ - collpair->face2 = index_coll; - collpair->ap1 = index_cloth; - collpair->ap2 = collpair->ap3 = -1; /* unused */ - collpair->bp1 = bp1; - collpair->bp2 = bp2; - collpair->bp3 = bp3; - - /* note: using the second point here, which is - * the current updated position that needs to be corrected - */ - copy_v3_v3(collpair->pa, p2); - collpair->distance = distance2; - mul_v3_v3fl(collpair->vector, facenor, -distance2); - - interp_v3_v3v3v3(collpair->pb, co1, co2, co3, w); - - copy_v3_v3(collpair->normal, facenor); - collpair->time = lambda; - collpair->flag = 0; - - collpair++; - return collpair; -} - -/* Determines collisions on overlap, - * collisions are written to collpair[i] and collision+number_collision_found is returned. */ -static CollPair *cloth_point_collision(ModifierData *md1, - ModifierData *md2, - BVHTreeOverlap *overlap, - float epsilon, - CollPair *collpair, - float UNUSED(dt)) -{ - ClothModifierData *clmd = (ClothModifierData *)md1; - CollisionModifierData *collmd = (CollisionModifierData *)md2; - /* Cloth *cloth = clmd->clothObject; */ /* UNUSED */ - ClothVertex *vert = NULL; - const MVertTri *vt; - const MVert *mverts = collmd->current_x; - - vert = &clmd->clothObject->verts[overlap->indexA]; - vt = &collmd->tri[overlap->indexB]; - - collpair = cloth_point_collpair(vert->tx, - vert->x, - mverts, - vt->tri[0], - vt->tri[1], - vt->tri[2], - overlap->indexA, - overlap->indexB, - epsilon, - collpair); - - return collpair; -} - -static void cloth_points_objcollisions_nearcheck(ClothModifierData *clmd, - CollisionModifierData *collmd, - CollPair **collisions, - CollPair **collisions_index, - int numresult, - BVHTreeOverlap *overlap, - float epsilon, - double dt) -{ - int i; - - /* can return 2 collisions in total */ - *collisions = (CollPair *)MEM_mallocN(sizeof(CollPair) * numresult * 2, "collision array"); - *collisions_index = *collisions; - - for (i = 0; i < numresult; i++) { - *collisions_index = cloth_point_collision( - (ModifierData *)clmd, (ModifierData *)collmd, overlap + i, epsilon, *collisions_index, dt); - } -} - -void cloth_find_point_contacts(Depsgraph *depsgraph, - Object *ob, - ClothModifierData *clmd, - float step, - float dt, - ColliderContacts **r_collider_contacts, - int *r_totcolliders) -{ - Cloth *cloth = clmd->clothObject; - BVHTree *cloth_bvh; - unsigned int i = 0, mvert_num = 0; - ClothVertex *verts = NULL; - - ColliderContacts *collider_contacts; - - Object **collobjs = NULL; - unsigned int numcollobj = 0; - - verts = cloth->verts; - mvert_num = cloth->mvert_num; - - //////////////////////////////////////////////////////////// - // static collisions - //////////////////////////////////////////////////////////// - - /* Check we do have collision objects to test against, before doing anything else. */ - collobjs = BKE_collision_objects_create( - depsgraph, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision); - if (!collobjs) { - *r_collider_contacts = NULL; - *r_totcolliders = 0; - return; - } - - // create temporary cloth points bvh - cloth_bvh = BLI_bvhtree_new(mvert_num, clmd->coll_parms->epsilon, 4, 6); - /* fill tree */ - for (i = 0; i < mvert_num; i++) { - float co[6]; - - copy_v3_v3(&co[0 * 3], verts[i].x); - copy_v3_v3(&co[1 * 3], verts[i].tx); - - BLI_bvhtree_insert(cloth_bvh, i, co, 2); - } - /* balance tree */ - BLI_bvhtree_balance(cloth_bvh); - - /* move object to position (step) in time */ - for (i = 0; i < numcollobj; i++) { - Object *collob = collobjs[i]; - CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType( - collob, eModifierType_Collision); - if (!collmd->bvhtree) { - continue; - } - - /* move object to position (step) in time */ - collision_move_object(collmd, step + dt, step, true); - } - - collider_contacts = MEM_callocN(sizeof(ColliderContacts) * numcollobj, "CollPair"); - - // check all collision objects - for (i = 0; i < numcollobj; i++) { - ColliderContacts *ct = collider_contacts + i; - Object *collob = collobjs[i]; - CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType( - collob, eModifierType_Collision); - BVHTreeOverlap *overlap; - unsigned int result = 0; - float epsilon; - - ct->ob = collob; - ct->collmd = collmd; - ct->collisions = NULL; - ct->totcollisions = 0; - - if (!collmd->bvhtree) { - continue; - } - - /* search for overlapping collision pairs */ - overlap = BLI_bvhtree_overlap(cloth_bvh, collmd->bvhtree, &result, NULL, NULL); - epsilon = BLI_bvhtree_get_epsilon(collmd->bvhtree); - - // go to next object if no overlap is there - if (result && overlap) { - CollPair *collisions_index; - - /* check if collisions really happen (costly near check) */ - cloth_points_objcollisions_nearcheck( - clmd, collmd, &ct->collisions, &collisions_index, result, overlap, epsilon, dt); - ct->totcollisions = (int)(collisions_index - ct->collisions); - - /* Resolve nearby collisions. */ -#if 0 - ret += cloth_points_objcollisions_resolve( - clmd, collmd, collob->pd, collisions[i], collisions_index[i], dt); -#endif - } - - if (overlap) { - MEM_freeN(overlap); - } - } - - BKE_collision_objects_free(collobjs); - - BLI_bvhtree_free(cloth_bvh); - - //////////////////////////////////////////////////////////// - // update positions - // this is needed for bvh_calc_DOP_hull_moving() [kdop.c] - //////////////////////////////////////////////////////////// - - // verts come from clmd - for (i = 0; i < mvert_num; i++) { - if (clmd->sim_parms->vgroup_mass > 0) { - if (verts[i].flags & CLOTH_VERT_FLAG_PINNED) { - continue; - } - } - - add_v3_v3v3(verts[i].tx, verts[i].txold, verts[i].tv); - } - //////////////////////////////////////////////////////////// - - *r_collider_contacts = collider_contacts; - *r_totcolliders = numcollobj; -} - -void cloth_free_contacts(ColliderContacts *collider_contacts, int totcolliders) -{ - if (collider_contacts) { - int i; - for (i = 0; i < totcolliders; i++) { - ColliderContacts *ct = collider_contacts + i; - if (ct->collisions) { - MEM_freeN(ct->collisions); - } - } - MEM_freeN(collider_contacts); - } -} diff --git a/source/blender/physics/intern/BPH_mass_spring.cpp b/source/blender/physics/intern/BPH_mass_spring.cpp index 999cefde104..94eaffd1f91 100644 --- a/source/blender/physics/intern/BPH_mass_spring.cpp +++ b/source/blender/physics/intern/BPH_mass_spring.cpp @@ -83,7 +83,7 @@ static float cloth_calc_volume(ClothModifierData *clmd) float vol = 0; if (clmd->sim_parms->vgroup_pressure > 0) { - for (unsigned int i = 0; i < cloth->tri_num; i++) { + for (unsigned int i = 0; i < cloth->primitive_num; i++) { bool skip_face = false; /* We have custom vertex weights for pressure. */ const MVertTri *vt = &tri[i]; @@ -103,7 +103,7 @@ static float cloth_calc_volume(ClothModifierData *clmd) } } else { - for (unsigned int i = 0; i < cloth->tri_num; i++) { + for (unsigned int i = 0; i < cloth->primitive_num; i++) { const MVertTri *vt = &tri[i]; vol += BPH_tri_tetra_volume_signed_6x(data, vt->tri[0], vt->tri[1], vt->tri[2]); } @@ -174,96 +174,17 @@ void BKE_cloth_solver_set_volume(ClothModifierData *clmd) cloth->initial_mesh_volume = cloth_calc_volume(clmd); } -static bool collision_response(ClothModifierData *clmd, - CollisionModifierData *collmd, - CollPair *collpair, - float dt, - float restitution, - float r_impulse[3]) -{ - Cloth *cloth = clmd->clothObject; - int index = collpair->ap1; - bool result = false; - - float v1[3], v2_old[3], v2_new[3], v_rel_old[3], v_rel_new[3]; - float epsilon2 = BLI_bvhtree_get_epsilon(collmd->bvhtree); - - float margin_distance = (float)collpair->distance - epsilon2; - float mag_v_rel; - - zero_v3(r_impulse); - - if (margin_distance > 0.0f) { - return false; /* XXX tested before already? */ - } - - /* only handle static collisions here */ - if (collpair->flag & COLLISION_IN_FUTURE) { - return false; - } - - /* velocity */ - copy_v3_v3(v1, cloth->verts[index].v); - collision_get_collider_velocity(v2_old, v2_new, collmd, collpair); - /* relative velocity = velocity of the cloth point relative to the collider */ - sub_v3_v3v3(v_rel_old, v1, v2_old); - sub_v3_v3v3(v_rel_new, v1, v2_new); - /* normal component of the relative velocity */ - mag_v_rel = dot_v3v3(v_rel_old, collpair->normal); - - /* only valid when moving toward the collider */ - if (mag_v_rel < -ALMOST_ZERO) { - float v_nor_old, v_nor_new; - float v_tan_old[3], v_tan_new[3]; - float bounce, repulse; - - /* Collision response based on - * "Simulating Complex Hair with Robust Collision Handling" (Choe, Choi, Ko, ACM SIGGRAPH 2005) - * http://graphics.snu.ac.kr/publications/2005-choe-HairSim/Choe_2005_SCA.pdf - */ - - v_nor_old = mag_v_rel; - v_nor_new = dot_v3v3(v_rel_new, collpair->normal); - - madd_v3_v3v3fl(v_tan_old, v_rel_old, collpair->normal, -v_nor_old); - madd_v3_v3v3fl(v_tan_new, v_rel_new, collpair->normal, -v_nor_new); - - bounce = -v_nor_old * restitution; - - repulse = -margin_distance / dt; /* base repulsion velocity in normal direction */ - /* XXX this clamping factor is quite arbitrary ... - * not sure if there is a more scientific approach, but seems to give good results - */ - CLAMP(repulse, 0.0f, 4.0f * bounce); - - if (margin_distance < -epsilon2) { - mul_v3_v3fl(r_impulse, collpair->normal, max_ff(repulse, bounce) - v_nor_new); - } - else { - bounce = 0.0f; - mul_v3_v3fl(r_impulse, collpair->normal, repulse - v_nor_new); - } - - result = true; - } - - return result; -} - /* Init constraint matrix * This is part of the modified CG method suggested by Baraff/Witkin in * "Large Steps in Cloth Simulation" (Siggraph 1998) */ -static void cloth_setup_constraints(ClothModifierData *clmd, - ColliderContacts *contacts, - int totcolliders, - float dt) +static void cloth_setup_constraints(ClothModifierData *clmd) { Cloth *cloth = clmd->clothObject; Implicit_Data *data = cloth->implicit; ClothVertex *verts = cloth->verts; int mvert_num = cloth->mvert_num; - int i, j, v; + int v; const float ZERO[3] = {0.0f, 0.0f, 0.0f}; @@ -277,37 +198,6 @@ static void cloth_setup_constraints(ClothModifierData *clmd, verts[v].impulse_count = 0; } - - for (i = 0; i < totcolliders; i++) { - ColliderContacts *ct = &contacts[i]; - for (j = 0; j < ct->totcollisions; j++) { - CollPair *collpair = &ct->collisions[j]; - // float restitution = (1.0f - clmd->coll_parms->damping) * (1.0f - ct->ob->pd->pdef_sbdamp); - float restitution = 0.0f; - int v = collpair->face1; - float impulse[3]; - - /* pinned verts handled separately */ - if (verts[v].flags & CLOTH_VERT_FLAG_PINNED) { - continue; - } - - /* XXX cheap way of avoiding instability from multiple collisions in the same step - * this should eventually be supported ... - */ - if (verts[v].impulse_count > 0) { - continue; - } - - /* calculate collision response */ - if (!collision_response(clmd, ct->collmd, collpair, dt, restitution, impulse)) { - continue; - } - - BPH_mass_spring_add_constraint_ndof2(data, v, collpair->normal, impulse); - ++verts[v].impulse_count; - } - } } /* computes where the cloth would be if it were subject to perfectly stiff edges @@ -691,7 +581,7 @@ static void cloth_calc_force( pressure_difference *= clmd->sim_parms->pressure_factor; - for (i = 0; i < cloth->tri_num; i++) { + for (i = 0; i < cloth->primitive_num; i++) { const MVertTri *vt = &tri[i]; if (fabs(pressure_difference) > 1E-6f) { if (clmd->sim_parms->vgroup_pressure > 0) { @@ -744,13 +634,13 @@ static void cloth_calc_force( effectors, NULL, clmd->sim_parms->effector_weights, &epoint, winvec[i], NULL); } - for (i = 0; i < cloth->tri_num; i++) { + for (i = 0; i < cloth->primitive_num; i++) { const MVertTri *vt = &tri[i]; BPH_mass_spring_force_face_wind(data, vt->tri[0], vt->tri[1], vt->tri[2], winvec); } /* Hair has only edges */ - if (cloth->tri_num == 0) { + if (cloth->primitive_num == 0) { #if 0 ClothHairData *hairdata = clmd->hairdata; ClothHairData *hair_ij, *hair_kl; @@ -1241,8 +1131,6 @@ int BPH_cloth_solve( unsigned int mvert_num = cloth->mvert_num; float dt = clmd->sim_parms->dt * clmd->sim_parms->timescale; Implicit_Data *id = cloth->implicit; - ColliderContacts *contacts = NULL; - int totcolliders = 0; BKE_sim_debug_data_clear_category("collision"); @@ -1269,25 +1157,8 @@ int BPH_cloth_solve( while (step < tf) { ImplicitSolverResult result; - if (is_hair) { - /* copy velocities for collision */ - for (i = 0; i < mvert_num; i++) { - BPH_mass_spring_get_motion_state(id, i, NULL, verts[i].tv); - copy_v3_v3(verts[i].v, verts[i].tv); - } - - /* determine contact points */ - if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED) { - cloth_find_point_contacts(depsgraph, ob, clmd, 0.0f, tf, &contacts, &totcolliders); - } - - /* setup vertex constraints for pinned vertices and contacts */ - cloth_setup_constraints(clmd, contacts, totcolliders, dt); - } - else { - /* setup vertex constraints for pinned vertices */ - cloth_setup_constraints(clmd, NULL, 0, dt); - } + /* setup vertex constraints for pinned vertices */ + cloth_setup_constraints(clmd); /* initialize forces to zero */ BPH_mass_spring_clear_forces(id); @@ -1300,9 +1171,7 @@ int BPH_cloth_solve( cloth_record_result(clmd, &result, dt); /* Calculate collision impulses. */ - if (!is_hair) { - cloth_solve_collisions(depsgraph, ob, clmd, step, dt); - } + cloth_solve_collisions(depsgraph, ob, clmd, step, dt); if (is_hair) { cloth_continuum_step(clmd, dt); @@ -1327,11 +1196,6 @@ int BPH_cloth_solve( BPH_mass_spring_get_motion_state(id, i, verts[i].txold, NULL); } - /* free contact points */ - if (contacts) { - cloth_free_contacts(contacts, totcolliders); - } - step += dt; } |