/// This maximum should not be necessary. It allows for untested/degenerate cases in production code.
		/// You don't want your game ever to lock-up.

		void computeClosestPoints( ref btTransform transA, ref btTransform transB, btPointCollector pointCollector)
		{
			if( m_convexB1 != null)
			{
				m_simplexSolver.reset();
				btGjkPairDetector gjk = BulletGlobals.GjkPairDetectorPool.Get();
				gjk.Initialize( m_convexA, m_convexB1, m_convexA.getShapeType(), m_convexB1.getShapeType(), m_convexA.getMargin(), m_convexB1.getMargin(), m_simplexSolver, m_penetrationDepthSolver);
				btGjkPairDetector.ClosestPointInput input = new btDiscreteCollisionDetectorInterface.ClosestPointInput();
				input.m_transformA = transA;
				input.m_transformB = transB;
				gjk.getClosestPoints( input, pointCollector, null );
				BulletGlobals.GjkPairDetectorPool.Free( gjk );
			}
			else
			{
				//convex versus plane
				btConvexShape convexShape = m_convexA;
				btStaticPlaneShape planeShape = m_planeShape;

				btVector3 planeNormal; planeShape.getPlaneNormal( out planeNormal );
				double planeConstant = planeShape.getPlaneConstant();

				//btTransform convexWorldTransform = transA;
				btTransform convexInPlaneTrans;
				btTransform tmpInv;
				transB.inverse( out tmpInv );
				tmpInv.Apply( ref transA, out convexInPlaneTrans );
				btTransform planeInConvex;
				convexInPlaneTrans.inverse( out tmpInv );
				tmpInv.Apply( ref transB, out planeInConvex );
				//planeInConvex = convexWorldTransform.inverse() * transB;

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

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

				btVector3 vtxInPlaneProjected;// = vtxInPlane - distance * planeNormal;
				vtxInPlane.SubScale( ref planeNormal, distance, out vtxInPlaneProjected );
				btVector3 vtxInPlaneWorld; transB.Apply(ref  vtxInPlaneProjected, out vtxInPlaneWorld );
				btVector3 normalOnSurfaceB; transB.m_basis.Apply( ref planeNormal, out normalOnSurfaceB );

				pointCollector.addContactPoint(
					ref normalOnSurfaceB,
					ref vtxInPlaneWorld,
					distance );
			}
		}
Example #2
0
		/// cast a convex against another convex object
		internal override bool calcTimeOfImpact(
							ref btTransform fromA,
							ref btTransform toA,
							ref btTransform fromB,
							ref btTransform toB,
							CastResult result)
		{


			m_simplexSolver.reset();

			/// compute linear velocity for this interval, to interpolate
			//assume no rotation/angular velocity, assert here?
			btVector3 linVelA, linVelB;
			toA.m_origin.Sub( ref fromA.m_origin, out linVelA  );
			toB.m_origin.Sub( ref fromB.m_origin, out linVelB );

			double radius = (double)( 0.001 );
			double lambda = btScalar.BT_ZERO;
			btVector3 v =  btVector3.xAxis;

			int maxIter = MAX_ITERATIONS;

			btVector3 n = btVector3.Zero;
			bool hasResult = false;
			btVector3 c;
			btVector3 r; linVelA.Sub( ref linVelB, out r  );

			double lastLambda = lambda;
			//double epsilon = (double)(0.001);

			int numIter = 0;
			//first solution, using GJK
			//	result.drawCoordSystem(sphereTr);

			btPointCollector pointCollector = new btPointCollector();

			btGjkPairDetector gjk = BulletGlobals.GjkPairDetectorPool.Get();
			gjk.Initialize( m_convexA, m_convexB, m_simplexSolver, null);//m_penetrationDepthSolver);		
			btGjkPairDetector.ClosestPointInput input = new btDiscreteCollisionDetectorInterface.ClosestPointInput();

			//we don't use margins during CCD
			//	gjk.setIgnoreMargin(true);

			input.m_transformA = fromA.T;
			input.m_transformB = fromB.T;
			gjk.getClosestPoints( input, pointCollector, null );

			hasResult = pointCollector.m_hasResult;
			c = pointCollector.m_pointInWorld;

            if( hasResult )
			{
				double dist;
				dist = pointCollector.m_distance;
				n = pointCollector.m_normalOnBInWorld;

				//not close enough
				while( dist > radius )
				{
					numIter++;
					if( numIter > maxIter )
					{
						BulletGlobals.GjkPairDetectorPool.Free( gjk );
						return false; //todo: report a failure
					}
					double dLambda = btScalar.BT_ZERO;

					double projectedLinearVelocity = r.dot( ref n );

					dLambda = dist / ( projectedLinearVelocity );

					lambda = lambda - dLambda;

					if( lambda > btScalar.BT_ONE )
					{
						BulletGlobals.GjkPairDetectorPool.Free( gjk );
						return false;
					}

					if( lambda < btScalar.BT_ZERO )
					{
						BulletGlobals.GjkPairDetectorPool.Free( gjk );
						return false;
					}

					//todo: next check with relative epsilon
					if( lambda <= lastLambda )
					{
						BulletGlobals.GjkPairDetectorPool.Free( gjk );
						return false;
						//n.setValue(0,0,0);
						//break;
					}
					lastLambda = lambda;

					//interpolate to next lambda
					result.DebugDraw( lambda );
					btVector3 tmp;
					btVector3.setInterpolate3( out tmp, ref fromA.m_origin, ref toA.m_origin, lambda );
					input.m_transformA.setOrigin( ref tmp );
					btVector3.setInterpolate3( out tmp, ref fromB.m_origin, ref toB.m_origin, lambda );
					input.m_transformB.setOrigin( ref tmp );

					gjk.getClosestPoints( input, pointCollector, null );
					if( pointCollector.m_hasResult )
					{
						if( pointCollector.m_distance < btScalar.BT_ZERO )
						{
							result.m_fraction = lastLambda;
							n = pointCollector.m_normalOnBInWorld;
							result.m_normal = n;
							result.m_hitPoint = pointCollector.m_pointInWorld;
							BulletGlobals.GjkPairDetectorPool.Free( gjk );
							return true;
						}
						c = pointCollector.m_pointInWorld;
						n = pointCollector.m_normalOnBInWorld;
						dist = pointCollector.m_distance;
					}
					else
					{
						//??
						BulletGlobals.GjkPairDetectorPool.Free( gjk );
						return false;
					}

				}

				//is n normalized?
				//don't report time of impact for motion away from the contact normal (or causes minor penetration)
				if( n.dot( ref r ) >= -result.m_allowedPenetration )
				{
					BulletGlobals.GjkPairDetectorPool.Free( gjk );
					return false;
				}

				result.m_fraction = lambda;
				result.m_normal = n;
				result.m_hitPoint = c;
				BulletGlobals.GjkPairDetectorPool.Free( gjk );
				return true;
			}

			BulletGlobals.GjkPairDetectorPool.Free( gjk );
			return false;


		}
		internal override bool calcTimeOfImpact(
						ref btTransform fromA,
						ref btTransform toA,
						ref btTransform fromB,
						ref btTransform toB,
						CastResult result)
		{


			/// compute linear and angular velocity for this interval, to interpolate
			btVector3 linVelA, angVelA, linVelB, angVelB;
			btTransformUtil.calculateVelocity( ref fromA,ref toA, btScalar.BT_ONE, out linVelA, out angVelA );
			btTransformUtil.calculateVelocity( ref fromB, ref toB, btScalar.BT_ONE, out linVelB, out angVelB );


			double boundingRadiusA = m_convexA.getAngularMotionDisc();
			double boundingRadiusB = m_convexB1 != null ? m_convexB1.getAngularMotionDisc() : 0;

			double maxAngularProjectedVelocity = angVelA.length() * boundingRadiusA + angVelB.length() * boundingRadiusB;
			btVector3 relLinVel = ( linVelB - linVelA );

			double relLinVelocLength = btVector3.btDelLength( ref linVelB,ref linVelA );

			if( ( relLinVelocLength + maxAngularProjectedVelocity ) == 0 )
				return false;



			double lambda = btScalar.BT_ZERO;
			btVector3 v = btVector3.xAxis;

			int maxIter = MAX_ITERATIONS;

			btVector3 n = btVector3.Zero;
			bool hasResult = false;
			btVector3 c;

			double lastLambda = lambda;
			//double epsilon = (double)(0.001);

			int numIter = 0;
			//first solution, using GJK


			double radius = 0.001f;
			//	result.drawCoordSystem(sphereTr);

			btPointCollector pointCollector1 = new btPointCollector();

			{

				computeClosestPoints( ref fromA, ref fromB, pointCollector1 );

				hasResult = pointCollector1.m_hasResult;
				c = pointCollector1.m_pointInWorld;
			}

			if( hasResult )
			{
				double dist;
				dist = pointCollector1.m_distance + result.m_allowedPenetration;
				n = pointCollector1.m_normalOnBInWorld;
				double projectedLinearVelocity = relLinVel.dot( n );
				if( ( projectedLinearVelocity + maxAngularProjectedVelocity ) <= btScalar.SIMD_EPSILON )
					return false;

				//not close enough
				while( dist > radius )
				{
					if( result.m_debugDrawer != null )
					{
						result.m_debugDrawer.drawSphere( ref c, 0.2f, ref btVector3.One );
					}
					double dLambda = btScalar.BT_ZERO;

					projectedLinearVelocity = relLinVel.dot( n );


					//don't report time of impact for motion away from the contact normal (or causes minor penetration)
					if( ( projectedLinearVelocity + maxAngularProjectedVelocity ) <= btScalar.SIMD_EPSILON )
						return false;

					dLambda = dist / ( projectedLinearVelocity + maxAngularProjectedVelocity );



					lambda = lambda + dLambda;

					if( lambda > btScalar.BT_ONE )
						return false;

					if( lambda < btScalar.BT_ZERO )
						return false;


					//todo: next check with relative epsilon
					if( lambda <= lastLambda )
					{
						return false;
					}
					lastLambda = lambda;



					//interpolate to next lambda
					btTransform interpolatedTransA, interpolatedTransB, relativeTrans;

					btTransformUtil.integrateTransform( ref fromA, ref linVelA, ref angVelA, lambda, out interpolatedTransA );
					btTransformUtil.integrateTransform( ref fromB, ref linVelB, ref angVelB, lambda, out interpolatedTransB );
					interpolatedTransB.inverseTimes( ref interpolatedTransA, out relativeTrans );

					if( result.m_debugDrawer != null )
					{
						result.m_debugDrawer.drawSphere( ref interpolatedTransA.m_origin, 0.2f, ref btVector3.xAxis );
					}

					result.DebugDraw( lambda );

					btPointCollector pointCollector = new btPointCollector();
					computeClosestPoints( ref interpolatedTransA, ref interpolatedTransB, pointCollector );

					if( pointCollector.m_hasResult )
					{
						dist = pointCollector.m_distance + result.m_allowedPenetration;
						c = pointCollector.m_pointInWorld;
						n = pointCollector.m_normalOnBInWorld;
					}
					else
					{
						result.reportFailure( -1, numIter );
						return false;
					}

					numIter++;
					if( numIter > maxIter )
					{
						result.reportFailure( -2, numIter );
						return false;
					}
				}

				result.m_fraction = lambda;
				result.m_normal = n;
				result.m_hitPoint = c;
				return true;
			}

			return false;

		}