[Bf-blender-cvs] [0607cd2e15] cloth-improvements: Replace plNearestPoints with a deticated solution

Luca Rood noreply at git.blender.org
Sat Mar 4 06:22:38 CET 2017


Commit: 0607cd2e15cc54692c7eed01500f6098dbaf1722
Author: Luca Rood
Date:   Sat Mar 4 00:24:35 2017 -0300
Branches: cloth-improvements
https://developer.blender.org/rB0607cd2e15cc54692c7eed01500f6098dbaf1722

Replace plNearestPoints with a deticated solution

Implement a dedicated collision detection function (was previously
relying on Bullet's generic `plNearestPoints`).
This function computes all the collision data to be used for response:
coordinates, distance, direction vector.

This new function has three advantages:

* Remove a dependency from cloth simulation (Bullet).
* Give more pleasing collision results (this function is tailored
specifically for our collision response method).
* Much faster computation (not benchmarked extensively, but observed
overal simulation time was cut roughly in half with "collision-heavy"
simulations).

===================================================================

M	source/blender/blenkernel/BKE_collision.h
M	source/blender/blenkernel/intern/collision.c

===================================================================

diff --git a/source/blender/blenkernel/BKE_collision.h b/source/blender/blenkernel/BKE_collision.h
index 8fedcd4ab0..6a859c0058 100644
--- a/source/blender/blenkernel/BKE_collision.h
+++ b/source/blender/blenkernel/BKE_collision.h
@@ -72,7 +72,7 @@ typedef enum {
 typedef struct CollPair {
 	unsigned int face1; // cloth face
 	unsigned int face2; // object face
-	double distance; // magnitude of vector
+	float distance;
 	float normal[3];
 	float vector[3]; // unnormalized collision vector: p2-p1
 	float pa[3], pb[3]; // collision point p1 on face1, p2 on face2
diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c
index 2f3968ec92..64215a2b63 100644
--- a/source/blender/blenkernel/intern/collision.c
+++ b/source/blender/blenkernel/intern/collision.c
@@ -49,9 +49,6 @@
 #include "BKE_modifier.h"
 #include "BKE_scene.h"
 
-#ifdef WITH_BULLET
-#include "Bullet-C-Api.h"
-#endif
 #include "BLI_kdopbvh.h"
 #include "BKE_collision.h"
 
@@ -177,6 +174,236 @@ void bvhtree_update_from_mvert(
 Collision modifier code end
 ***********************************/
 
+static void clamp_point_seg(float a[3], float b[3], float p[3])
+{
+	float ap[3], bp[3], ab[3];
+
+	sub_v3_v3v3(ap, p, a);
+	sub_v3_v3v3(bp, p, b);
+	sub_v3_v3v3(ab, b, a);
+
+	if (dot_v3v3(ap, bp) > 0.0f) {
+		if (dot_v3v3(ap, ab) > 0.0f) {
+			copy_v3_v3(p, b);
+		}
+		else {
+			copy_v3_v3(p, a);
+		}
+	}
+}
+
+static bool isect_seg_seg(float a1[3], float a2[3], float b1[3], float b2[3], float r_a[3], float r_b[3])
+{
+	if (isect_line_line_v3(a1, a2, b1, b2, r_a, r_b)) {
+		clamp_point_seg(a1, a2, r_a);
+		clamp_point_seg(b1, b2, r_b);
+
+		return true;
+	}
+
+	return false;
+}
+
+BLI_INLINE int next_ind(int i)
+{
+	return (++i < 3) ? i : 0;
+}
+
+static float compute_collision_point(float a1[3], float a2[3], float a3[3], float b1[3], float b2[3], 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];
+	float dist;
+	float mindist = FLT_MAX;
+	float tmp_co1[3], tmp_co2[3];
+	float isect_a[3], isect_b[3];
+	int isect_count = 0;
+	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(a[2], a3);
+
+	copy_v3_v3(b[0], b1);
+	copy_v3_v3(b[1], b2);
+	copy_v3_v3(b[2], b3);
+
+	/* Find intersections */
+	for (int i = 0; i < 3; i++) {
+		if (isect_line_segment_tri_v3(a[i], a[next_ind(i)], b[0], b[1], b[2], &tmp, NULL)) {
+			interp_v3_v3v3(isect_a, a[i], a[next_ind(i)], tmp);
+			isect_count++;
+		}
+	}
+
+	if (isect_count == 0) {
+		for (int i = 0; i < 3; i++) {
+			if (isect_line_segment_tri_v3(b[i], b[next_ind(i)], a[0], a[1], a[2], &tmp, NULL)) {
+				isect_count++;
+			}
+		}
+	}
+	else if (isect_count == 1) {
+		for (int i = 0; i < 3; i++) {
+			if (isect_line_segment_tri_v3(b[i], b[next_ind(i)], a[0], a[1], a[2], &tmp, NULL)) {
+				interp_v3_v3v3(isect_b, b[i], b[next_ind(i)], tmp);
+				break;
+			}
+		}
+	}
+
+	/* Determine collision side */
+	if (culling) {
+		normal_tri_v3(normal, b[0], b[1], b[2]);
+		cent_tri_v3(cent, b[0], b[1], b[2]);
+
+		if (isect_count == 2) {
+			backside = true;
+		}
+		else if (isect_count == 0) {
+			for (int i = 0; i < 3; i++) {
+				sub_v3_v3v3(tmp_vec, a[i], cent);
+				if (dot_v3v3(tmp_vec, normal) < 0.0f) {
+					backside = true;
+					break;
+				}
+			}
+		}
+	}
+
+	if (isect_count == 1) {
+		/* Edge intersection */
+		copy_v3_v3(r_a, isect_a);
+		copy_v3_v3(r_b, isect_b);
+
+		sub_v3_v3v3(r_vec, r_b, r_a);
+
+		return 0.0f;
+	}
+	else if (backside) {
+		float maxdist = 0.0f;
+		bool found = false;
+
+		/* Point projections */
+		for (int i = 0; i < 3; 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;
+				}
+			}
+		}
+
+		negate_v3(normal);
+
+		for (int i = 0; i < 3; i++) {
+			if (isect_ray_tri_v3(b[i], normal, a[0], a[1], a[2], &tmp, NULL)) {
+				if (tmp > maxdist) {
+					maxdist = tmp;
+					madd_v3_v3v3fl(r_a, b[i], normal, tmp);
+					copy_v3_v3(r_b, b[i]);
+					found = true;
+				}
+			}
+		}
+
+		negate_v3(normal);
+
+		/* 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);
+
+			for (int j = 0; j < 3; j++) {
+				if (isect_line_plane_v3(tmp_co1, a[j], a[next_ind(j)], b[i], dir) &&
+				    point_in_slice_seg(tmp_co1, a[j], a[next_ind(j)]) &&
+				    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);
+
+			return 0.0f;
+		}
+	}
+
+	/* Closest point */
+	for (int i = 0; i < 3; 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 < mindist) {
+			mindist = tmp;
+			copy_v3_v3(r_a, a[i]);
+			copy_v3_v3(r_b, tmp_co1);
+		}
+	}
+
+	for (int i = 0; i < 3; i++) {
+		closest_on_tri_to_point_v3(tmp_co1, b[i], a[0], a[1], a[2]);
+		tmp = len_squared_v3v3(tmp_co1, b[i]);
+
+		if (tmp < mindist) {
+			mindist = tmp;
+			copy_v3_v3(r_a, tmp_co1);
+			copy_v3_v3(r_b, b[i]);
+		}
+	}
+
+	/* Closest edge */
+	if (isect_count == 0) {
+		for (int i = 0; i < 3; i++) {
+			for (int j = 0; j < 3; j++) {
+				if (isect_seg_seg(a[i], a[next_ind(i)], b[j], b[next_ind(j)], tmp_co1, tmp_co2)) {
+					tmp = len_squared_v3v3(tmp_co1, tmp_co2);
+
+					if (tmp < mindist) {
+						mindist = tmp;
+						copy_v3_v3(r_a, tmp_co1);
+						copy_v3_v3(r_b, tmp_co2);
+					}
+				}
+			}
+		}
+	}
+
+	if (isect_count == 0) {
+		sub_v3_v3v3(r_vec, r_a, r_b);
+		dist = sqrtf(mindist);
+	}
+	else {
+		sub_v3_v3v3(r_vec, r_b, r_a);
+		dist = 0.0f;
+	}
+
+	if (culling && (dot_v3v3(r_vec, normal) < 0.0f)) {
+		return FLT_MAX;
+	}
+
+	return dist;
+}
+
 static void free_impulse_clusters(ImpulseCluster *clusters)
 {
 	while (clusters) {
@@ -396,8 +623,6 @@ static int cloth_collision_response_static (ClothModifierData *clmd, CollisionMo
 	float v1[3], v2[3], relativeVelocity[3];
 	float magrelVel;
 	float epsilon2 = BLI_bvhtree_get_epsilon ( collmd->bvhtree );
-	float collider_norm[3];
-	bool backside;
 
 	cloth1 = clmd->clothObject;
 
@@ -426,34 +651,6 @@ static int cloth_collision_response_static (ClothModifierData *clmd, CollisionMo
 			collmd->current_x[collpair->bp3].co,
 			&u1, &u2, &u3 );
 
-		/* compute collision normal */
-		if (collob->pd->flag & PFIELD_CLOTH_USE_NORMAL) {
-			normal_tri_v3(collider_norm, collmd->current_x[collpair->bp1].co, collmd->current_x[collpair->bp2].co, collmd->current_x[collpair->bp3].co);
-			backside = dot_v3v3(collider_norm, collpair->normal) < 0.0f;
-
-			if (!(collob->pd->flag & PFIELD_CLOTH_USE_CULLING) && backside) {
-				negate_v3(collider_norm);
-				backside = false;
-			}
-		}
-		else {
-			copy_v3_v3(collider_norm, collpair->normal);
-
-			if (collob->pd->flag & PFIELD_CLOTH_USE_CULLING) {
-				float tmp_norm[3];
-
-				normal_tri_v3(tmp_norm, collmd->current_x[collpair->bp1].co, collmd->current_x[collpair->bp2].co, collmd->current_x[collpair->bp3].co);
-				backside = dot_v3v3(collider_norm, tmp_norm) < 0.0f;
-
-				if (backside) {
-					negate_v3(collider_norm);
-				}
-			}
-			else {
-				backside = false;
-			}
-		}
-
 		/* Calculate relative "velocity". */
 		collision_interpolateOnTriangle ( v1, cloth1->verts[collpair->ap1].tv, cloth1->verts[collpair->ap2].tv, cloth1->verts[collpair->ap3].tv, w1, w2, w3 );
 
@@ -462,7 +659,7 @@ static int cloth_collision_response_static (ClothModifierData *clmd, CollisionMo
 		sub_v3_v3v3(relativeVelocity, v2, v1);
 
 		/* Calculate the normal component of the relative velocity (actually only the magnitude - the direction is stored in 'normal'). */
-		magrelVel = dot_v3v3(relativeVelocity, collider_norm);
+		magrelVel = dot_v3v3(relativeVelocity, collpair->normal);
 
 		/* printf("magrelVel: %f\n", magrelVel); */
 
@@ -478,7 +675,7 @@ static int cloth_collision_response_static (ClothModifierData *clmd, CollisionMo
 			float temp[3], time_multiplier;
 
 			/* calculate tangential velocity */
-			copy_v3_v3 ( temp, collider_norm );
+			copy_v3_v3(temp, collpair->normal);
 			mul_v3_fl(temp, magrelVel);
 			sub_v3_v3v3(vrel_t_pre, relativeVelocity, temp);
 
@@ -508,38 +705,14 @@ static int cloth_collision_response_static (ClothModifierData *clmd, CollisionMo
 			/* Impulse should be uniform throughout polygon, the scaling used above was wrong */
 			impulse =  magrelVel / 1.5f;
 
-			if (backside) {
-				float pt_relvel[3];
-				float pt_magvel;
-
-				sub_v3_v3v3(pt_relvel, v2, cloth1->verts[collpair->ap1].tv);
-				pt_magvel = dot_v3v3(pt_relvel, collider_norm);
-
-				VECADDMUL ( i1, collider_norm, pt_magvel * 0.25f );
-				cloth1->verts[collpair->ap1].impulse_count++;
-
-				sub_v3_v3v3(pt_relvel, v2, cloth1->verts[collpair->ap2].tv);
-				pt_magvel = dot_v3v3(pt_relvel, collider_norm);
-
-				VECADDMUL ( i2, collider_norm, pt_magvel * 0.25f );
-				cloth1->verts[collpair->ap2].impulse_count++;
-
-				sub_v3_v3v3(pt_relvel, v2, cloth1->verts[collpair->ap3].tv);
-				pt_magvel = dot_v3v3(pt_relvel, collider_norm);
-
-				VECADDMUL ( i3, collider_norm, pt_magvel * 0.25f );
-				cloth1->verts[collpair->ap3].impulse_count++;
-			}
-			else {
-				VECADDMUL ( i1, collider_norm, w1 * impulse );
-				cloth1->verts[collpair->ap1].impulse_count++;
+			VECADDMUL ( i1, collpair->normal, w1 * impulse );
+			cloth1->verts[collpair->ap1].impulse_count++;
 
-				VECADDMUL ( i2, collider_norm, w2 * impulse );
-				cloth1->verts[collpair->ap2].impulse_count++;
+			VECADDMUL ( i2, collpair->normal, w2 * impulse );
+			cloth1->verts[collpair->ap2].impulse_count

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list