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:
Diffstat (limited to 'source/blender/blenkernel/intern/collision.c')
-rw-r--r--source/blender/blenkernel/intern/collision.c780
1 files changed, 650 insertions, 130 deletions
diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c
index 2f600935b1e..d35762a6f13 100644
--- a/source/blender/blenkernel/intern/collision.c
+++ b/source/blender/blenkernel/intern/collision.c
@@ -33,6 +33,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_cloth_types.h"
+#include "DNA_effect_types.h"
#include "DNA_group_types.h"
#include "DNA_object_types.h"
#include "DNA_object_force.h"
@@ -45,6 +46,7 @@
#include "BLI_edgehash.h"
#include "BKE_cloth.h"
+#include "BKE_effect.h"
#include "BKE_modifier.h"
#include "BKE_scene.h"
@@ -69,82 +71,92 @@ void collision_move_object(CollisionModifierData *collmd, float step, float prev
float tv[3] = {0, 0, 0};
unsigned int i = 0;
- for ( i = 0; i < collmd->numverts; i++ ) {
+ for (i = 0; i < collmd->mvert_num; i++) {
sub_v3_v3v3(tv, collmd->xnew[i].co, collmd->x[i].co);
VECADDS(collmd->current_x[i].co, collmd->x[i].co, tv, prevstep);
VECADDS(collmd->current_xnew[i].co, collmd->x[i].co, tv, step);
sub_v3_v3v3(collmd->current_v[i].co, collmd->current_xnew[i].co, collmd->current_x[i].co);
}
- bvhtree_update_from_mvert ( collmd->bvhtree, collmd->mfaces, collmd->numfaces, collmd->current_x, collmd->current_xnew, collmd->numverts, 1 );
+ bvhtree_update_from_mvert(
+ collmd->bvhtree, collmd->current_x, collmd->current_xnew,
+ collmd->tri, collmd->tri_num, true);
}
-BVHTree *bvhtree_build_from_mvert ( MFace *mfaces, unsigned int numfaces, MVert *x, unsigned int UNUSED(numverts), float epsilon )
+BVHTree *bvhtree_build_from_mvert(
+ const MVert *mvert,
+ const struct MVertTri *tri, int tri_num,
+ float epsilon)
{
BVHTree *tree;
- float co[12];
- unsigned int i;
- MFace *tface = mfaces;
+ const MVertTri *vt;
+ int i;
+
+ tree = BLI_bvhtree_new(tri_num, epsilon, 4, 26);
- tree = BLI_bvhtree_new ( numfaces*2, epsilon, 4, 26 );
+ /* fill tree */
+ for (i = 0, vt = tri; i < tri_num; i++, vt++) {
+ float co[3][3];
- // fill tree
- for ( i = 0; i < numfaces; i++, tface++ ) {
- copy_v3_v3 ( &co[0*3], x[tface->v1].co );
- copy_v3_v3 ( &co[1*3], x[tface->v2].co );
- copy_v3_v3 ( &co[2*3], x[tface->v3].co );
- if ( tface->v4 )
- copy_v3_v3 ( &co[3*3], x[tface->v4].co );
+ copy_v3_v3(co[0], mvert[vt->tri[0]].co);
+ copy_v3_v3(co[1], mvert[vt->tri[1]].co);
+ copy_v3_v3(co[2], mvert[vt->tri[2]].co);
- BLI_bvhtree_insert ( tree, i, co, ( mfaces->v4 ? 4 : 3 ) );
+ BLI_bvhtree_insert(tree, i, co[0], 3);
}
- // balance tree
- BLI_bvhtree_balance ( tree );
+ /* balance tree */
+ BLI_bvhtree_balance(tree);
return tree;
}
-void bvhtree_update_from_mvert(BVHTree *bvhtree, MFace *faces, int numfaces, MVert *x, MVert *xnew, int UNUSED(numverts), int moving )
+void bvhtree_update_from_mvert(
+ BVHTree *bvhtree,
+ const MVert *mvert, const MVert *mvert_moving,
+ const MVertTri *tri, int tri_num,
+ bool moving)
{
+ const MVertTri *vt;
int i;
- MFace *mfaces = faces;
- float co[12], co_moving[12];
- bool ret = false;
- if ( !bvhtree )
+ if ((bvhtree == NULL) || (mvert == NULL)) {
return;
+ }
- if ( x ) {
- for ( i = 0; i < numfaces; i++, mfaces++ ) {
- copy_v3_v3 ( &co[0*3], x[mfaces->v1].co );
- copy_v3_v3 ( &co[1*3], x[mfaces->v2].co );
- copy_v3_v3 ( &co[2*3], x[mfaces->v3].co );
- if ( mfaces->v4 )
- copy_v3_v3 ( &co[3*3], x[mfaces->v4].co );
-
- // copy new locations into array
- if ( moving && xnew ) {
- // update moving positions
- copy_v3_v3 ( &co_moving[0*3], xnew[mfaces->v1].co );
- copy_v3_v3 ( &co_moving[1*3], xnew[mfaces->v2].co );
- copy_v3_v3 ( &co_moving[2*3], xnew[mfaces->v3].co );
- if ( mfaces->v4 )
- copy_v3_v3 ( &co_moving[3*3], xnew[mfaces->v4].co );
-
- ret = BLI_bvhtree_update_node ( bvhtree, i, co, co_moving, ( mfaces->v4 ? 4 : 3 ) );
- }
- else {
- ret = BLI_bvhtree_update_node ( bvhtree, i, co, NULL, ( mfaces->v4 ? 4 : 3 ) );
- }
+ if (mvert_moving == NULL) {
+ moving = false;
+ }
+
+ for (i = 0, vt = tri; i < tri_num; i++, vt++) {
+ float co[3][3];
+ bool ret;
+
+ copy_v3_v3(co[0], mvert[vt->tri[0]].co);
+ copy_v3_v3(co[1], mvert[vt->tri[1]].co);
+ copy_v3_v3(co[2], mvert[vt->tri[2]].co);
- // check if tree is already full
- if ( !ret )
- break;
+ /* copy new locations into array */
+ if (moving) {
+ float co_moving[3][3];
+ /* update moving positions */
+ copy_v3_v3(co_moving[0], mvert_moving[vt->tri[0]].co);
+ copy_v3_v3(co_moving[1], mvert_moving[vt->tri[1]].co);
+ copy_v3_v3(co_moving[2], mvert_moving[vt->tri[2]].co);
+
+ ret = BLI_bvhtree_update_node(bvhtree, i, &co[0][0], &co_moving[0][0], 3);
+ }
+ else {
+ ret = BLI_bvhtree_update_node(bvhtree, i, &co[0][0], NULL, 3);
}
- BLI_bvhtree_update_tree ( bvhtree );
+ /* check if tree is already full */
+ if (ret == false) {
+ break;
+ }
}
+
+ BLI_bvhtree_update_tree(bvhtree);
}
/***********************************
@@ -378,80 +390,29 @@ static CollPair* cloth_collision(ModifierData *md1, ModifierData *md2,
ClothModifierData *clmd = (ClothModifierData *)md1;
CollisionModifierData *collmd = (CollisionModifierData *) md2;
/* Cloth *cloth = clmd->clothObject; */ /* UNUSED */
- MFace *face1=NULL, *face2 = NULL;
+ const MVertTri *tri_a, *tri_b;
#ifdef WITH_BULLET
ClothVertex *verts1 = clmd->clothObject->verts;
#endif
double distance = 0;
float epsilon1 = clmd->coll_parms->epsilon;
float epsilon2 = BLI_bvhtree_getepsilon ( collmd->bvhtree );
- int i;
- face1 = & ( clmd->clothObject->mfaces[overlap->indexA] );
- face2 = & ( collmd->mfaces[overlap->indexB] );
-
- // check all 4 possible collisions
- for ( i = 0; i < 4; i++ ) {
- if ( i == 0 ) {
- // fill faceA
- collpair->ap1 = face1->v1;
- collpair->ap2 = face1->v2;
- collpair->ap3 = face1->v3;
-
- // fill faceB
- collpair->bp1 = face2->v1;
- collpair->bp2 = face2->v2;
- collpair->bp3 = face2->v3;
- }
- else if ( i == 1 ) {
- if ( face1->v4 ) {
- // fill faceA
- collpair->ap1 = face1->v1;
- collpair->ap2 = face1->v3;
- collpair->ap3 = face1->v4;
-
- // fill faceB
- collpair->bp1 = face2->v1;
- collpair->bp2 = face2->v2;
- collpair->bp3 = face2->v3;
- }
- else {
- i++;
- }
- }
- if ( i == 2 ) {
- if ( face2->v4 ) {
- // fill faceA
- collpair->ap1 = face1->v1;
- collpair->ap2 = face1->v2;
- collpair->ap3 = face1->v3;
-
- // fill faceB
- collpair->bp1 = face2->v1;
- collpair->bp2 = face2->v4;
- collpair->bp3 = face2->v3;
- }
- else {
- break;
- }
- }
- else if ( i == 3 ) {
- if ( face1->v4 && face2->v4 ) {
- // fill faceA
- collpair->ap1 = face1->v1;
- collpair->ap2 = face1->v3;
- collpair->ap3 = face1->v4;
-
- // fill faceB
- collpair->bp1 = face2->v1;
- collpair->bp2 = face2->v3;
- collpair->bp3 = face2->v4;
- }
- else {
- break;
- }
- }
-
+ tri_a = &clmd->clothObject->tri[overlap->indexA];
+ tri_b = &collmd->tri[overlap->indexB];
+
+ /* fill face_a */
+ collpair->ap1 = tri_a->tri[0];
+ collpair->ap2 = tri_a->tri[1];
+ collpair->ap3 = tri_a->tri[2];
+
+ /* fill face_b */
+ collpair->bp1 = tri_b->tri[0];
+ collpair->bp2 = tri_b->tri[1];
+ collpair->bp3 = tri_b->tri[2];
+
+ {
+
#ifdef WITH_BULLET
// calc distance + normal
distance = plNearestPoints (
@@ -648,24 +609,24 @@ static void cloth_bvh_objcollisions_nearcheck ( ClothModifierData * clmd, Collis
{
int i;
- *collisions = (CollPair *) MEM_mallocN(sizeof(CollPair) * numresult * 64, "collision array" ); // * 4 since cloth_collision_static can return more than 1 collision
+ *collisions = (CollPair *) MEM_mallocN(sizeof(CollPair) * numresult * 4, "collision array" ); // * 4 since cloth_collision_static can return more than 1 collision
*collisions_index = *collisions;
for ( i = 0; i < numresult; i++ ) {
- *collisions_index = cloth_collision ( (ModifierData *)clmd, (ModifierData *)collmd,
- overlap+i, *collisions_index, dt );
+ *collisions_index = cloth_collision((ModifierData *)clmd, (ModifierData *)collmd,
+ overlap+i, *collisions_index, dt);
}
}
static int cloth_bvh_objcollisions_resolve ( ClothModifierData * clmd, CollisionModifierData *collmd, CollPair *collisions, CollPair *collisions_index)
{
Cloth *cloth = clmd->clothObject;
- int i=0, j = 0, /*numfaces = 0, */ numverts = 0;
+ int i=0, j = 0, /*numfaces = 0, */ mvert_num = 0;
ClothVertex *verts = NULL;
int ret = 0;
int result = 0;
- numverts = clmd->clothObject->numverts;
+ mvert_num = clmd->clothObject->mvert_num;
verts = cloth->verts;
// process all collisions (calculate impulses, TODO: also repulses if distance too short)
@@ -678,7 +639,7 @@ static int cloth_bvh_objcollisions_resolve ( ClothModifierData * clmd, Collision
// apply impulses in parallel
if (result) {
- for (i = 0; i < numverts; i++) {
+ for (i = 0; i < mvert_num; i++) {
// calculate "velocities" (just xnew = xold + v; no dt in v)
if (verts[i].impulse_count) {
// VECADDMUL ( verts[i].tv, verts[i].impulse, 1.0f / verts[i].impulse_count );
@@ -704,7 +665,7 @@ int cloth_bvh_objcollision(Object *ob, ClothModifierData *clmd, float step, floa
{
Cloth *cloth= clmd->clothObject;
BVHTree *cloth_bvh= cloth->bvhtree;
- unsigned int i=0, /* numfaces = 0, */ /* UNUSED */ numverts = 0, k, l, j;
+ unsigned int i=0, /* numfaces = 0, */ /* UNUSED */ mvert_num = 0, k, l, j;
int rounds = 0; // result counts applied collisions; ic is for debug output;
ClothVertex *verts = NULL;
int ret = 0, ret2 = 0;
@@ -716,7 +677,7 @@ int cloth_bvh_objcollision(Object *ob, ClothModifierData *clmd, float step, floa
verts = cloth->verts;
/* numfaces = cloth->numfaces; */ /* UNUSED */
- numverts = cloth->numverts;
+ mvert_num = cloth->mvert_num;
////////////////////////////////////////////////////////////
// static collisions
@@ -762,7 +723,7 @@ int cloth_bvh_objcollision(Object *ob, ClothModifierData *clmd, float step, floa
continue;
/* search for overlapping collision pairs */
- overlap = BLI_bvhtree_overlap ( cloth_bvh, collmd->bvhtree, &result );
+ overlap = BLI_bvhtree_overlap(cloth_bvh, collmd->bvhtree, &result, NULL, NULL);
// go to next object if no overlap is there
if ( result && overlap ) {
@@ -792,8 +753,8 @@ int cloth_bvh_objcollision(Object *ob, ClothModifierData *clmd, float step, floa
// this is needed for bvh_calc_DOP_hull_moving() [kdop.c]
////////////////////////////////////////////////////////////
- // verts come from clmd
- for ( i = 0; i < numverts; i++ ) {
+ /* verts come from clmd */
+ for (i = 0; i < mvert_num; i++) {
if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL ) {
if ( verts [i].flags & CLOTH_VERT_FLAG_PINNED ) {
continue;
@@ -818,13 +779,13 @@ int cloth_bvh_objcollision(Object *ob, ClothModifierData *clmd, float step, floa
verts = cloth->verts; // needed for openMP
/* numfaces = cloth->numfaces; */ /* UNUSED */
- numverts = cloth->numverts;
+ mvert_num = cloth->mvert_num;
verts = cloth->verts;
if ( cloth->bvhselftree ) {
// search for overlapping collision pairs
- overlap = BLI_bvhtree_overlap ( cloth->bvhselftree, cloth->bvhselftree, &result );
+ overlap = BLI_bvhtree_overlap(cloth->bvhselftree, cloth->bvhselftree, &result, NULL, NULL);
// #pragma omp parallel for private(k, i, j) schedule(static)
for ( k = 0; k < result; k++ ) {
@@ -896,8 +857,8 @@ int cloth_bvh_objcollision(Object *ob, ClothModifierData *clmd, float step, floa
////////////////////////////////////////////////////////////
// SELFCOLLISIONS: update velocities
////////////////////////////////////////////////////////////
- if ( ret2 ) {
- for ( i = 0; i < cloth->numverts; i++ ) {
+ if (ret2) {
+ for (i = 0; i < cloth->mvert_num; i++) {
if ( ! ( verts [i].flags & CLOTH_VERT_FLAG_PINNED ) ) {
sub_v3_v3v3(verts[i].tv, verts[i].tx, verts[i].txold);
}
@@ -913,3 +874,562 @@ int cloth_bvh_objcollision(Object *ob, ClothModifierData *clmd, float step, floa
return 1|MIN2 ( ret, 1 );
}
+
+BLI_INLINE void max_v3_v3v3(float r[3], const float a[3], const float b[3])
+{
+ r[0] = max_ff(a[0], b[0]);
+ r[1] = max_ff(a[1], b[1]);
+ r[2] = max_ff(a[2], b[2]);
+}
+
+void collision_get_collider_velocity(float vel_old[3], float vel_new[3], CollisionModifierData *collmd, CollPair *collpair)
+{
+ float u1, u2, u3;
+
+ /* compute barycentric coordinates */
+ collision_compute_barycentric(collpair->pb,
+ collmd->current_x[collpair->bp1].co,
+ collmd->current_x[collpair->bp2].co,
+ collmd->current_x[collpair->bp3].co,
+ &u1, &u2, &u3);
+
+ collision_interpolateOnTriangle(vel_new, collmd->current_v[collpair->bp1].co, collmd->current_v[collpair->bp2].co, collmd->current_v[collpair->bp3].co, u1, u2, u3);
+ /* XXX assume constant velocity of the collider for now */
+ copy_v3_v3(vel_old, vel_new);
+}
+
+static bool cloth_points_collision_response_static(ClothModifierData *clmd, CollisionModifierData *collmd, PartDeflect *pd,
+ CollPair *collpair, CollPair *collision_end, float dt)
+{
+ bool result = false;
+ float restitution = (1.0f - clmd->coll_parms->damping) * (1.0f - pd->pdef_sbdamp);
+ float inv_dt = 1.0f / dt;
+ Cloth *cloth1 = clmd->clothObject;
+
+ // float w1, w2;
+ float u1, u2, u3;
+ float v1[3], v2_old[3], v2_new[3], v_rel_old[3], v_rel_new[3];
+ float epsilon2 = BLI_bvhtree_getepsilon ( collmd->bvhtree );
+
+ for ( ; collpair != collision_end; collpair++ ) {
+ float margin_distance = (float)(collpair->distance - (double)epsilon2);
+ float impulse[3];
+ float mag_v_rel;
+
+ if (margin_distance > 0.0f)
+ continue;
+
+ zero_v3(impulse);
+
+ /* only handle static collisions here */
+ if ( collpair->flag & COLLISION_IN_FUTURE )
+ continue;
+
+ /* compute barycentric coordinates for both collision points */
+ // w1 = 1.0f - collpair->time;
+ // w2 = collpair->time;
+
+ /* was: txold */
+ collision_compute_barycentric ( collpair->pb,
+ collmd->current_x[collpair->bp1].co,
+ collmd->current_x[collpair->bp2].co,
+ collmd->current_x[collpair->bp3].co,
+ &u1, &u2, &u3 );
+
+ /* Calculate relative velocity */
+ copy_v3_v3(v1, cloth1->verts[collpair->ap1].tv);
+
+ collision_interpolateOnTriangle ( v2_new, collmd->current_v[collpair->bp1].co, collmd->current_v[collpair->bp2].co, collmd->current_v[collpair->bp3].co, u1, u2, u3 );
+ /* XXX assume constant velocity of the collider for now */
+ copy_v3_v3(v2_old, v2_new);
+
+ 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);
+
+ /**** DEBUG ****/
+ BKE_sim_debug_data_add_dot(collpair->pa, 0.9, 0.2, 0.2, "collision", 833, collpair->face1, collpair->face2);
+ BKE_sim_debug_data_add_dot(collpair->pb, 0.2, 0.9, 0.2, "collision", 834, collpair->face1, collpair->face2);
+ BKE_sim_debug_data_add_line(collpair->pa, collpair->pb, 0.8, 0.8, 0.8, "collision", 835, collpair->face1, collpair->face2);
+ /********/
+
+ 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);
+
+ repulse = -margin_distance * inv_dt + dot_v3v3(v1, collpair->normal);
+
+ if (margin_distance < -epsilon2) {
+ bounce = -v_nor_new + v_nor_old * restitution;
+ mul_v3_v3fl(impulse, collpair->normal, max_ff(repulse, bounce));
+ }
+ else {
+ bounce = 0.0f;
+ mul_v3_v3fl(impulse, collpair->normal, repulse);
+ }
+ cloth1->verts[collpair->ap1].impulse_count++;
+
+ result = true;
+ }
+
+ if (result) {
+ int i = 0;
+
+ for (i = 0; i < 3; i++) {
+ if (cloth1->verts[collpair->ap1].impulse_count > 0 && fabsf(cloth1->verts[collpair->ap1].impulse[i]) < fabsf(impulse[i]))
+ cloth1->verts[collpair->ap1].impulse[i] = impulse[i];
+ }
+ }
+ }
+ return result;
+}
+
+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[4])
+{
+ 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);
+
+ nor_v0p2 = dot_v3v3(v0p2, r_nor);
+ madd_v3_v3v3fl(p2face, p2, r_nor, -nor_v0p2);
+ interp_weights_face_v3(r_w, v0, v1, v2, NULL, p2face);
+
+ sub_v3_v3v3(p1p2, p2, p1);
+ sub_v3_v3v3(v0p2, p2, v0);
+ 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;
+
+#if 0 /* XXX this method uses the intersection point, but is broken and doesn't work well in general */
+ float p[3], vec1[3], line[3], edge1[3], edge2[3], q[3];
+ float a, f, u, v;
+
+ sub_v3_v3v3(edge1, v1, v0);
+ sub_v3_v3v3(edge2, v2, v0);
+ sub_v3_v3v3(line, p2, p1);
+
+ cross_v3_v3v3(p, line, edge2);
+ a = dot_v3v3(edge1, p);
+ if (a == 0.0f) return 0;
+ f = 1.0f / a;
+
+ sub_v3_v3v3(vec1, p1, v0);
+
+ u = f * dot_v3v3(vec1, p);
+ if ((u < 0.0f) || (u > 1.0f))
+ return false;
+
+ cross_v3_v3v3(q, vec1, edge1);
+
+ v = f * dot_v3v3(line, q);
+ if ((v < 0.0f) || ((u + v) > 1.0f))
+ return false;
+
+ *r_lambda = f * dot_v3v3(edge2, q);
+ /* don't care about 0..1 lambda range here */
+ /*if ((*r_lambda < 0.0f) || (*r_lambda > 1.0f))
+ * return 0;
+ */
+
+ r_w[0] = 1.0f - u - v;
+ r_w[1] = u;
+ r_w[2] = v;
+ r_w[3] = 0.0f;
+
+ cross_v3_v3v3(r_nor, edge1, edge2);
+ normalize_v3(r_nor);
+
+ return true;
+#endif
+}
+
+static CollPair *cloth_point_collpair(
+ float p1[3], 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[4];
+
+ 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);
+ }
+}
+
+static int cloth_points_objcollisions_resolve(ClothModifierData * clmd, CollisionModifierData *collmd, PartDeflect *pd,
+ CollPair *collisions, CollPair *collisions_index, float dt)
+{
+ Cloth *cloth = clmd->clothObject;
+ int i = 0, mvert_num = clmd->clothObject->mvert_num;
+ ClothVertex *verts = cloth->verts;
+ int ret = 0;
+
+ // process all collisions
+ if ( collmd->bvhtree ) {
+ bool result = cloth_points_collision_response_static(clmd, collmd, pd, collisions, collisions_index, dt);
+
+ // apply impulses in parallel
+ if (result) {
+ for (i = 0; i < mvert_num; i++) {
+ // calculate "velocities" (just xnew = xold + v; no dt in v)
+ if (verts[i].impulse_count) {
+ // VECADDMUL ( verts[i].tv, verts[i].impulse, 1.0f / verts[i].impulse_count );
+ VECADD ( verts[i].tv, verts[i].tv, verts[i].impulse);
+ zero_v3(verts[i].impulse);
+ verts[i].impulse_count = 0;
+
+ ret++;
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+// cloth - object collisions
+int cloth_points_objcollision(Object *ob, ClothModifierData *clmd, float step, float dt)
+{
+ Cloth *cloth= clmd->clothObject;
+ BVHTree *cloth_bvh;
+ int rounds = 0; // result counts applied collisions; ic is for debug output;
+ float round_dt = dt / (float)clmd->coll_parms->loop_count;
+ unsigned int i = 0, mvert_num = 0;
+ ClothVertex *verts = NULL;
+ int ret = 0, ret2 = 0;
+ Object **collobjs = NULL;
+ unsigned int numcollobj = 0;
+
+ verts = cloth->verts;
+ mvert_num = cloth->mvert_num;
+
+ ////////////////////////////////////////////////////////////
+ // static collisions
+ ////////////////////////////////////////////////////////////
+
+ // create temporary cloth points bvh
+ cloth_bvh = BLI_bvhtree_new(mvert_num, max_ff(clmd->coll_parms->epsilon, clmd->coll_parms->distance_repel), 4, 6);
+ /* fill tree */
+ for (i = 0; i < mvert_num; i++) {
+ float co[2][3];
+
+ copy_v3_v3(co[0], verts[i].x);
+ copy_v3_v3(co[1], verts[i].tx);
+
+ BLI_bvhtree_insert(cloth_bvh, i, co[0], 2);
+ }
+ /* balance tree */
+ BLI_bvhtree_balance(cloth_bvh);
+
+ collobjs = get_collisionobjects(clmd->scene, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision);
+ if (!collobjs)
+ return 0;
+
+ /* 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 );
+ }
+
+ do {
+ CollPair **collisions, **collisions_index;
+
+ ret2 = 0;
+
+ collisions = MEM_callocN(sizeof(CollPair *) *numcollobj, "CollPair");
+ collisions_index = MEM_callocN(sizeof(CollPair *) *numcollobj, "CollPair");
+
+ // check all collision objects
+ for (i = 0; i < numcollobj; i++) {
+ Object *collob= collobjs[i];
+ CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision);
+ BVHTreeOverlap *overlap = NULL;
+ unsigned int result = 0;
+ float epsilon;
+
+ if (!collmd->bvhtree)
+ continue;
+
+ /* search for overlapping collision pairs */
+ overlap = BLI_bvhtree_overlap(cloth_bvh, collmd->bvhtree, &result, NULL, NULL);
+ epsilon = BLI_bvhtree_getepsilon(collmd->bvhtree);
+
+ // go to next object if no overlap is there
+ if (result && overlap) {
+ /* check if collisions really happen (costly near check) */
+ cloth_points_objcollisions_nearcheck(clmd, collmd, &collisions[i], &collisions_index[i],
+ result, overlap, epsilon, round_dt);
+
+ // resolve nearby collisions
+ ret += cloth_points_objcollisions_resolve(clmd, collmd, collob->pd, collisions[i], collisions_index[i], round_dt);
+ ret2 += ret;
+ }
+
+ if (overlap)
+ MEM_freeN ( overlap );
+ }
+ rounds++;
+
+ for (i = 0; i < numcollobj; i++) {
+ if (collisions[i])
+ MEM_freeN(collisions[i]);
+ }
+
+ MEM_freeN(collisions);
+ MEM_freeN(collisions_index);
+
+ ////////////////////////////////////////////////////////////
+ // 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->flags & CLOTH_SIMSETTINGS_FLAG_GOAL ) {
+ if ( verts [i].flags & CLOTH_VERT_FLAG_PINNED ) {
+ continue;
+ }
+ }
+
+ VECADD ( verts[i].tx, verts[i].txold, verts[i].tv );
+ }
+ ////////////////////////////////////////////////////////////
+ }
+ while ( ret2 && ( clmd->coll_parms->loop_count>rounds ) );
+
+ if (collobjs)
+ MEM_freeN(collobjs);
+
+ BLI_bvhtree_free(cloth_bvh);
+
+ return 1|MIN2 ( ret, 1 );
+}
+
+void cloth_find_point_contacts(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
+ ////////////////////////////////////////////////////////////
+
+ // create temporary cloth points bvh
+ cloth_bvh = BLI_bvhtree_new(mvert_num, max_ff(clmd->coll_parms->epsilon, clmd->coll_parms->distance_repel), 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);
+
+ collobjs = get_collisionobjects(clmd->scene, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision);
+ if (!collobjs) {
+ *r_collider_contacts = NULL;
+ *r_totcolliders = 0;
+ return;
+ }
+
+ /* 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 );
+ }
+
+ 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_getepsilon(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
+// ret += cloth_points_objcollisions_resolve(clmd, collmd, collob->pd, collisions[i], collisions_index[i], dt);
+ }
+
+ if (overlap)
+ MEM_freeN(overlap);
+ }
+
+ if (collobjs)
+ MEM_freeN(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->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) {
+ if (verts [i].flags & CLOTH_VERT_FLAG_PINNED) {
+ continue;
+ }
+ }
+
+ VECADD(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);
+ }
+}