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--source/blender/blenkernel/BKE_cloth.h20
-rw-r--r--source/blender/blenkernel/intern/cloth.c118
-rw-r--r--source/blender/blenkernel/intern/collision.c673
-rw-r--r--source/blender/physics/intern/BPH_mass_spring.cpp156
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;
}