Beispiel #1
0
		public static void Run()
		{

			{
				btTransform planeObjWorld = new btTransform( new btQuaternion( 0.2, 0.1, 0.3, 1 ), new btVector3( 3, 4, 5 ) );
				btTransform convexWorldTransform = new btTransform( new btQuaternion( 0.2, 0.3, 0, 1 ), new btVector3( 3, 4, 5 ) );
				btTransform convexInPlaneTrans;
				btTransform tmp;
				planeObjWorld.inverse( out tmp );
				tmp.Apply( ref convexWorldTransform, out convexInPlaneTrans );
				PrintTransform( ref convexInPlaneTrans );

				planeObjWorld.inverseTimes( ref convexWorldTransform, out convexInPlaneTrans );
				PrintTransform( ref convexInPlaneTrans );
				//convexInPlaneTrans = planeObjWorld( convexWorldTransform;
				//PrintTransform( &convexInPlaneTrans );
			}
			{
				btTransform planeObjWorld = new btTransform( new btQuaternion( 0.2, 0.1, 0.3, 1 ), new btVector3( 5, 2, 1 ) );
				btTransform convexWorldTransform = new btTransform( new btQuaternion( 0.2, 0.3, 0, 1 ), new btVector3( 3, 4, 5 ) );
				btTransform convexInPlaneTrans;
				btTransform tmp;
				planeObjWorld.inverse( out tmp );
				tmp.Apply( ref convexWorldTransform, out convexInPlaneTrans );
				PrintTransform( ref convexInPlaneTrans );

				planeObjWorld.inverseTimes( ref convexWorldTransform, out convexInPlaneTrans );
				PrintTransform( ref convexInPlaneTrans );
				//convexInPlaneTrans = planeObjWorld( convexWorldTransform;
				//PrintTransform( &convexInPlaneTrans );

				btQuaternion perturbeRot = new btQuaternion( 0.1, 0.5, 0.25, 0.8 );
				perturbeRot.normalize();

				btTransform planeObjWrapTrans = new btTransform( new btQuaternion( 0.2, 0.1, 0.3, 1 ), new btVector3( 4, 7, 2 ) );
				planeObjWrapTrans.inverseTimes( ref convexWorldTransform, out convexInPlaneTrans );

				//now perturbe the convex-world transform
				btMatrix3x3 perturbeMat = new btMatrix3x3( ref perturbeRot );
				btMatrix3x3 tmpPerturbe; convexWorldTransform.m_basis.Apply( ref perturbeMat, out tmpPerturbe );
				convexWorldTransform.m_basis = tmpPerturbe;

				btTransform planeInConvex;
				convexWorldTransform.inverseTimes( ref planeObjWrapTrans, out planeInConvex );
				PrintTransform( ref planeInConvex );
			}
			Console.Read();

		}
Beispiel #2
0
		void getOrientation( out btQuaternion result )
		{
			m_worldTransform.m_basis.getRotation( out result );
		}
Beispiel #3
0
		public void setMotorTarget( ref btQuaternion qAinB, double dt )
		{
			// convert target from body to constraint space
			btMatrix3x3 tmp;
			m_rbBFrame.m_basis.inverse( out tmp );
			btQuaternion tmpq;
			m_rbBFrame.getRotation( out tmpq );
			tmpq.inverse( out tmpq );
			btQuaternion tmpq2;
			tmpq.Mult( ref qAinB, out tmpq2 );
			m_rbAFrame.getRotation( out tmpq );
			btQuaternion qConstraint;// = m_rbBFrame.getRotation().inverse() * qAinB * m_rbAFrame.getRotation();
			tmpq2.Mult( ref tmpq, out qConstraint );
			qConstraint.normalize();

			// extract "pure" hinge component
			btVector3 vNoHinge; btQuaternion.quatRotate( ref qConstraint, ref vHinge, out vNoHinge ); vNoHinge.normalize();
			btQuaternion qNoHinge; btQuaternion.shortestArcQuat( ref vHinge, ref vNoHinge, out qNoHinge );
			qNoHinge.inverse( out tmpq );
			btQuaternion qHinge;// = qNoHinge.inverse() * qConstraint;
			tmpq.Mult( ref qConstraint, out qHinge );
			qHinge.normalize();

			// compute angular target, clamped to limits
			double targetAngle = qHinge.getAngle();
			if( targetAngle > btScalar.SIMD_PI ) // long way around. flip quat and recalculate.
			{
				qHinge.inverse( out qHinge );
				//qHinge = -( qHinge );
				targetAngle = qHinge.getAngle();
			}
			if( qHinge.z < 0 )
				targetAngle = -targetAngle;

			setMotorTarget( targetAngle, dt );
		}
		//
		// Convex-Convex collision algorithm
		//
		internal override void processCollision( btCollisionObjectWrapper body0Wrap
							, ref btTransform body0Transform
							, btCollisionObjectWrapper body1Wrap
							, ref btTransform body1Transform
							, btDispatcherInfo dispatchInfo, btManifoldResult resultOut )
		{

			if( m_manifoldPtr == null )
			{
				//swapped?
				m_manifoldPtr = m_dispatcher.getNewManifold( body0Wrap.m_collisionObject, body1Wrap.m_collisionObject );
				m_ownManifold = true;
			}
			resultOut.setPersistentManifold( m_manifoldPtr );

			//comment-out next line to test multi-contact generation
			//resultOut.getPersistentManifold().clearManifold();


			btConvexShape min0 = (btConvexShape)body0Wrap.getCollisionShape();
			btConvexShape min1 = (btConvexShape)body1Wrap.getCollisionShape();

			btVector3 normalOnB;
			btVector3 pointOnBWorld;
#if !BT_DISABLE_CAPSULE_CAPSULE_COLLIDER
			if( ( min0.getShapeType() == BroadphaseNativeTypes.CAPSULE_SHAPE_PROXYTYPE )
				&& ( min1.getShapeType() == BroadphaseNativeTypes.CAPSULE_SHAPE_PROXYTYPE ) )
			{
				btCapsuleShape capsuleA = (btCapsuleShape)min0;
				btCapsuleShape capsuleB = (btCapsuleShape)min1;
				//	btVector3 localScalingA = capsuleA.getLocalScaling();
				//	btVector3 localScalingB = capsuleB.getLocalScaling();

				double threshold = m_manifoldPtr.getContactBreakingThreshold();

				double dist = capsuleCapsuleDistance( out normalOnB, out pointOnBWorld
						, capsuleA.getHalfHeight(), capsuleA.getRadius()
						, capsuleB.getHalfHeight(), capsuleB.getRadius()
						, capsuleA.getUpAxis(), capsuleB.getUpAxis()
						, ref body0Wrap.m_collisionObject.m_worldTransform, ref body1Wrap.m_collisionObject.m_worldTransform, threshold );

				if( dist < threshold )
				{
					Debug.Assert( normalOnB.length2() >= ( btScalar.SIMD_EPSILON * btScalar.SIMD_EPSILON ) );
					resultOut.addContactPoint( ref normalOnB, ref pointOnBWorld, dist );
				}
				resultOut.refreshContactPoints();
				return;
			}
#endif //BT_DISABLE_CAPSULE_CAPSULE_COLLIDER




#if USE_SEPDISTANCE_UTIL2
	if (dispatchInfo.m_useConvexConservativeDistanceUtil)
	{
		m_sepDistance.updateSeparatingDistance(body0.getWorldTransform(),body1.getWorldTransform());
	}

	if (!dispatchInfo.m_useConvexConservativeDistanceUtil || m_sepDistance.getConservativeSeparatingDistance()<=0)
#endif //USE_SEPDISTANCE_UTIL2

			{
				btGjkPairDetector.ClosestPointInput input = BulletGlobals.ClosestPointInputPool.Get();
				input.Initialize();

				btGjkPairDetector gjkPairDetector = BulletGlobals.GjkPairDetectorPool.Get();
				gjkPairDetector.Initialize( min0, min1, m_simplexSolver, m_pdSolver );
				//TODO: if (dispatchInfo.m_useContinuous)
				gjkPairDetector.setMinkowskiA( min0 );
				gjkPairDetector.setMinkowskiB( min1 );

#if USE_SEPDISTANCE_UTIL2
	if (dispatchInfo.m_useConvexConservativeDistanceUtil)
	{
		input.m_maximumDistanceSquared = BT_LARGE_FLOAT;
	} else
#endif //USE_SEPDISTANCE_UTIL2
				{
					//if (dispatchInfo.m_convexMaxDistanceUseCPT)
					//{
					//	input.m_maximumDistanceSquared = min0.getMargin() + min1.getMargin() + m_manifoldPtr.getContactProcessingThreshold();
					//} else
					//{
					input.m_maximumDistanceSquared = min0.getMargin() + min1.getMargin() + m_manifoldPtr.getContactBreakingThreshold();
					//		}

					input.m_maximumDistanceSquared *= input.m_maximumDistanceSquared;
				}

				input.m_transformA = body0Transform;
				input.m_transformB = body1Transform;


#if USE_SEPDISTANCE_UTIL2
	double sepDist = 0;
	if (dispatchInfo.m_useConvexConservativeDistanceUtil)
	{
		sepDist = gjkPairDetector.getCachedSeparatingDistance();
		if (sepDist>SIMD_EPSILON)
		{
			sepDist += dispatchInfo.m_convexConservativeDistanceThreshold;
			//now perturbe directions to get multiple contact points
			
		}
	}
#endif //USE_SEPDISTANCE_UTIL2

				if( min0.isPolyhedral() && min1.isPolyhedral() )
				{



					btDummyResult dummy = new btDummyResult();

					///btBoxShape is an exception: its vertices are created WITH margin so don't subtract it

					double min0Margin = min0.getShapeType() == BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE ? 0 : min0.getMargin();
					double min1Margin = min1.getShapeType() == BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE ? 0 : min1.getMargin();

					btWithoutMarginResult withoutMargin = new btWithoutMarginResult( resultOut, min0Margin, min1Margin );

					btPolyhedralConvexShape polyhedronA = (btPolyhedralConvexShape)min0;
					btPolyhedralConvexShape polyhedronB = (btPolyhedralConvexShape)min1;
					if( polyhedronA.getConvexPolyhedron() != null && polyhedronB.getConvexPolyhedron() != null )
					{
						double threshold = m_manifoldPtr.getContactBreakingThreshold();

						double minDist = -1e30f;
						btVector3 sepNormalWorldSpace;
						bool foundSepAxis = true;

						if( dispatchInfo.m_enableSatConvex )
						{
							foundSepAxis = btPolyhedralContactClipping.findSeparatingAxis(
								polyhedronA.getConvexPolyhedron(), polyhedronB.getConvexPolyhedron(),
								ref body0Wrap.m_collisionObject.m_worldTransform,
								ref body1Wrap.m_collisionObject.m_worldTransform,
								out sepNormalWorldSpace, resultOut );
						}
						else
						{
#if ZERO_MARGIN
				gjkPairDetector.setIgnoreMargin(true);
				gjkPairDetector.getClosestPoints(input,*resultOut,dispatchInfo.m_debugDraw);
#else

							gjkPairDetector.getClosestPoints( input, withoutMargin, dispatchInfo.m_debugDraw );
							//gjkPairDetector.getClosestPoints(input,dummy,dispatchInfo.m_debugDraw);
#endif //ZERO_MARGIN
							//double l2 = gjkPairDetector.getCachedSeparatingAxis().length2();
							//if (l2>SIMD_EPSILON)
							{
								sepNormalWorldSpace = withoutMargin.m_reportedNormalOnWorld;//gjkPairDetector.getCachedSeparatingAxis()*(1/l2);
																							//minDist = -1e30f;//gjkPairDetector.getCachedSeparatingDistance();
								minDist = withoutMargin.m_reportedDistance;//gjkPairDetector.getCachedSeparatingDistance()+min0.getMargin()+min1.getMargin();

#if ZERO_MARGIN
					foundSepAxis = true;//gjkPairDetector.getCachedSeparatingDistance()<0;
#else
								foundSepAxis = withoutMargin.m_foundResult && minDist < 0;//-(min0.getMargin()+min1.getMargin());
#endif
							}
						}
						if( foundSepAxis )
						{

							//				Console.WriteLine("sepNormalWorldSpace=%f,%f,%f\n",sepNormalWorldSpace.x,sepNormalWorldSpace.y,sepNormalWorldSpace.z);

							btPolyhedralContactClipping.clipHullAgainstHull( ref sepNormalWorldSpace, polyhedronA.getConvexPolyhedron(), polyhedronB.getConvexPolyhedron(),
								ref body0Wrap.m_collisionObject.m_worldTransform,
								ref body1Wrap.m_collisionObject.m_worldTransform
								, minDist - threshold, threshold, resultOut );

						}
						if( m_ownManifold )
						{
							resultOut.refreshContactPoints();
						}
						BulletGlobals.ClosestPointInputPool.Free( input );
						BulletGlobals.GjkPairDetectorPool.Free( gjkPairDetector );
						return;

					}
					else
					{
						//we can also deal with convex versus triangle (without connectivity data)
						if( polyhedronA.getConvexPolyhedron() != null && polyhedronB.getShapeType() == BroadphaseNativeTypes.TRIANGLE_SHAPE_PROXYTYPE )
						{

							btVertexArray vertices = new btVertexArray();
							btTriangleShape tri = (btTriangleShape)polyhedronB;
							btVector3 tmp;
							body1Transform.Apply( ref tri.m_vertices1, out tmp );
							vertices.Add( ref tmp );
							body1Transform.Apply( ref tri.m_vertices2, out tmp );
							vertices.Add( ref tmp );
							body1Transform.Apply( ref tri.m_vertices3, out tmp );
							vertices.Add( ref tmp );

							//tri.initializePolyhedralFeatures();

							double threshold = m_manifoldPtr.getContactBreakingThreshold();

							btVector3 sepNormalWorldSpace;
							double minDist = -btScalar.BT_LARGE_FLOAT;
							double maxDist = threshold;

							bool foundSepAxis = false;
							if( false )
							{
								polyhedronB.initializePolyhedralFeatures();
								foundSepAxis = btPolyhedralContactClipping.findSeparatingAxis(
										polyhedronA.getConvexPolyhedron(), polyhedronB.getConvexPolyhedron(),
										ref body0Wrap.m_collisionObject.m_worldTransform,
										ref body1Wrap.m_collisionObject.m_worldTransform,
										out sepNormalWorldSpace, resultOut );
								//	 Console.WriteLine("sepNormalWorldSpace=%f,%f,%f\n",sepNormalWorldSpace.x,sepNormalWorldSpace.y,sepNormalWorldSpace.z);
								btPolyhedralContactClipping.clipFaceAgainstHull( ref sepNormalWorldSpace
									, polyhedronA.getConvexPolyhedron(),
									ref body0Wrap.m_collisionObject.m_worldTransform, vertices, minDist - threshold, maxDist, resultOut );

							}
							else
							{
#if ZERO_MARGIN
					gjkPairDetector.setIgnoreMargin(true);
					gjkPairDetector.getClosestPoints(input,*resultOut,dispatchInfo.m_debugDraw);
#else
								gjkPairDetector.getClosestPoints( input, dummy, dispatchInfo.m_debugDraw );
#endif//ZERO_MARGIN

								double l2 = gjkPairDetector.getCachedSeparatingAxis().length2();
								if( l2 > btScalar.SIMD_EPSILON )
								{
									gjkPairDetector.getCachedSeparatingAxis().Mult( ( 1 / l2 ), out sepNormalWorldSpace );
									//minDist = gjkPairDetector.getCachedSeparatingDistance();
									//maxDist = threshold;
									minDist = gjkPairDetector.getCachedSeparatingDistance() - min0.getMargin() - min1.getMargin();
									//foundSepAxis = true;
									btPolyhedralContactClipping.clipFaceAgainstHull( ref sepNormalWorldSpace
										, polyhedronA.getConvexPolyhedron(),
										ref body0Wrap.m_collisionObject.m_worldTransform, vertices, minDist - threshold, maxDist, resultOut );
								}
								else
								{
									//sepNormalWorldSpace = btVector3.Zero;
								}
							}


							if( m_ownManifold )
							{
								resultOut.refreshContactPoints();
							}
							BulletGlobals.ClosestPointInputPool.Free( input );
							BulletGlobals.GjkPairDetectorPool.Free( gjkPairDetector );

							return;
						}

					}


				}

				gjkPairDetector.getClosestPoints( input, resultOut, dispatchInfo.m_debugDraw );

				//now perform 'm_numPerturbationIterations' collision queries with the perturbated collision objects

				//perform perturbation when more then 'm_minimumPointsPerturbationThreshold' points
				if( m_numPerturbationIterations != 0
					&& resultOut.m_manifoldPtr.m_cachedPoints < m_minimumPointsPerturbationThreshold )
				{

					int i;
					btVector3 v0, v1;
					btVector3 sepNormalWorldSpace;
					double l2 = gjkPairDetector.getCachedSeparatingAxis().length2();

					if( l2 > btScalar.SIMD_EPSILON )
					{
						gjkPairDetector.getCachedSeparatingAxis().Mult( ( 1 / l2 ), out sepNormalWorldSpace );

						btVector3.btPlaneSpace1( ref sepNormalWorldSpace, out v0, out v1 );


						bool perturbeA = true;
						double angleLimit = 0.125f * btScalar.SIMD_PI;
						double perturbeAngle;
						double radiusA = min0.getAngularMotionDisc();
						double radiusB = min1.getAngularMotionDisc();
						if( radiusA < radiusB )
						{
							perturbeAngle = btPersistentManifold.gContactBreakingThreshold / radiusA;
							perturbeA = true;
						}
						else
						{
							perturbeAngle = btPersistentManifold.gContactBreakingThreshold / radiusB;
							perturbeA = false;
						}
						if( perturbeAngle > angleLimit )
							perturbeAngle = angleLimit;

						btTransform unPerturbedTransform;
						if( perturbeA )
						{
							unPerturbedTransform = input.m_transformA;
						}
						else
						{
							unPerturbedTransform = input.m_transformB;
						}

						for( i = 0; i < m_numPerturbationIterations; i++ )
						{
							if( v0.length2() > btScalar.SIMD_EPSILON )
							{
								btQuaternion perturbeRot = new btQuaternion( ref v0, perturbeAngle );
								double iterationAngle = i * ( btScalar.SIMD_2_PI / (double)( m_numPerturbationIterations ) );
								btQuaternion rotq = new btQuaternion( ref sepNormalWorldSpace, iterationAngle );


								if( perturbeA )
								{
									btQuaternion tmpq;
									btQuaternion tmpq2;
									rotq.inverse( out tmpq );
									btQuaternion.Mult( ref tmpq, ref perturbeRot, out tmpq2 );
									btQuaternion.Mult( ref tmpq2, ref rotq, out tmpq );
									btMatrix3x3 m = new btMatrix3x3( ref tmpq );
									btMatrix3x3 m2; body0Transform.getBasis( out m2 );
									btMatrix3x3 m3;
									btMatrix3x3.Mult( ref m, ref m2, out m3 );
									input.m_transformA.setBasis( ref m3 );
									input.m_transformB = body1Transform;
#if DEBUG_CONTACTS
					dispatchInfo.m_debugDraw.drawTransform(input.m_transformA,10.0);
#endif //DEBUG_CONTACTS
								}
								else
								{
									btQuaternion tmpq;
									btQuaternion tmpq2;
									rotq.inverse( out tmpq );
									btQuaternion.Mult( ref tmpq, ref perturbeRot, out tmpq2 );
									btQuaternion.Mult( ref tmpq2, ref rotq, out tmpq );
									btMatrix3x3 m = new btMatrix3x3( ref tmpq );
									btMatrix3x3 m2; body1Transform.getBasis( out m2 );
									btMatrix3x3 m3;
									btMatrix3x3.Mult( ref m, ref m2, out m3 );

									input.m_transformA = body0Transform;
									input.m_transformB.setBasis( ref m3 );
#if DEBUG_CONTACTS
					dispatchInfo.m_debugDraw.drawTransform(input.m_transformB,10.0);
#endif
								}

								btPerturbedContactResult perturbedResultOut = BulletGlobals.PerturbedContactResultPool.Get();
								if( perturbeA )
									perturbedResultOut.Initialize( resultOut
										, ref input.m_transformA, ref input.m_transformB
										, ref input.m_transformA
										, perturbeA
										, dispatchInfo.m_debugDraw );
								else
									perturbedResultOut.Initialize( resultOut
										, ref input.m_transformA, ref input.m_transformB
										, ref input.m_transformB
												, perturbeA
												, dispatchInfo.m_debugDraw );
								gjkPairDetector.getClosestPoints( input, perturbedResultOut, dispatchInfo.m_debugDraw );
								BulletGlobals.PerturbedContactResultPool.Free( perturbedResultOut );
							}
						}
					}
				}



#if USE_SEPDISTANCE_UTIL2
	if (dispatchInfo.m_useConvexConservativeDistanceUtil && (sepDist>SIMD_EPSILON))
	{
		m_sepDistance.initSeparatingDistance(gjkPairDetector.getCachedSeparatingAxis(),sepDist,body0.getWorldTransform(),body1.getWorldTransform());
	}
#endif //USE_SEPDISTANCE_UTIL2

				BulletGlobals.ClosestPointInputPool.Free( input );
				BulletGlobals.GjkPairDetectorPool.Free( gjkPairDetector );

			}

			if( m_ownManifold )
			{
				resultOut.refreshContactPoints();
			}

		}
		internal override void processCollision( btCollisionObjectWrapper body0Wrap
			, ref btTransform body0Transform
			, btCollisionObjectWrapper body1Wrap
			, ref btTransform body1Transform
			, btDispatcherInfo dispatchInfo, btManifoldResult resultOut )
		{
			//(void)dispatchInfo;
			if( m_manifoldPtr == null )
				return;
			btCollisionObjectWrapper convexObjWrap = m_swapped ? body1Wrap : body0Wrap;
			btCollisionObjectWrapper planeObjWrap = m_swapped ? body0Wrap : body1Wrap;

			btConvexShape convexShape = (btConvexShape)convexObjWrap.m_shape;
			btStaticPlaneShape planeShape = (btStaticPlaneShape)planeObjWrap.getCollisionShape();
			//btVector3 planeNormal;
			//planeShape.getPlaneNormal().Copy( out planeNormal );
			double planeConstant = planeShape.getPlaneConstant();
			if( m_swapped )
				collideSingleContact( false, ref btQuaternion.Identity, convexObjWrap
					, ref body1Transform
					, planeObjWrap
					, ref body0Transform
					, dispatchInfo, resultOut
							, ref planeShape.m_planeNormal, planeConstant );
			else
				collideSingleContact( false, ref btQuaternion.Identity, convexObjWrap
					, ref body0Transform
					, planeObjWrap
					, ref body1Transform
					, dispatchInfo, resultOut
							, ref planeShape.m_planeNormal, planeConstant );
			/*
						btCollisionObjectWrapper convexObjWrap = m_swapped ? body1Wrap : body0Wrap;
						btCollisionObjectWrapper planeObjWrap = m_swapped ? body0Wrap : body1Wrap;

						btConvexShape convexShape = (btConvexShape)convexObjWrap.m_shape;
						btStaticPlaneShape planeShape = (btStaticPlaneShape)planeObjWrap.m_shape;

						bool hasCollision = false;
						btVector3 planeNormal; planeShape.m_planeNormal.Copy( out planeNormal );
						double planeConstant = planeShape.getPlaneConstant();
						btTransform planeInConvex;
						convexObjWrap.getWorldTransform().inverseTimes( planeObjWrap.getWorldTransform(), out planeInConvex );
						btTransform convexInPlaneTrans;
						planeObjWrap.getWorldTransform().inverseTimes( convexObjWrap.getWorldTransform(), out convexInPlaneTrans );

						btVector3 invPlaneNormal;
						planeNormal.Invert( out invPlaneNormal );
						btVector3 tmp;
						planeInConvex.getBasis().Apply( planeNormal, out tmp );
						btVector3 vtx; convexShape.localGetSupportingVertex( ref tmp, out vtx );
						btVector3 vtxInPlane; convexInPlaneTrans.Apply( ref vtx, out vtxInPlane );
						double distance = ( planeNormal.dot( ref vtxInPlane ) - planeConstant );

						btVector3 vtxInPlaneProjected; vtxInPlane.AddScale( planeNormal, -distance, out vtxInPlaneProjected );
						btVector3 vtxInPlaneWorld; planeObjWrap.getWorldTransform().Apply( ref vtxInPlaneProjected, out vtxInPlaneWorld );

						hasCollision = distance < m_manifoldPtr.getContactBreakingThreshold();
						resultOut.setPersistentManifold( m_manifoldPtr );
						if( hasCollision )
						{
							/// report a contact. internally this will be kept persistent, and contact reduction is done
							btVector3 normalOnSurfaceB = planeObjWrap.getWorldTransform().getBasis() * planeNormal;
							btVector3 pOnB = vtxInPlaneWorld;
							resultOut.addContactPoint( ref normalOnSurfaceB, ref pOnB, distance );
						}
			*/
			//the perturbation algorithm doesn't work well with implicit surfaces such as spheres, cylinder and cones:
			//they keep on rolling forever because of the additional off-center contact points
			//so only enable the feature for polyhedral shapes (btBoxShape, btConvexHullShape etc)
			if( convexShape.isPolyhedral() && resultOut.m_manifoldPtr.m_cachedPoints < m_minimumPointsPerturbationThreshold )
			{
				btVector3 v0, v1;
				btVector3.btPlaneSpace1( ref planeShape.m_planeNormal, out v0, out v1 );
				//now perform 'm_numPerturbationIterations' collision queries with the perturbated collision objects

				double angleLimit = 0.125f * btScalar.SIMD_PI;
				double perturbeAngle;
				double radius = convexShape.getAngularMotionDisc();
				perturbeAngle = btPersistentManifold.gContactBreakingThreshold / radius;
				if( perturbeAngle > angleLimit )
					perturbeAngle = angleLimit;

				btQuaternion perturbeRot = new btQuaternion( ref v0, perturbeAngle );
				double interval = btScalar.SIMD_2_PI / (double)( m_numPerturbationIterations );
				for( int i = 0; i < m_numPerturbationIterations; i++ )
				{
					double iterationAngle = i * interval;
					btQuaternion rotq = new btQuaternion( ref planeShape.m_planeNormal, iterationAngle );
					btQuaternion rotqInv;
					rotq.inverse( out rotqInv );
					btQuaternion tmpq, tmpq2;
					rotqInv.Mult( ref perturbeRot, out tmpq );
					tmpq.Mult( ref rotq, out tmpq2 );
					if( m_swapped )
						collideSingleContact( true, ref tmpq2
							, convexObjWrap, ref body1Transform
							, planeObjWrap, ref body0Transform
							, dispatchInfo
										, resultOut, ref planeShape.m_planeNormal, planeConstant );
					else
						collideSingleContact( true, ref tmpq2
							, convexObjWrap, ref body0Transform
							, planeObjWrap, ref body1Transform, dispatchInfo
									, resultOut, ref planeShape.m_planeNormal, planeConstant );
				}
			}

			if( m_ownManifold )
			{
				if( m_manifoldPtr.m_cachedPoints != 0 )
				{
					resultOut.refreshContactPoints();
				}
			}
		}
		public void getMotorTarget( out btQuaternion result ) { result = m_qTarget; }
		void collideSingleContact( bool usePertube, ref btQuaternion perturbeRot
			, btCollisionObjectWrapper convexObjWrap
			, ref btTransform convexTransform
			, btCollisionObjectWrapper planeObjWrap
			, ref btTransform planeTransform
			, btDispatcherInfo dispatchInfo, btManifoldResult resultOut
			, ref btVector3 planeNormal, double planeConstant
			)
		{
			//btCollisionObjectWrapper convexObjWrap = m_swapped ? body1Wrap : body0Wrap;
			//btCollisionObjectWrapper planeObjWrap = m_swapped ? body0Wrap : body1Wrap;

			btConvexShape convexShape = (btConvexShape)convexObjWrap.getCollisionShape();
			btStaticPlaneShape planeShape = (btStaticPlaneShape)planeObjWrap.getCollisionShape();

			bool hasCollision = false;
			//planeNormal = planeShape.getPlaneNormal().Copy( out planeNormal );
			//double planeConstant = planeShape.getPlaneConstant();

			btTransform convexWorldTransform = convexTransform;
			//btTransform planeWorldTransform = planeObjWrap.m_worldTransform;
			btTransform convexInPlaneTrans;
			planeTransform.inverseTimes( ref convexWorldTransform, out convexInPlaneTrans );

			if( usePertube )
			{
				//now perturbe the convex-world transform
				btMatrix3x3 perturbeMat = new btMatrix3x3( ref perturbeRot );
				btMatrix3x3 tmpPerturbe; convexWorldTransform.m_basis.Apply( ref perturbeMat, out tmpPerturbe );
				convexWorldTransform.m_basis = tmpPerturbe;
				//convexWorldTransform.getBasis() *= btMatrix3x3( perturbeRot );
			}

			btTransform planeInConvex;
			convexTransform.inverseTimes( ref planeObjWrap.m_collisionObject.m_worldTransform, out planeInConvex );

			btVector3 tmp, tmp2;
			planeNormal.Invert( out tmp );
			planeInConvex.m_basis.Apply( ref tmp, out tmp2 );
			btVector3 vtx; convexShape.localGetSupportingVertex( ref tmp2, out vtx );

			btVector3 vtxInPlane; convexInPlaneTrans.Apply( ref vtx, out vtxInPlane );
			double distance = ( planeNormal.dot( ref vtxInPlane ) - planeConstant );

			btVector3 vtxInPlaneProjected; vtxInPlane.AddScale( ref planeNormal, -distance, out vtxInPlaneProjected );
			btVector3 vtxInPlaneWorld; planeTransform.Apply( ref vtxInPlaneProjected, out vtxInPlaneWorld );

			hasCollision = distance < m_manifoldPtr.getContactBreakingThreshold();
			resultOut.setPersistentManifold( m_manifoldPtr );
			if( hasCollision )
			{
				/// report a contact. internally this will be kept persistent, and contact reduction is done
				btVector3 normalOnSurfaceB; planeTransform.m_basis.Apply( ref planeNormal, out normalOnSurfaceB );
				btScalar.Dbg( "Convex plane adds point " + normalOnSurfaceB + " " + vtxInPlaneWorld + " " + distance.ToString( "g17" ) );
				resultOut.addContactPoint( ref normalOnSurfaceB, ref vtxInPlaneWorld, distance );
			}
		}
		void setMotorTargetInConstraintSpace( ref btQuaternion q )
		{
			m_qTarget = q;

			// clamp motor target to within limits
			{
				double softness = 1;//m_limitSoftness;

				// split into twist and cone
				btVector3 vTwisted; btQuaternion.quatRotate( ref m_qTarget, ref vTwist, out vTwisted );
				btQuaternion qTargetCone; btQuaternion.shortestArcQuat( ref vTwist, ref vTwisted, out qTargetCone ); qTargetCone.normalize();
				qTargetCone.inverse( out qTargetCone );
				btQuaternion qTargetTwist; qTargetCone.Mult( ref m_qTarget, out qTargetTwist ); qTargetTwist.normalize();

				// clamp cone
				if( m_swingSpan1 >= (double)( 0.05f ) && m_swingSpan2 >= (double)( 0.05f ) )
				{
					double swingAngle, swingLimit; btVector3 swingAxis;
					computeConeLimitInfo( ref qTargetCone, out swingAngle, out swingAxis, out swingLimit );

					if( Math.Abs( swingAngle ) > btScalar.SIMD_EPSILON )
					{
						if( swingAngle > swingLimit * softness )
							swingAngle = swingLimit * softness;
						else if( swingAngle < -swingLimit * softness )
							swingAngle = -swingLimit * softness;
						qTargetCone = new btQuaternion( ref swingAxis, swingAngle );
					}
				}

				// clamp twist
				if( m_twistSpan >= (double)( 0.05f ) )
				{
					double twistAngle; btVector3 twistAxis;
					computeTwistLimitInfo( ref qTargetTwist, out twistAngle, out twistAxis );

					if( Math.Abs( twistAngle ) > btScalar.SIMD_EPSILON )
					{
						// eddy todo: limitSoftness used here???
						if( twistAngle > m_twistSpan * softness )
							twistAngle = m_twistSpan * softness;
						else if( twistAngle < -m_twistSpan * softness )
							twistAngle = -m_twistSpan * softness;
						qTargetTwist = new btQuaternion( ref twistAxis, twistAngle );
					}
				}

				qTargetCone.Mult( ref qTargetTwist, out m_qTarget );
			}
		}
		// setMotorTarget:
		// q: the desired rotation of bodyA wrt bodyB.
		// note: if q violates the joint limits, the internal target is clamped to avoid conflicting impulses (very bad for stability)
		// note: don't forget to enableMotor()
		public void setMotorTarget( ref btQuaternion q )
		{
			//btTransform trACur = m_rbA.m_worldTransform;
			//btTransform trBCur = m_rbB.m_worldTransform;
			//	btTransform trABCur = trBCur.inverse() * trACur;
			//	btQuaternion qABCur = trABCur.getRotation();
			//	btTransform trConstraintCur = (trBCur * m_rbBFrame).inverse() * (trACur * m_rbAFrame);
			//btQuaternion qConstraintCur = trConstraintCur.getRotation();

			btQuaternion tmp, tmp2, tmp3;

			m_rbBFrame.getRotation( out tmp );
			tmp.inverse( out tmp );
			tmp.Mult( ref q, out tmp3 );
			m_rbAFrame.getRotation( out tmp2 );
			btQuaternion qConstraint;// = m_rbBFrame.getRotation().inverse() * q * m_rbAFrame.getRotation();
			tmp3.Mult( ref tmp2, out qConstraint );
			setMotorTargetInConstraintSpace( ref qConstraint );
		}
Beispiel #10
0
		// given a twist rotation in constraint space, (pre: cone must already be removed)
		// this method computes its corresponding angle and axis.
		void computeTwistLimitInfo( ref btQuaternion qTwist,
														  out double twistAngle, // out
														  out btVector3 vTwistAxis ) // out
		{
			btQuaternion qMinTwist = qTwist;
			twistAngle = qTwist.getAngle();

			if( twistAngle > btScalar.SIMD_PI ) // long way around. flip quat and recalculate.
			{
				qTwist.inverse( out qMinTwist );
				twistAngle = qMinTwist.getAngle();
			}
			if( twistAngle < 0 )
			{
				// this should never happen
#if false
        Debug.Assert(false);
#endif
			}

			vTwistAxis = new btVector3( qMinTwist.x, qMinTwist.y, qMinTwist.z );
			if( twistAngle > btScalar.SIMD_EPSILON )
				vTwistAxis.normalize();
		}
Beispiel #11
0
		internal void GetPointForAngle( double fAngleInRadians, double fLength, out btVector3 result )
		{
			// compute x/y in ellipse using cone angle (0 . 2*PI along surface of cone)
			double xEllipse = btScalar.btCos( fAngleInRadians );
			double yEllipse = btScalar.btSin( fAngleInRadians );

			// Use the slope of the vector (using x/yEllipse) and find the length
			// of the line that intersects the ellipse:
			//  x^2   y^2
			//  --- + --- = 1, where a and b are semi-major axes 2 and 1 respectively (ie. the limits)
			//  a^2   b^2
			// Do the math and it should be clear.

			double swingLimit = m_swingSpan1; // if xEllipse == 0, just use axis b (1)
			if( Math.Abs( xEllipse ) > btScalar.SIMD_EPSILON )
			{
				double surfaceSlope2 = ( yEllipse * yEllipse ) / ( xEllipse * xEllipse );
				double norm = 1 / ( m_swingSpan2 * m_swingSpan2 );
				norm += surfaceSlope2 / ( m_swingSpan1 * m_swingSpan1 );
				double swingLimit2 = ( 1 + surfaceSlope2 ) / norm;
				swingLimit = btScalar.btSqrt( swingLimit2 );
			}

			// convert into point in constraint space:
			// note: twist is x-axis, swing 1 and 2 are along the z and y axes respectively
			btVector3 vSwingAxis = new btVector3( 0, xEllipse, -yEllipse );
			btQuaternion qSwing = new btQuaternion( ref vSwingAxis, swingLimit );
			btVector3 vPointInConstraintSpace = new btVector3( fLength, 0, 0 );
			btQuaternion.quatRotate( ref qSwing, ref vPointInConstraintSpace, out result );
		}
Beispiel #12
0
		// given a cone rotation in constraint space, (pre: twist must already be removed)
		// this method computes its corresponding swing angle and axis.
		// more interestingly, it computes the cone/swing limit (angle) for this cone "pose".
		void computeConeLimitInfo( ref btQuaternion qCone,
														 out double swingAngle, // out
														 out btVector3 vSwingAxis, // out
														 out double swingLimit ) // out
		{
			swingAngle = qCone.getAngle();
			if( swingAngle > btScalar.SIMD_EPSILON )
			{
				vSwingAxis = new btVector3( qCone.x, qCone.y, qCone.z );
				vSwingAxis.normalize();
#if false
        // non-zero twist?! this should never happen.
       Debug.Assert(Math.Abs(vSwingAxis.x) <= btScalar.SIMD_EPSILON));
#endif

				// Compute limit for given swing. tricky:
				// Given a swing axis, we're looking for the intersection with the bounding cone ellipse.
				// (Since we're dealing with angles, this ellipse is embedded on the surface of a sphere.)

				// For starters, compute the direction from center to surface of ellipse.
				// This is just the perpendicular (ie. rotate 2D vector by PI/2) of the swing axis.
				// (vSwingAxis is the cone rotation (in z,y); change vars and rotate to (x,y) coords.)
				double xEllipse = vSwingAxis.y;
				double yEllipse = -vSwingAxis.z;

				// Now, we use the slope of the vector (using x/yEllipse) and find the length
				// of the line that intersects the ellipse:
				//  x^2   y^2
				//  --- + --- = 1, where a and b are semi-major axes 2 and 1 respectively (ie. the limits)
				//  a^2   b^2
				// Do the math and it should be clear.

				swingLimit = m_swingSpan1; // if xEllipse == 0, we have a pure vSwingAxis.z rotation: just use swingspan1
				if( Math.Abs( xEllipse ) > btScalar.SIMD_EPSILON )
				{
					double surfaceSlope2 = ( yEllipse * yEllipse ) / ( xEllipse * xEllipse );
					double norm = 1 / ( m_swingSpan2 * m_swingSpan2 );
					norm += surfaceSlope2 / ( m_swingSpan1 * m_swingSpan1 );
					double swingLimit2 = ( 1 + surfaceSlope2 ) / norm;
					swingLimit = btScalar.btSqrt( swingLimit2 );
				}
				// test!
				/*swingLimit = m_swingSpan2;
				if (Math.Abs(vSwingAxis.z) > btScalar.SIMD_EPSILON)
				{
				double mag_2 = m_swingSpan1*m_swingSpan1 + m_swingSpan2*m_swingSpan2;
				double sinphi = m_swingSpan2 / sqrt(mag_2);
				double phi = asin(sinphi);
				double theta = atan2(Math.Abs(vSwingAxis.y),Math.Abs(vSwingAxis.z));
				double alpha = 3.14159f - theta - phi;
				double sinalpha = sin(alpha);
				swingLimit = m_swingSpan1 * sinphi/sinalpha;
				}*/
			}
			else //if( swingAngle < 0 )
			{
				vSwingAxis = btVector3.xAxis;
				swingLimit = 0;
				// this should never happen!
#if false
        Debug.Assert(false);
#endif
			}
		}