[Bf-blender-cvs] [9cfeca0] hair_system: Basic collision response for hairs with other objects.

Lukas Tönne noreply at git.blender.org
Thu Aug 7 23:00:01 CEST 2014


Commit: 9cfeca0d7cac6426dd484c9ec0b4ffc5bac5b2cc
Author: Lukas Tönne
Date:   Thu Aug 7 22:59:10 2014 +0200
Branches: hair_system
https://developer.blender.org/rB9cfeca0d7cac6426dd484c9ec0b4ffc5bac5b2cc

Basic collision response for hairs with other objects.

This only includes a restitution force atm, so the hair just slides
sideways over meshes. Friction forces and detailed collision settings
still have to be added for giving more control.

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

M	source/blender/hair/intern/HAIR_collision.cpp
M	source/blender/hair/intern/HAIR_curve.h
M	source/blender/hair/intern/HAIR_solver.cpp
M	source/blender/hair/intern/HAIR_solver.h

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

diff --git a/source/blender/hair/intern/HAIR_collision.cpp b/source/blender/hair/intern/HAIR_collision.cpp
index 6962cf0..ff3c26c 100644
--- a/source/blender/hair/intern/HAIR_collision.cpp
+++ b/source/blender/hair/intern/HAIR_collision.cpp
@@ -36,7 +36,8 @@ extern "C" {
 
 HAIR_NAMESPACE_BEGIN
 
-PointContactInfo::PointContactInfo(const btManifoldPoint &bt_point) :
+PointContactInfo::PointContactInfo(const btManifoldPoint &bt_point, int point_index) :
+    point_index(point_index),
     local_point_body(bt_point.m_localPointB.m_floats),
     local_point_hair(bt_point.m_localPointA),
     world_point_body(bt_point.m_positionWorldOnB),
@@ -50,7 +51,8 @@ PointContactInfo::PointContactInfo(const btManifoldPoint &bt_point) :
 
 struct HairContactResultCallback : btCollisionWorld::ContactResultCallback {
 	HairContactResultCallback(PointContactCache &cache) :
-	    m_cache(&cache)
+	    cache(&cache),
+	    point_index(0)
 	{
 	}
 
@@ -59,11 +61,21 @@ struct HairContactResultCallback : btCollisionWorld::ContactResultCallback {
 	                         const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1)
 	{
 		if (cp.getDistance() < 0.f) {
-			m_cache->push_back(PointContactInfo(cp));
+			PointContactInfo info(cp, point_index);
 			
-			const btVector3 &ptA = cp.getPositionWorldOnA();
-			const btVector3 &ptB = cp.getPositionWorldOnB();
-			Debug::collision_contact(float3(ptA.x(), ptA.y(), ptA.z()), float3(ptB.x(), ptB.y(), ptB.z()));
+			const btCollisionObject *ob1 = colObj1Wrap->getCollisionObject();
+			
+			float3 lin_vel(ob1->getInterpolationLinearVelocity().m_floats);
+			float3 ang_vel(ob1->getInterpolationAngularVelocity().m_floats);
+			float3 p((ob1->getWorldTransform() * cp.m_localPointB).m_floats);
+			
+			info.world_vel_body = dot_v3v3(lin_vel + cross_v3_v3(ang_vel, p), info.world_normal_body) * info.world_normal_body;
+			
+			cache->push_back(info);
+			
+//			const btVector3 &ptA = cp.getPositionWorldOnA();
+//			const btVector3 &ptB = cp.getPositionWorldOnB();
+//			Debug::collision_contact(float3(ptA.x(), ptA.y(), ptA.z()), float3(ptB.x(), ptB.y(), ptB.z()));
 		}
 		
 		/* note: return value is unused
@@ -72,9 +84,46 @@ struct HairContactResultCallback : btCollisionWorld::ContactResultCallback {
 		return 0.0f;
 	}
 	
-	PointContactCache *m_cache;
+	PointContactCache *cache;
+	int point_index;
 };
 
+void Solver::cache_point_contacts(PointContactCache &cache) const
+{
+	btDynamicsWorld *dworld = m_forces.dynamics_world->dynamicsWorld;
+	btPairCachingGhostObject *ghost = &m_data->rb_ghost.ghost;
+	
+//	btManifoldArray manifold_array;
+	const btBroadphasePairArray& pairs = ghost->getOverlappingPairCache()->getOverlappingPairArray();
+	int num_pairs = pairs.size();
+	
+	cache.reserve(num_pairs);
+	
+	for (int i = 0; i < num_pairs; i++) {
+//		manifold_array.clear();
+		
+		const btBroadphasePair& pair = pairs[i];
+		
+		/* unless we manually perform collision detection on this pair, the contacts are in the dynamics world paircache */
+		btBroadphasePair* collision_pair = dworld->getPairCache()->findPair(pair.m_pProxy0,pair.m_pProxy1);
+		if (!collision_pair)
+			continue;
+		
+		btCollisionObject *ob0 = (btCollisionObject *)pair.m_pProxy0->m_clientObject;
+		btCollisionObject *ob1 = (btCollisionObject *)pair.m_pProxy1->m_clientObject;
+		btCollisionObject *other = ob0 == ghost ? ob1 : ob0;
+		
+		HairContactResultCallback cb(cache);
+		
+		Point *point = m_data->points;
+		int totpoints = m_data->totpoints;
+		for (int k = 0; k < totpoints; ++k, ++point) {
+			cb.point_index = k;
+			dworld->contactPairTest(&point->rb_ghost.ghost, other, cb);
+		}
+	}
+}
+
 #if 0
 struct HairContactResultCallback : btCollisionWorld::ContactResultCallback {
 	btScalar addSingleResult(btManifoldPoint &cp,
@@ -186,40 +235,4 @@ void SolverData::debug_contacts(rbDynamicsWorld *world)
 }
 #endif
 
-
-void Solver::cache_point_contacts(PointContactCache &cache) const
-{
-	btDynamicsWorld *dworld = m_forces.dynamics_world->dynamicsWorld;
-	btPairCachingGhostObject *ghost = &m_data->rb_ghost.ghost;
-	
-//	btManifoldArray manifold_array;
-	const btBroadphasePairArray& pairs = ghost->getOverlappingPairCache()->getOverlappingPairArray();
-	int num_pairs = pairs.size();
-	
-	cache.reserve(num_pairs);
-	
-	for (int i = 0; i < num_pairs; i++) {
-//		manifold_array.clear();
-		
-		const btBroadphasePair& pair = pairs[i];
-		
-		/* unless we manually perform collision detection on this pair, the contacts are in the dynamics world paircache */
-		btBroadphasePair* collision_pair = dworld->getPairCache()->findPair(pair.m_pProxy0,pair.m_pProxy1);
-		if (!collision_pair)
-			continue;
-		
-		btCollisionObject *ob0 = (btCollisionObject *)pair.m_pProxy0->m_clientObject;
-		btCollisionObject *ob1 = (btCollisionObject *)pair.m_pProxy1->m_clientObject;
-		btCollisionObject *other = ob0 == ghost ? ob1 : ob0;
-		
-		HairContactResultCallback cb(cache);
-		
-		Point *point = m_data->points;
-		int totpoints = m_data->totpoints;
-		for (int k = 0; k < totpoints; ++k, ++point) {
-			dworld->contactPairTest(&point->rb_ghost.ghost, other, cb);
-		}
-	}
-}
-
 HAIR_NAMESPACE_END
diff --git a/source/blender/hair/intern/HAIR_curve.h b/source/blender/hair/intern/HAIR_curve.h
index ca75700..4bf9ea2 100644
--- a/source/blender/hair/intern/HAIR_curve.h
+++ b/source/blender/hair/intern/HAIR_curve.h
@@ -52,6 +52,7 @@ struct Point {
 	
 	State cur;
 	State next;
+	float3 force_accum; /* accumulated external forces */
 	
 	float3 rest_co;
 	float3 rest_bend;
diff --git a/source/blender/hair/intern/HAIR_solver.cpp b/source/blender/hair/intern/HAIR_solver.cpp
index a1f2fa2..d0e85bc 100644
--- a/source/blender/hair/intern/HAIR_solver.cpp
+++ b/source/blender/hair/intern/HAIR_solver.cpp
@@ -256,16 +256,11 @@ static float3 calc_bend_damping(const HairParams &params, const Point *point0, c
 	return params.bend_damping * (dvel - dot_v3v3(dvel, dir) * dir);
 }
 
-static float3 calc_collision_force()
-{
-	return float3(0.0f, 0.0f, 0.0f);
-}
-
 struct SolverTaskData {
 	Curve *curves;
 	Point *points;
-	int totcurves;
-	int totpoints;
+	int startcurve, totcurves;
+	int startpoint, totpoints;
 };
 
 static void do_internal_forces(const HairParams &params, const SolverForces &forces, float time, float timestep, const Point *point0, const Point *point1, const Frame &frame,
@@ -318,15 +313,63 @@ static void do_damping(const HairParams &params, const SolverForces &forces, flo
 	}
 }
 
+static void do_collision(const HairParams &params, const SolverForces &forces, float time, float timestep, const SolverTaskData &data, const PointContactCache &contacts)
+{
+	int start = data.startpoint;
+	int end = start + data.totpoints;
+	
+	/* XXX there could be a bit of overhead here since we skip points that are not in the task point range.
+	 * contacts could be sorted by point index to avoid this, but the sorting might actually be more costly than it's worth ...
+	 */
+	for (int i = 0; i < contacts.size(); ++i) {
+		const PointContactInfo &info = contacts[i];
+		
+		if (info.point_index < start || info.point_index >= end)
+			continue;
+		
+		Point *point = data.points + (info.point_index - start);
+		
+		/* Collision response based on
+		 * "Simulating Complex Hair with Robust Collision Handling"
+		 * Choe, Choi, Ko 2005
+		 * http://graphics.snu.ac.kr/publications/2005-choe-HairSim/Choe_2005_SCA.pdf
+		 */
+		
+		/* XXX we don't have a nice way of handling deformation velocity yet,
+		 * assume constant linear/rotational velocity for now
+		 */
+		float3 obj_v0 = info.world_vel_body;
+		float3 obj_v1 = obj_v0;
+		float3 v0 = point->cur.vel;
+		if (dot_v3v3(v0, info.world_normal_body) < 0.0f) {
+			/* estimate for velocity change to prevent collision (3.2, (8)) */
+			float3 dv_a = dot_v3v3(info.restitution * (obj_v0 - v0) + (obj_v1 - v0), info.world_normal_body) * info.world_normal_body;
+			
+			point->force_accum = point->force_accum + dv_a / timestep;
+//			Debug::collision_contact(point->cur.co, point->cur.co + point->force_accum);
+		}
+	}
+}
+
 void Solver::do_integration(float time, float timestep, const SolverTaskData &data) const
 {
 	const int totsteps = 1; /* XXX TODO can have multiple integration steps per tick for accuracy */
 	float dt = timestep / (float)totsteps;
 	
+	int totcurve = data.totcurves;
+	/*int totpoint = data.totpoints;*/
+	
+	PointContactCache contacts;
+	cache_point_contacts(contacts);
+	
 	for (int step = 0; step < totsteps; ++step) {
 		
-		int totcurve = data.totcurves;
-		/*int totpoint = data.totpoints;*/
+		/* clear forces */
+		for (int k = 0; k < data.totpoints; ++k) {
+			data.points[k].force_accum = float3(0.0f, 0.0f, 0.0f);
+		}
+		
+		do_collision(m_params, m_forces, time, dt, data, contacts);
 		
 		int ktot = 0; /* global point counter over all curves */
 		Curve *curve = data.curves;
@@ -371,7 +414,7 @@ void Solver::do_integration(float time, float timestep, const SolverTaskData &da
 				do_external_forces(m_params, m_forces, time, dt, point, point_next, frame_iter.frame(), extern_force);
 				do_damping(m_params, m_forces, time, dt, point, point_next, frame_iter.frame(), damping, damping_next);
 				
-				float3 acc = intern_force + extern_force + damping + acc_prev;
+				float3 acc = intern_force + extern_force + damping + acc_prev + point->force_accum;
 				point->next.vel = point->cur.vel + acc * timestep;
 				
 				float3 vel = point->next.vel;
@@ -449,6 +492,8 @@ void Solver::step_threaded(float time, float timestep)
 			SolverTaskData solver_task;
 			solver_task.curves = m_data->curves + hair_start;
 			solver_task.points = m_data->points + point_start;
+			solver_task.startcurve = hair_start;
+			solver_task.startpoint = point_start;
 			solver_task.totcurves = num_hairs;
 			solver_task.totpoints = num_points;
 			taskdata.push_back(solver_task);
diff --git a/source/blender/hair/intern/HAIR_solver.h b/source/blender/hair/intern/HAIR_solver.h
index cf5e7ce..ad6874a 100644
--- a/source/blender/hair/intern/HAIR_solver.h
+++ b/source/blender/hair/intern/HAIR_solver.h
@@ -129,7 +129,9 @@ struct SolverForces {
 
 struct PointContactInfo {
 	PointContactInfo() {}
-	PointContactInfo(const btManifoldPoint &bt_point);
+	PointContactInfo(const btManifo

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list