[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 ¶ms, 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 ¶ms, 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 ¶ms, const SolverForces &forces, flo
}
}
+static void do_collision(const HairParams ¶ms, 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