Logo Search packages:      
Sourcecode: blender version File versions

void SM_Object::dynamicCollision ( const MT_Point3 local2,
const MT_Vector3 normal,
MT_Scalar  dist,
const MT_Vector3 rel_vel,
MT_Scalar  restitution,
MT_Scalar  friction_factor,
MT_Scalar  invMass 
) [private]

dynamicCollision computes the response to a collision.

Parameters:
local2 the contact point in local coordinates.
normal the contact normal.
dist the penetration depth of the contact. (unused)
rel_vel the relative velocity of the objects
restitution the amount of momentum conserved in the collision. Range: 0.0 - 1.0
friction_factor the amount of friction between the two surfaces.
invMass the inverse mass of the collision objects (1.0 / mass)

rel_vel_normal is the relative velocity in the contact normal direction.

if rel_vel_normal > 0, the objects are moving apart!

if rel_vel_normal < ImpulseThreshold, scale the restitution down. This should improve the simulation where the object is stacked.

Apply impulse at the collision point. Take rotational inertia into account.

Apply impulse through object centre. (no rotation.)

The friction part starts here!!!!!!!!

Compute the lateral component of the relative velocity lateral actually points in the opposite direction, i.e., into the direction of the friction force.

For anisotropic friction we scale the lateral component, rather than compute a direction-dependent fricition factor. For this the lateral component is transformed to local coordinates.

We cannot use m_xform.getBasis() for the matrix, since it might contain a non-uniform scaling. OPT: it's a bit daft to compute the matrix since the quaternion itself can be used to do the transformation.

lcs is orthogonal so lcs.inversed() == lcs.transposed(), and lcs.transposed() * lateral == lateral * lcs.

A tiny Coulomb friction primer: The Coulomb friction law states that the magnitude of the maximum possible friction force depends linearly on the magnitude of the normal force.

\[ F_max_friction = friction_factor * F_normal \]

(NB: independent of the contact area!!)

The friction factor depends on the material. We use impulses rather than forces but let us not be bothered by this.

Here's the trick. We compute the impulse to make the lateral velocity zero. (Make the objects stick together at the contact point. If this impulse is larger than the maximum possible friction impulse, then shrink its magnitude to the maximum friction.

For rigid bodies we take the inertia into account, since the friction impulse is going to change the angular momentum as well.

Definition at line 175 of file SM_Object.cpp.

References applyCenterImpulse(), applyImpulse(), MT_Vector3::cross(), MT_Vector3::dot(), ImpulseThreshold, MT_Vector3::length(), SM_ShapeProps::m_do_anisotropic, SM_ShapeProps::m_friction_scaling, and MT_Vector3::scale().

{
      /**
       * rel_vel_normal is the relative velocity in the contact normal direction.
       */
      MT_Scalar  rel_vel_normal = normal.dot(rel_vel);
                  
      /**
       * if rel_vel_normal > 0, the objects are moving apart! 
       */
      if (rel_vel_normal < 0.) {
            /**
             * if rel_vel_normal < ImpulseThreshold, scale the restitution down.
             * This should improve the simulation where the object is stacked.
             */
            restitution *= MT_min(MT_Scalar(1.0), rel_vel_normal/ImpulseThreshold);
                        
            MT_Scalar impulse = -(1.0 + restitution) * rel_vel_normal;
            
            if (isRigidBody())
            {
                  MT_Vector3 temp = getInvInertiaTensor() * local2.cross(normal);
                  impulse /= invMass + normal.dot(temp.cross(local2));
                  
                  /**
                   * Apply impulse at the collision point.
                   * Take rotational inertia into account.
                   */
                  applyImpulse(local2 + getPosition(), impulse * normal);
            } else {
                  /**
                   * Apply impulse through object centre. (no rotation.)
                   */
                  impulse /= invMass;
                  applyCenterImpulse( impulse * normal ); 
            }
            
            MT_Vector3 external = m_combined_lin_vel + m_combined_ang_vel.cross(local2);
            MT_Vector3 lateral =  rel_vel - external - normal * (rel_vel_normal - external.dot(normal));
#if 0
            // test - only do friction on the physics part of the 
            // velocity.
            vel1  -= obj1->m_combined_lin_vel;
            vel2  -= obj2->m_combined_lin_vel;

            // This should look familiar....
            rel_vel        = vel2 - vel1;
            rel_vel_normal = normal.dot(rel_vel);
#endif
            /**
             * The friction part starts here!!!!!!!!
                 *
             * Compute the lateral component of the relative velocity
             * lateral actually points in the opposite direction, i.e.,
             * into the direction of the friction force.
             */
            if (m_shapeProps->m_do_anisotropic) {

                  /**
                   * For anisotropic friction we scale the lateral component,
                   * rather than compute a direction-dependent fricition 
                   * factor. For this the lateral component is transformed to
                   * local coordinates.
                   */

                  MT_Matrix3x3 lcs(m_orn);
                  
                  /**
                   * We cannot use m_xform.getBasis() for the matrix, since 
                   * it might contain a non-uniform scaling. 
                   * OPT: it's a bit daft to compute the matrix since the 
                   * quaternion itself can be used to do the transformation.
                   */
                  MT_Vector3 loc_lateral = lateral * lcs;
                  
                  /**
                   * lcs is orthogonal so lcs.inversed() == lcs.transposed(),
                   * and lcs.transposed() * lateral == lateral * lcs.
                   */
                  const MT_Vector3& friction_scaling = 
                        m_shapeProps->m_friction_scaling; 

                  // Scale the local lateral...
                  loc_lateral.scale(friction_scaling[0], 
                                          friction_scaling[1], 
                                          friction_scaling[2]);
                  // ... and transform it back to global coordinates
                  lateral = lcs * loc_lateral;
            }
                  
            /**
             * A tiny Coulomb friction primer:
             * The Coulomb friction law states that the magnitude of the
             * maximum possible friction force depends linearly on the 
             * magnitude of the normal force.
             *
             * \f[
                 F_max_friction = friction_factor * F_normal 
               \f]
             *
             * (NB: independent of the contact area!!)
             *
             * The friction factor depends on the material. 
             * We use impulses rather than forces but let us not be 
             * bothered by this. 
             */
            MT_Scalar  rel_vel_lateral = lateral.length();

            if (rel_vel_lateral > MT_EPSILON) {
                  lateral /= rel_vel_lateral;

                  // Compute the maximum friction impulse
                  MT_Scalar max_friction = 
                        friction_factor * MT_max(MT_Scalar(0.0), impulse);

                  // I guess the GEN_max is not necessary, so let's check it

                  assert(impulse >= 0.0);

                  /**
                   * Here's the trick. We compute the impulse to make the
                   * lateral velocity zero. (Make the objects stick together
                   * at the contact point. If this impulse is larger than
                   * the maximum possible friction impulse, then shrink its
                   * magnitude to the maximum friction.
                   */

                  if (isRigidBody()) {
                              
                        /**
                         * For rigid bodies we take the inertia into account, 
                         * since the friction impulse is going to change the
                         * angular momentum as well.
                         */
                        MT_Vector3 temp = getInvInertiaTensor() * local2.cross(lateral);
                        MT_Scalar impulse_lateral = rel_vel_lateral /
                              (invMass + lateral.dot(temp.cross(local2)));

                        MT_Scalar friction = MT_min(impulse_lateral, max_friction);
                        applyImpulse(local2 + getPosition(), -lateral * friction);
                  }
                  else {
                        MT_Scalar impulse_lateral = rel_vel_lateral / invMass;

                        MT_Scalar friction = MT_min(impulse_lateral, max_friction);
                        applyCenterImpulse( -friction * lateral);
                  }
                        

            }     

            //calcXform();
            //notifyClient();

      }
}


Generated by  Doxygen 1.6.0   Back to index