Package com.bulletphysics.dynamics.constraintsolver

Source Code of com.bulletphysics.dynamics.constraintsolver.ContactConstraint

/*
* Java port of Bullet (c) 2008 Martin Dvorak <jezek2@advel.cz>
*
* Bullet Continuous Collision Detection and Physics Library
* Copyright (c) 2003-2008 Erwin Coumans  http://www.bulletphysics.com/
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
*    claim that you wrote the original software. If you use this software
*    in a product, an acknowledgment in the product documentation would be
*    appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
*    misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/

package com.bulletphysics.dynamics.constraintsolver;

import com.bulletphysics.BulletGlobals;
import com.bulletphysics.util.ObjectPool;
import com.bulletphysics.collision.narrowphase.ManifoldPoint;
import com.bulletphysics.dynamics.RigidBody;
import com.bulletphysics.linearmath.Transform;
import cz.advel.stack.Stack;
import javax.vecmath.Matrix3f;
import javax.vecmath.Vector3f;

/**
* Functions for resolving contacts.
*
* @author jezek2
*/
public class ContactConstraint {
 
  public static final ContactSolverFunc resolveSingleCollision = new ContactSolverFunc() {
    public float resolveContact(RigidBody body1, RigidBody body2, ManifoldPoint contactPoint, ContactSolverInfo info) {
      return resolveSingleCollision(body1, body2, contactPoint, info);
    }
  };

  public static final ContactSolverFunc resolveSingleFriction = new ContactSolverFunc() {
    public float resolveContact(RigidBody body1, RigidBody body2, ManifoldPoint contactPoint, ContactSolverInfo info) {
      return resolveSingleFriction(body1, body2, contactPoint, info);
    }
  };

  public static final ContactSolverFunc resolveSingleCollisionCombined = new ContactSolverFunc() {
    public float resolveContact(RigidBody body1, RigidBody body2, ManifoldPoint contactPoint, ContactSolverInfo info) {
      return resolveSingleCollisionCombined(body1, body2, contactPoint, info);
    }
  };
 
  /**
   * Bilateral constraint between two dynamic objects.
   */
  public static void resolveSingleBilateral(RigidBody body1, Vector3f pos1,
      RigidBody body2, Vector3f pos2,
      float distance, Vector3f normal, float[] impulse, float timeStep) {
    float normalLenSqr = normal.lengthSquared();
    assert (Math.abs(normalLenSqr) < 1.1f);
    if (normalLenSqr > 1.1f) {
      impulse[0] = 0f;
      return;
    }

    ObjectPool<JacobianEntry> jacobiansPool = ObjectPool.get(JacobianEntry.class);
    Vector3f tmp = Stack.alloc(Vector3f.class);
   
    Vector3f rel_pos1 = Stack.alloc(Vector3f.class);
    rel_pos1.sub(pos1, body1.getCenterOfMassPosition(tmp));

    Vector3f rel_pos2 = Stack.alloc(Vector3f.class);
    rel_pos2.sub(pos2, body2.getCenterOfMassPosition(tmp));

    //this jacobian entry could be re-used for all iterations

    Vector3f vel1 = Stack.alloc(Vector3f.class);
    body1.getVelocityInLocalPoint(rel_pos1, vel1);

    Vector3f vel2 = Stack.alloc(Vector3f.class);
    body2.getVelocityInLocalPoint(rel_pos2, vel2);

    Vector3f vel = Stack.alloc(Vector3f.class);
    vel.sub(vel1, vel2);

    Matrix3f mat1 = body1.getCenterOfMassTransform(Stack.alloc(Transform.class)).basis;
    mat1.transpose();

    Matrix3f mat2 = body2.getCenterOfMassTransform(Stack.alloc(Transform.class)).basis;
    mat2.transpose();

    JacobianEntry jac = jacobiansPool.get();
    jac.init(mat1, mat2,
        rel_pos1, rel_pos2, normal,
        body1.getInvInertiaDiagLocal(Stack.alloc(Vector3f.class)), body1.getInvMass(),
        body2.getInvInertiaDiagLocal(Stack.alloc(Vector3f.class)), body2.getInvMass());

    float jacDiagAB = jac.getDiagonal();
    float jacDiagABInv = 1f / jacDiagAB;

    Vector3f tmp1 = body1.getAngularVelocity(Stack.alloc(Vector3f.class));
    mat1.transform(tmp1);

    Vector3f tmp2 = body2.getAngularVelocity(Stack.alloc(Vector3f.class));
    mat2.transform(tmp2);

    float rel_vel = jac.getRelativeVelocity(
        body1.getLinearVelocity(Stack.alloc(Vector3f.class)),
        tmp1,
        body2.getLinearVelocity(Stack.alloc(Vector3f.class)),
        tmp2);

    jacobiansPool.release(jac);

    float a;
    a = jacDiagABInv;


    rel_vel = normal.dot(vel);

    // todo: move this into proper structure
    float contactDamping = 0.2f;

    //#ifdef ONLY_USE_LINEAR_MASS
    //  btScalar massTerm = btScalar(1.) / (body1.getInvMass() + body2.getInvMass());
    //  impulse = - contactDamping * rel_vel * massTerm;
    //#else 
    float velocityImpulse = -contactDamping * rel_vel * jacDiagABInv;
    impulse[0] = velocityImpulse;
    //#endif
  }

  /**
   * Response between two dynamic objects with friction.
   */
  public static float resolveSingleCollision(
      RigidBody body1,
      RigidBody body2,
      ManifoldPoint contactPoint,
      ContactSolverInfo solverInfo) {
   
    Vector3f tmpVec = Stack.alloc(Vector3f.class);

    Vector3f pos1_ = contactPoint.getPositionWorldOnA(Stack.alloc(Vector3f.class));
    Vector3f pos2_ = contactPoint.getPositionWorldOnB(Stack.alloc(Vector3f.class));
    Vector3f normal = contactPoint.normalWorldOnB;

    // constant over all iterations
    Vector3f rel_pos1 = Stack.alloc(Vector3f.class);
    rel_pos1.sub(pos1_, body1.getCenterOfMassPosition(tmpVec));

    Vector3f rel_pos2 = Stack.alloc(Vector3f.class);
    rel_pos2.sub(pos2_, body2.getCenterOfMassPosition(tmpVec));

    Vector3f vel1 = body1.getVelocityInLocalPoint(rel_pos1, Stack.alloc(Vector3f.class));
    Vector3f vel2 = body2.getVelocityInLocalPoint(rel_pos2, Stack.alloc(Vector3f.class));
    Vector3f vel = Stack.alloc(Vector3f.class);
    vel.sub(vel1, vel2);

    float rel_vel;
    rel_vel = normal.dot(vel);

    float Kfps = 1f / solverInfo.timeStep;

    // btScalar damping = solverInfo.m_damping ;
    float Kerp = solverInfo.erp;
    float Kcor = Kerp * Kfps;

    ConstraintPersistentData cpd = (ConstraintPersistentData) contactPoint.userPersistentData;
    assert (cpd != null);
    float distance = cpd.penetration;
    float positionalError = Kcor * -distance;
    float velocityError = cpd.restitution - rel_vel; // * damping;

    float penetrationImpulse = positionalError * cpd.jacDiagABInv;

    float velocityImpulse = velocityError * cpd.jacDiagABInv;

    float normalImpulse = penetrationImpulse + velocityImpulse;

    // See Erin Catto's GDC 2006 paper: Clamp the accumulated impulse
    float oldNormalImpulse = cpd.appliedImpulse;
    float sum = oldNormalImpulse + normalImpulse;
    cpd.appliedImpulse = 0f > sum ? 0f : sum;

    normalImpulse = cpd.appliedImpulse - oldNormalImpulse;

    //#ifdef USE_INTERNAL_APPLY_IMPULSE
    Vector3f tmp = Stack.alloc(Vector3f.class);
    if (body1.getInvMass() != 0f) {
      tmp.scale(body1.getInvMass(), contactPoint.normalWorldOnB);
      body1.internalApplyImpulse(tmp, cpd.angularComponentA, normalImpulse);
    }
    if (body2.getInvMass() != 0f) {
      tmp.scale(body2.getInvMass(), contactPoint.normalWorldOnB);
      body2.internalApplyImpulse(tmp, cpd.angularComponentB, -normalImpulse);
    }
    //#else //USE_INTERNAL_APPLY_IMPULSE
    //  body1.applyImpulse(normal*(normalImpulse), rel_pos1);
    //  body2.applyImpulse(-normal*(normalImpulse), rel_pos2);
    //#endif //USE_INTERNAL_APPLY_IMPULSE

    return normalImpulse;
  }
 
  public static float resolveSingleFriction(
      RigidBody body1,
      RigidBody body2,
      ManifoldPoint contactPoint,
      ContactSolverInfo solverInfo) {
   
    Vector3f tmpVec = Stack.alloc(Vector3f.class);
   
    Vector3f pos1 = contactPoint.getPositionWorldOnA(Stack.alloc(Vector3f.class));
    Vector3f pos2 = contactPoint.getPositionWorldOnB(Stack.alloc(Vector3f.class));

    Vector3f rel_pos1 = Stack.alloc(Vector3f.class);
    rel_pos1.sub(pos1, body1.getCenterOfMassPosition(tmpVec));

    Vector3f rel_pos2 = Stack.alloc(Vector3f.class);
    rel_pos2.sub(pos2, body2.getCenterOfMassPosition(tmpVec));

    ConstraintPersistentData cpd = (ConstraintPersistentData) contactPoint.userPersistentData;
    assert (cpd != null);

    float combinedFriction = cpd.friction;

    float limit = cpd.appliedImpulse * combinedFriction;

    if (cpd.appliedImpulse > 0f) //friction
    {
      //apply friction in the 2 tangential directions

      // 1st tangent
      Vector3f vel1 = Stack.alloc(Vector3f.class);
      body1.getVelocityInLocalPoint(rel_pos1, vel1);

      Vector3f vel2 = Stack.alloc(Vector3f.class);
      body2.getVelocityInLocalPoint(rel_pos2, vel2);

      Vector3f vel = Stack.alloc(Vector3f.class);
      vel.sub(vel1, vel2);

      float j1, j2;

      {
        float vrel = cpd.frictionWorldTangential0.dot(vel);

        // calculate j that moves us to zero relative velocity
        j1 = -vrel * cpd.jacDiagABInvTangent0;
        float oldTangentImpulse = cpd.accumulatedTangentImpulse0;
        cpd.accumulatedTangentImpulse0 = oldTangentImpulse + j1;

        cpd.accumulatedTangentImpulse0 = Math.min(cpd.accumulatedTangentImpulse0, limit);
        cpd.accumulatedTangentImpulse0 = Math.max(cpd.accumulatedTangentImpulse0, -limit);
        j1 = cpd.accumulatedTangentImpulse0 - oldTangentImpulse;
      }
      {
        // 2nd tangent

        float vrel = cpd.frictionWorldTangential1.dot(vel);

        // calculate j that moves us to zero relative velocity
        j2 = -vrel * cpd.jacDiagABInvTangent1;
        float oldTangentImpulse = cpd.accumulatedTangentImpulse1;
        cpd.accumulatedTangentImpulse1 = oldTangentImpulse + j2;

        cpd.accumulatedTangentImpulse1 = Math.min(cpd.accumulatedTangentImpulse1, limit);
        cpd.accumulatedTangentImpulse1 = Math.max(cpd.accumulatedTangentImpulse1, -limit);
        j2 = cpd.accumulatedTangentImpulse1 - oldTangentImpulse;
      }

      //#ifdef USE_INTERNAL_APPLY_IMPULSE
      Vector3f tmp = Stack.alloc(Vector3f.class);

      if (body1.getInvMass() != 0f) {
        tmp.scale(body1.getInvMass(), cpd.frictionWorldTangential0);
        body1.internalApplyImpulse(tmp, cpd.frictionAngularComponent0A, j1);

        tmp.scale(body1.getInvMass(), cpd.frictionWorldTangential1);
        body1.internalApplyImpulse(tmp, cpd.frictionAngularComponent1A, j2);
      }
      if (body2.getInvMass() != 0f) {
        tmp.scale(body2.getInvMass(), cpd.frictionWorldTangential0);
        body2.internalApplyImpulse(tmp, cpd.frictionAngularComponent0B, -j1);

        tmp.scale(body2.getInvMass(), cpd.frictionWorldTangential1);
        body2.internalApplyImpulse(tmp, cpd.frictionAngularComponent1B, -j2);
      }
      //#else //USE_INTERNAL_APPLY_IMPULSE
      //  body1.applyImpulse((j1 * cpd->m_frictionWorldTangential0)+(j2 * cpd->m_frictionWorldTangential1), rel_pos1);
      //  body2.applyImpulse((j1 * -cpd->m_frictionWorldTangential0)+(j2 * -cpd->m_frictionWorldTangential1), rel_pos2);
      //#endif //USE_INTERNAL_APPLY_IMPULSE
    }
    return cpd.appliedImpulse;
  }
 
  /**
   * velocity + friction<br>
   * response between two dynamic objects with friction
   */
  public static float resolveSingleCollisionCombined(
      RigidBody body1,
      RigidBody body2,
      ManifoldPoint contactPoint,
      ContactSolverInfo solverInfo) {
   
    Vector3f tmpVec = Stack.alloc(Vector3f.class);
   
    Vector3f pos1 = contactPoint.getPositionWorldOnA(Stack.alloc(Vector3f.class));
    Vector3f pos2 = contactPoint.getPositionWorldOnB(Stack.alloc(Vector3f.class));
    Vector3f normal = contactPoint.normalWorldOnB;

    Vector3f rel_pos1 = Stack.alloc(Vector3f.class);
    rel_pos1.sub(pos1, body1.getCenterOfMassPosition(tmpVec));

    Vector3f rel_pos2 = Stack.alloc(Vector3f.class);
    rel_pos2.sub(pos2, body2.getCenterOfMassPosition(tmpVec));

    Vector3f vel1 = body1.getVelocityInLocalPoint(rel_pos1, Stack.alloc(Vector3f.class));
    Vector3f vel2 = body2.getVelocityInLocalPoint(rel_pos2, Stack.alloc(Vector3f.class));
    Vector3f vel = Stack.alloc(Vector3f.class);
    vel.sub(vel1, vel2);

    float rel_vel;
    rel_vel = normal.dot(vel);

    float Kfps = 1f / solverInfo.timeStep;

    //btScalar damping = solverInfo.m_damping ;
    float Kerp = solverInfo.erp;
    float Kcor = Kerp * Kfps;

    ConstraintPersistentData cpd = (ConstraintPersistentData) contactPoint.userPersistentData;
    assert (cpd != null);
    float distance = cpd.penetration;
    float positionalError = Kcor * -distance;
    float velocityError = cpd.restitution - rel_vel;// * damping;

    float penetrationImpulse = positionalError * cpd.jacDiagABInv;

    float velocityImpulse = velocityError * cpd.jacDiagABInv;

    float normalImpulse = penetrationImpulse + velocityImpulse;

    // See Erin Catto's GDC 2006 paper: Clamp the accumulated impulse
    float oldNormalImpulse = cpd.appliedImpulse;
    float sum = oldNormalImpulse + normalImpulse;
    cpd.appliedImpulse = 0f > sum ? 0f : sum;

    normalImpulse = cpd.appliedImpulse - oldNormalImpulse;


    //#ifdef USE_INTERNAL_APPLY_IMPULSE
    Vector3f tmp = Stack.alloc(Vector3f.class);
    if (body1.getInvMass() != 0f) {
      tmp.scale(body1.getInvMass(), contactPoint.normalWorldOnB);
      body1.internalApplyImpulse(tmp, cpd.angularComponentA, normalImpulse);
    }
    if (body2.getInvMass() != 0f) {
      tmp.scale(body2.getInvMass(), contactPoint.normalWorldOnB);
      body2.internalApplyImpulse(tmp, cpd.angularComponentB, -normalImpulse);
    }
    //#else //USE_INTERNAL_APPLY_IMPULSE
    //  body1.applyImpulse(normal*(normalImpulse), rel_pos1);
    //  body2.applyImpulse(-normal*(normalImpulse), rel_pos2);
    //#endif //USE_INTERNAL_APPLY_IMPULSE

    {
      //friction
      body1.getVelocityInLocalPoint(rel_pos1, vel1);
      body2.getVelocityInLocalPoint(rel_pos2, vel2);
      vel.sub(vel1, vel2);

      rel_vel = normal.dot(vel);

      tmp.scale(rel_vel, normal);
      Vector3f lat_vel = Stack.alloc(Vector3f.class);
      lat_vel.sub(vel, tmp);
      float lat_rel_vel = lat_vel.length();

      float combinedFriction = cpd.friction;

      if (cpd.appliedImpulse > 0) {
        if (lat_rel_vel > BulletGlobals.FLT_EPSILON) {
          lat_vel.scale(1f / lat_rel_vel);

          Vector3f temp1 = Stack.alloc(Vector3f.class);
          temp1.cross(rel_pos1, lat_vel);
          body1.getInvInertiaTensorWorld(Stack.alloc(Matrix3f.class)).transform(temp1);

          Vector3f temp2 = Stack.alloc(Vector3f.class);
          temp2.cross(rel_pos2, lat_vel);
          body2.getInvInertiaTensorWorld(Stack.alloc(Matrix3f.class)).transform(temp2);

          Vector3f java_tmp1 = Stack.alloc(Vector3f.class);
          java_tmp1.cross(temp1, rel_pos1);

          Vector3f java_tmp2 = Stack.alloc(Vector3f.class);
          java_tmp2.cross(temp2, rel_pos2);

          tmp.add(java_tmp1, java_tmp2);

          float friction_impulse = lat_rel_vel /
              (body1.getInvMass() + body2.getInvMass() + lat_vel.dot(tmp));
          float normal_impulse = cpd.appliedImpulse * combinedFriction;

          friction_impulse = Math.min(friction_impulse, normal_impulse);
          friction_impulse = Math.max(friction_impulse, -normal_impulse);

          tmp.scale(-friction_impulse, lat_vel);
          body1.applyImpulse(tmp, rel_pos1);

          tmp.scale(friction_impulse, lat_vel);
          body2.applyImpulse(tmp, rel_pos2);
        }
      }
    }

    return normalImpulse;
  }

  public static float resolveSingleFrictionEmpty(
      RigidBody body1,
      RigidBody body2,
      ManifoldPoint contactPoint,
      ContactSolverInfo solverInfo) {
    return 0f;
  }
 
}
TOP

Related Classes of com.bulletphysics.dynamics.constraintsolver.ContactConstraint

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.