All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.bulletphysics.dynamics.constraintsolver.ContactConstraint Maven / Gradle / Ivy

The newest version!
/*
 * Java port of Bullet (c) 2008 Martin Dvorak 
 *
 * 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 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
* 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; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy