571 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			571 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
|  | /*
 | ||
|  | Bullet Continuous Collision Detection and Physics Library | ||
|  | Copyright (c) 2011 Advanced Micro Devices, Inc.  http://bulletphysics.org
 | ||
|  | 
 | ||
|  | 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. | ||
|  | */ | ||
|  | 
 | ||
|  | 
 | ||
|  | ///This file was written by Erwin Coumans
 | ||
|  | ///Separating axis rest based on work from Pierre Terdiman, see
 | ||
|  | ///And contact clipping based on work from Simon Hobbs
 | ||
|  | 
 | ||
|  | 
 | ||
|  | #include "btPolyhedralContactClipping.h"
 | ||
|  | #include "BulletCollision/CollisionShapes/btConvexPolyhedron.h"
 | ||
|  | 
 | ||
|  | #include <float.h> //for FLT_MAX
 | ||
|  | 
 | ||
|  | int gExpectedNbTests=0; | ||
|  | int gActualNbTests = 0; | ||
|  | bool gUseInternalObject = true; | ||
|  | 
 | ||
|  | // Clips a face to the back of a plane
 | ||
|  | void btPolyhedralContactClipping::clipFace(const btVertexArray& pVtxIn, btVertexArray& ppVtxOut, const btVector3& planeNormalWS,btScalar planeEqWS) | ||
|  | { | ||
|  | 	 | ||
|  | 	int ve; | ||
|  | 	btScalar ds, de; | ||
|  | 	int numVerts = pVtxIn.size(); | ||
|  | 	if (numVerts < 2) | ||
|  | 		return; | ||
|  | 
 | ||
|  | 	btVector3 firstVertex=pVtxIn[pVtxIn.size()-1]; | ||
|  | 	btVector3 endVertex = pVtxIn[0]; | ||
|  | 	 | ||
|  | 	ds = planeNormalWS.dot(firstVertex)+planeEqWS; | ||
|  | 
 | ||
|  | 	for (ve = 0; ve < numVerts; ve++) | ||
|  | 	{ | ||
|  | 		endVertex=pVtxIn[ve]; | ||
|  | 
 | ||
|  | 		de = planeNormalWS.dot(endVertex)+planeEqWS; | ||
|  | 
 | ||
|  | 		if (ds<0) | ||
|  | 		{ | ||
|  | 			if (de<0) | ||
|  | 			{ | ||
|  | 				// Start < 0, end < 0, so output endVertex
 | ||
|  | 				ppVtxOut.push_back(endVertex); | ||
|  | 			} | ||
|  | 			else | ||
|  | 			{ | ||
|  | 				// Start < 0, end >= 0, so output intersection
 | ||
|  | 				ppVtxOut.push_back( 	firstVertex.lerp(endVertex,btScalar(ds * 1.f/(ds - de)))); | ||
|  | 			} | ||
|  | 		} | ||
|  | 		else | ||
|  | 		{ | ||
|  | 			if (de<0) | ||
|  | 			{ | ||
|  | 				// Start >= 0, end < 0 so output intersection and end
 | ||
|  | 				ppVtxOut.push_back(firstVertex.lerp(endVertex,btScalar(ds * 1.f/(ds - de)))); | ||
|  | 				ppVtxOut.push_back(endVertex); | ||
|  | 			} | ||
|  | 		} | ||
|  | 		firstVertex = endVertex; | ||
|  | 		ds = de; | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | static bool TestSepAxis(const btConvexPolyhedron& hullA, const btConvexPolyhedron& hullB, const btTransform& transA,const btTransform& transB, const btVector3& sep_axis, btScalar& depth, btVector3& witnessPointA, btVector3& witnessPointB) | ||
|  | { | ||
|  | 	btScalar Min0,Max0; | ||
|  | 	btScalar Min1,Max1; | ||
|  | 	btVector3 witnesPtMinA,witnesPtMaxA; | ||
|  | 	btVector3 witnesPtMinB,witnesPtMaxB; | ||
|  | 
 | ||
|  | 	hullA.project(transA,sep_axis, Min0, Max0,witnesPtMinA,witnesPtMaxA); | ||
|  | 	hullB.project(transB, sep_axis, Min1, Max1,witnesPtMinB,witnesPtMaxB); | ||
|  | 
 | ||
|  | 	if(Max0<Min1 || Max1<Min0) | ||
|  | 		return false; | ||
|  | 
 | ||
|  | 	btScalar d0 = Max0 - Min1; | ||
|  | 	btAssert(d0>=0.0f); | ||
|  | 	btScalar d1 = Max1 - Min0; | ||
|  | 	btAssert(d1>=0.0f); | ||
|  | 	if (d0<d1) | ||
|  | 	{ | ||
|  | 		depth = d0; | ||
|  | 		witnessPointA = witnesPtMaxA; | ||
|  | 		witnessPointB = witnesPtMinB; | ||
|  | 
 | ||
|  | 	} else | ||
|  | 	{ | ||
|  | 		depth = d1; | ||
|  | 		witnessPointA = witnesPtMinA; | ||
|  | 		witnessPointB = witnesPtMaxB; | ||
|  | 	} | ||
|  | 	 | ||
|  | 	return true; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | static int gActualSATPairTests=0; | ||
|  | 
 | ||
|  | inline bool IsAlmostZero(const btVector3& v) | ||
|  | { | ||
|  | 	if(btFabs(v.x())>1e-6 || btFabs(v.y())>1e-6 || btFabs(v.z())>1e-6)	return false; | ||
|  | 	return true; | ||
|  | } | ||
|  | 
 | ||
|  | #ifdef TEST_INTERNAL_OBJECTS
 | ||
|  | 
 | ||
|  | inline void BoxSupport(const btScalar extents[3], const btScalar sv[3], btScalar p[3]) | ||
|  | { | ||
|  | 	// This version is ~11.000 cycles (4%) faster overall in one of the tests.
 | ||
|  | //	IR(p[0]) = IR(extents[0])|(IR(sv[0])&SIGN_BITMASK);
 | ||
|  | //	IR(p[1]) = IR(extents[1])|(IR(sv[1])&SIGN_BITMASK);
 | ||
|  | //	IR(p[2]) = IR(extents[2])|(IR(sv[2])&SIGN_BITMASK);
 | ||
|  | 	p[0] = sv[0] < 0.0f ? -extents[0] : extents[0]; | ||
|  | 	p[1] = sv[1] < 0.0f ? -extents[1] : extents[1]; | ||
|  | 	p[2] = sv[2] < 0.0f ? -extents[2] : extents[2]; | ||
|  | } | ||
|  | 
 | ||
|  | void InverseTransformPoint3x3(btVector3& out, const btVector3& in, const btTransform& tr) | ||
|  | { | ||
|  | 	const btMatrix3x3& rot = tr.getBasis(); | ||
|  | 	const btVector3& r0 = rot[0]; | ||
|  | 	const btVector3& r1 = rot[1]; | ||
|  | 	const btVector3& r2 = rot[2]; | ||
|  | 
 | ||
|  | 	const btScalar x = r0.x()*in.x() + r1.x()*in.y() + r2.x()*in.z(); | ||
|  | 	const btScalar y = r0.y()*in.x() + r1.y()*in.y() + r2.y()*in.z(); | ||
|  | 	const btScalar z = r0.z()*in.x() + r1.z()*in.y() + r2.z()*in.z(); | ||
|  | 
 | ||
|  | 	out.setValue(x, y, z); | ||
|  | } | ||
|  | 
 | ||
|  |  bool TestInternalObjects( const btTransform& trans0, const btTransform& trans1, const btVector3& delta_c, const btVector3& axis, const btConvexPolyhedron& convex0, const btConvexPolyhedron& convex1, btScalar dmin) | ||
|  | { | ||
|  | 	const btScalar dp = delta_c.dot(axis); | ||
|  | 
 | ||
|  | 	btVector3 localAxis0; | ||
|  | 	InverseTransformPoint3x3(localAxis0, axis,trans0); | ||
|  | 	btVector3 localAxis1; | ||
|  | 	InverseTransformPoint3x3(localAxis1, axis,trans1); | ||
|  | 
 | ||
|  | 	btScalar p0[3]; | ||
|  | 	BoxSupport(convex0.m_extents, localAxis0, p0); | ||
|  | 	btScalar p1[3]; | ||
|  | 	BoxSupport(convex1.m_extents, localAxis1, p1); | ||
|  | 
 | ||
|  | 	const btScalar Radius0 = p0[0]*localAxis0.x() + p0[1]*localAxis0.y() + p0[2]*localAxis0.z(); | ||
|  | 	const btScalar Radius1 = p1[0]*localAxis1.x() + p1[1]*localAxis1.y() + p1[2]*localAxis1.z(); | ||
|  | 
 | ||
|  | 	const btScalar MinRadius = Radius0>convex0.m_radius ? Radius0 : convex0.m_radius; | ||
|  | 	const btScalar MaxRadius = Radius1>convex1.m_radius ? Radius1 : convex1.m_radius; | ||
|  | 
 | ||
|  | 	const btScalar MinMaxRadius = MaxRadius + MinRadius; | ||
|  | 	const btScalar d0 = MinMaxRadius + dp; | ||
|  | 	const btScalar d1 = MinMaxRadius - dp; | ||
|  | 
 | ||
|  | 	const btScalar depth = d0<d1 ? d0:d1; | ||
|  | 	if(depth>dmin) | ||
|  | 		return false; | ||
|  | 	return true; | ||
|  | } | ||
|  | #endif //TEST_INTERNAL_OBJECTS
 | ||
|  | 
 | ||
|  |   | ||
|  |   | ||
|  |  SIMD_FORCE_INLINE void btSegmentsClosestPoints( | ||
|  | 	btVector3& ptsVector, | ||
|  | 	btVector3& offsetA, | ||
|  | 	btVector3& offsetB, | ||
|  | 	btScalar& tA, btScalar& tB, | ||
|  | 	const btVector3& translation, | ||
|  | 	const btVector3& dirA, btScalar hlenA, | ||
|  | 	const btVector3& dirB, btScalar hlenB ) | ||
|  | { | ||
|  | 	// compute the parameters of the closest points on each line segment
 | ||
|  | 
 | ||
|  | 	btScalar dirA_dot_dirB = btDot(dirA,dirB); | ||
|  | 	btScalar dirA_dot_trans = btDot(dirA,translation); | ||
|  | 	btScalar dirB_dot_trans = btDot(dirB,translation); | ||
|  | 
 | ||
|  | 	btScalar denom = 1.0f - dirA_dot_dirB * dirA_dot_dirB; | ||
|  | 
 | ||
|  | 	if ( denom == 0.0f ) { | ||
|  | 		tA = 0.0f; | ||
|  | 	} else { | ||
|  | 		tA = ( dirA_dot_trans - dirB_dot_trans * dirA_dot_dirB ) / denom; | ||
|  | 		if ( tA < -hlenA ) | ||
|  | 			tA = -hlenA; | ||
|  | 		else if ( tA > hlenA ) | ||
|  | 			tA = hlenA; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	tB = tA * dirA_dot_dirB - dirB_dot_trans; | ||
|  | 
 | ||
|  | 	if ( tB < -hlenB ) { | ||
|  | 		tB = -hlenB; | ||
|  | 		tA = tB * dirA_dot_dirB + dirA_dot_trans; | ||
|  | 
 | ||
|  | 		if ( tA < -hlenA ) | ||
|  | 			tA = -hlenA; | ||
|  | 		else if ( tA > hlenA ) | ||
|  | 			tA = hlenA; | ||
|  | 	} else if ( tB > hlenB ) { | ||
|  | 		tB = hlenB; | ||
|  | 		tA = tB * dirA_dot_dirB + dirA_dot_trans; | ||
|  | 
 | ||
|  | 		if ( tA < -hlenA ) | ||
|  | 			tA = -hlenA; | ||
|  | 		else if ( tA > hlenA ) | ||
|  | 			tA = hlenA; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	// compute the closest points relative to segment centers.
 | ||
|  | 
 | ||
|  | 	offsetA = dirA * tA; | ||
|  | 	offsetB = dirB * tB; | ||
|  | 
 | ||
|  | 	ptsVector = translation - offsetA + offsetB; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | bool btPolyhedralContactClipping::findSeparatingAxis(	const btConvexPolyhedron& hullA, const btConvexPolyhedron& hullB, const btTransform& transA,const btTransform& transB, btVector3& sep, btDiscreteCollisionDetectorInterface::Result& resultOut) | ||
|  | { | ||
|  | 	gActualSATPairTests++; | ||
|  | 
 | ||
|  | //#ifdef TEST_INTERNAL_OBJECTS
 | ||
|  | 	const btVector3 c0 = transA * hullA.m_localCenter; | ||
|  | 	const btVector3 c1 = transB * hullB.m_localCenter; | ||
|  | 	const btVector3 DeltaC2 = c0 - c1; | ||
|  | //#endif
 | ||
|  | 
 | ||
|  | 	btScalar dmin = FLT_MAX; | ||
|  | 	int curPlaneTests=0; | ||
|  | 
 | ||
|  | 	int numFacesA = hullA.m_faces.size(); | ||
|  | 	// Test normals from hullA
 | ||
|  | 	for(int i=0;i<numFacesA;i++) | ||
|  | 	{ | ||
|  | 		const btVector3 Normal(hullA.m_faces[i].m_plane[0], hullA.m_faces[i].m_plane[1], hullA.m_faces[i].m_plane[2]); | ||
|  | 		btVector3 faceANormalWS = transA.getBasis() * Normal; | ||
|  | 		if (DeltaC2.dot(faceANormalWS)<0) | ||
|  | 			faceANormalWS*=-1.f; | ||
|  | 
 | ||
|  | 		curPlaneTests++; | ||
|  | #ifdef TEST_INTERNAL_OBJECTS
 | ||
|  | 		gExpectedNbTests++; | ||
|  | 		if(gUseInternalObject && !TestInternalObjects(transA,transB, DeltaC2, faceANormalWS, hullA, hullB, dmin)) | ||
|  | 			continue; | ||
|  | 		gActualNbTests++; | ||
|  | #endif
 | ||
|  | 
 | ||
|  | 		btScalar d; | ||
|  | 		btVector3 wA,wB; | ||
|  | 		if(!TestSepAxis( hullA, hullB, transA,transB, faceANormalWS, d,wA,wB)) | ||
|  | 			return false; | ||
|  | 
 | ||
|  | 		if(d<dmin) | ||
|  | 		{ | ||
|  | 			dmin = d; | ||
|  | 			sep = faceANormalWS; | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	int numFacesB = hullB.m_faces.size(); | ||
|  | 	// Test normals from hullB
 | ||
|  | 	for(int i=0;i<numFacesB;i++) | ||
|  | 	{ | ||
|  | 		const btVector3 Normal(hullB.m_faces[i].m_plane[0], hullB.m_faces[i].m_plane[1], hullB.m_faces[i].m_plane[2]); | ||
|  | 		btVector3 WorldNormal = transB.getBasis() * Normal; | ||
|  | 		if (DeltaC2.dot(WorldNormal)<0) | ||
|  | 			WorldNormal *=-1.f; | ||
|  | 
 | ||
|  | 		curPlaneTests++; | ||
|  | #ifdef TEST_INTERNAL_OBJECTS
 | ||
|  | 		gExpectedNbTests++; | ||
|  | 		if(gUseInternalObject && !TestInternalObjects(transA,transB,DeltaC2, WorldNormal, hullA, hullB, dmin)) | ||
|  | 			continue; | ||
|  | 		gActualNbTests++; | ||
|  | #endif
 | ||
|  | 
 | ||
|  | 		btScalar d; | ||
|  | 		btVector3 wA,wB; | ||
|  | 		if(!TestSepAxis(hullA, hullB,transA,transB, WorldNormal,d,wA,wB)) | ||
|  | 			return false; | ||
|  | 
 | ||
|  | 		if(d<dmin) | ||
|  | 		{ | ||
|  | 			dmin = d; | ||
|  | 			sep = WorldNormal; | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	btVector3 edgeAstart,edgeAend,edgeBstart,edgeBend; | ||
|  | 	int edgeA=-1; | ||
|  | 	int edgeB=-1; | ||
|  | 	btVector3 worldEdgeA; | ||
|  | 	btVector3 worldEdgeB; | ||
|  | 	btVector3 witnessPointA(0,0,0),witnessPointB(0,0,0); | ||
|  | 	 | ||
|  | 
 | ||
|  | 	int curEdgeEdge = 0; | ||
|  | 	// Test edges
 | ||
|  | 	for(int e0=0;e0<hullA.m_uniqueEdges.size();e0++) | ||
|  | 	{ | ||
|  | 		const btVector3 edge0 = hullA.m_uniqueEdges[e0]; | ||
|  | 		const btVector3 WorldEdge0 = transA.getBasis() * edge0; | ||
|  | 		for(int e1=0;e1<hullB.m_uniqueEdges.size();e1++) | ||
|  | 		{ | ||
|  | 			const btVector3 edge1 = hullB.m_uniqueEdges[e1]; | ||
|  | 			const btVector3 WorldEdge1 = transB.getBasis() * edge1; | ||
|  | 
 | ||
|  | 			btVector3 Cross = WorldEdge0.cross(WorldEdge1); | ||
|  | 			curEdgeEdge++; | ||
|  | 			if(!IsAlmostZero(Cross)) | ||
|  | 			{ | ||
|  | 				Cross = Cross.normalize(); | ||
|  | 				if (DeltaC2.dot(Cross)<0) | ||
|  | 					Cross *= -1.f; | ||
|  | 
 | ||
|  | 
 | ||
|  | #ifdef TEST_INTERNAL_OBJECTS
 | ||
|  | 				gExpectedNbTests++; | ||
|  | 				if(gUseInternalObject && !TestInternalObjects(transA,transB,DeltaC2, Cross, hullA, hullB, dmin)) | ||
|  | 					continue; | ||
|  | 				gActualNbTests++; | ||
|  | #endif
 | ||
|  | 
 | ||
|  | 				btScalar dist; | ||
|  | 				btVector3 wA,wB; | ||
|  | 				if(!TestSepAxis( hullA, hullB, transA,transB, Cross, dist,wA,wB)) | ||
|  | 					return false; | ||
|  | 
 | ||
|  | 				if(dist<dmin) | ||
|  | 				{ | ||
|  | 					dmin = dist; | ||
|  | 					sep = Cross; | ||
|  | 					edgeA=e0; | ||
|  | 					edgeB=e1; | ||
|  | 					worldEdgeA = WorldEdge0; | ||
|  | 					worldEdgeB = WorldEdge1; | ||
|  | 					witnessPointA=wA; | ||
|  | 					witnessPointB=wB; | ||
|  | 				} | ||
|  | 			} | ||
|  | 		} | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if (edgeA>=0&&edgeB>=0) | ||
|  | 	{ | ||
|  | //		printf("edge-edge\n");
 | ||
|  | 		//add an edge-edge contact
 | ||
|  | 
 | ||
|  | 		btVector3 ptsVector; | ||
|  | 		btVector3 offsetA; | ||
|  | 		btVector3 offsetB; | ||
|  | 		btScalar tA; | ||
|  | 		btScalar tB; | ||
|  | 
 | ||
|  | 		btVector3 translation = witnessPointB-witnessPointA; | ||
|  | 
 | ||
|  | 		btVector3 dirA = worldEdgeA; | ||
|  | 		btVector3 dirB = worldEdgeB; | ||
|  | 		 | ||
|  | 		btScalar hlenB = 1e30f; | ||
|  | 		btScalar hlenA = 1e30f; | ||
|  | 
 | ||
|  | 		btSegmentsClosestPoints(ptsVector,offsetA,offsetB,tA,tB, | ||
|  | 			translation, | ||
|  | 			dirA, hlenA, | ||
|  | 			dirB,hlenB); | ||
|  | 
 | ||
|  | 		btScalar nlSqrt = ptsVector.length2(); | ||
|  | 		if (nlSqrt>SIMD_EPSILON) | ||
|  | 		{ | ||
|  | 			btScalar nl = btSqrt(nlSqrt); | ||
|  | 			ptsVector *= 1.f/nl; | ||
|  | 			if (ptsVector.dot(DeltaC2)<0.f) | ||
|  | 			{ | ||
|  | 				ptsVector*=-1.f; | ||
|  | 			} | ||
|  | 			btVector3 ptOnB = witnessPointB + offsetB; | ||
|  | 			btScalar distance = nl; | ||
|  | 			resultOut.addContactPoint(ptsVector, ptOnB,-distance); | ||
|  | 		} | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 
 | ||
|  | 	if((DeltaC2.dot(sep))<0.0f) | ||
|  | 		sep = -sep; | ||
|  | 
 | ||
|  | 	return true; | ||
|  | } | ||
|  | 
 | ||
|  | void	btPolyhedralContactClipping::clipFaceAgainstHull(const btVector3& separatingNormal, const btConvexPolyhedron& hullA,  const btTransform& transA, btVertexArray& worldVertsB1,btVertexArray& worldVertsB2, const btScalar minDist, btScalar maxDist,btDiscreteCollisionDetectorInterface::Result& resultOut) | ||
|  | { | ||
|  | 	worldVertsB2.resize(0); | ||
|  | 	btVertexArray* pVtxIn = &worldVertsB1; | ||
|  | 	btVertexArray* pVtxOut = &worldVertsB2; | ||
|  | 	pVtxOut->reserve(pVtxIn->size()); | ||
|  | 
 | ||
|  | 	int closestFaceA=-1; | ||
|  | 	{ | ||
|  | 		btScalar dmin = FLT_MAX; | ||
|  | 		for(int face=0;face<hullA.m_faces.size();face++) | ||
|  | 		{ | ||
|  | 			const btVector3 Normal(hullA.m_faces[face].m_plane[0], hullA.m_faces[face].m_plane[1], hullA.m_faces[face].m_plane[2]); | ||
|  | 			const btVector3 faceANormalWS = transA.getBasis() * Normal; | ||
|  | 		 | ||
|  | 			btScalar d = faceANormalWS.dot(separatingNormal); | ||
|  | 			if (d < dmin) | ||
|  | 			{ | ||
|  | 				dmin = d; | ||
|  | 				closestFaceA = face; | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | 	if (closestFaceA<0) | ||
|  | 		return; | ||
|  | 
 | ||
|  | 	const btFace& polyA = hullA.m_faces[closestFaceA]; | ||
|  | 
 | ||
|  | 		// clip polygon to back of planes of all faces of hull A that are adjacent to witness face
 | ||
|  | 	int numVerticesA = polyA.m_indices.size(); | ||
|  | 	for(int e0=0;e0<numVerticesA;e0++) | ||
|  | 	{ | ||
|  | 		const btVector3& a = hullA.m_vertices[polyA.m_indices[e0]]; | ||
|  | 		const btVector3& b = hullA.m_vertices[polyA.m_indices[(e0+1)%numVerticesA]]; | ||
|  | 		const btVector3 edge0 = a - b; | ||
|  | 		const btVector3 WorldEdge0 = transA.getBasis() * edge0; | ||
|  | 		btVector3 worldPlaneAnormal1 = transA.getBasis()* btVector3(polyA.m_plane[0],polyA.m_plane[1],polyA.m_plane[2]); | ||
|  | 
 | ||
|  | 		btVector3 planeNormalWS1 = -WorldEdge0.cross(worldPlaneAnormal1);//.cross(WorldEdge0);
 | ||
|  | 		btVector3 worldA1 = transA*a; | ||
|  | 		btScalar planeEqWS1 = -worldA1.dot(planeNormalWS1); | ||
|  | 		 | ||
|  | //int otherFace=0;
 | ||
|  | #ifdef BLA1
 | ||
|  | 		int otherFace = polyA.m_connectedFaces[e0]; | ||
|  | 		btVector3 localPlaneNormal (hullA.m_faces[otherFace].m_plane[0],hullA.m_faces[otherFace].m_plane[1],hullA.m_faces[otherFace].m_plane[2]); | ||
|  | 		btScalar localPlaneEq = hullA.m_faces[otherFace].m_plane[3]; | ||
|  | 
 | ||
|  | 		btVector3 planeNormalWS = transA.getBasis()*localPlaneNormal; | ||
|  | 		btScalar planeEqWS=localPlaneEq-planeNormalWS.dot(transA.getOrigin()); | ||
|  | #else 
 | ||
|  | 		btVector3 planeNormalWS = planeNormalWS1; | ||
|  | 		btScalar planeEqWS=planeEqWS1; | ||
|  | 		 | ||
|  | #endif
 | ||
|  | 		//clip face
 | ||
|  | 
 | ||
|  | 		clipFace(*pVtxIn, *pVtxOut,planeNormalWS,planeEqWS); | ||
|  | 		btSwap(pVtxIn,pVtxOut); | ||
|  | 		pVtxOut->resize(0); | ||
|  | 	} | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | //#define ONLY_REPORT_DEEPEST_POINT
 | ||
|  | 
 | ||
|  | 	btVector3 point; | ||
|  | 	 | ||
|  | 
 | ||
|  | 	// only keep points that are behind the witness face
 | ||
|  | 	{ | ||
|  | 		btVector3 localPlaneNormal (polyA.m_plane[0],polyA.m_plane[1],polyA.m_plane[2]); | ||
|  | 		btScalar localPlaneEq = polyA.m_plane[3]; | ||
|  | 		btVector3 planeNormalWS = transA.getBasis()*localPlaneNormal; | ||
|  | 		btScalar planeEqWS=localPlaneEq-planeNormalWS.dot(transA.getOrigin()); | ||
|  | 		for (int i=0;i<pVtxIn->size();i++) | ||
|  | 		{ | ||
|  | 			btVector3 vtx = pVtxIn->at(i); | ||
|  | 			btScalar depth = planeNormalWS.dot(vtx)+planeEqWS; | ||
|  | 			if (depth <=minDist) | ||
|  | 			{ | ||
|  | //				printf("clamped: depth=%f to minDist=%f\n",depth,minDist);
 | ||
|  | 				depth = minDist; | ||
|  | 			} | ||
|  | 
 | ||
|  | 			if (depth <=maxDist) | ||
|  | 			{ | ||
|  | 				btVector3 point = pVtxIn->at(i); | ||
|  | #ifdef ONLY_REPORT_DEEPEST_POINT
 | ||
|  | 				curMaxDist = depth; | ||
|  | #else
 | ||
|  | #if 0
 | ||
|  | 				if (depth<-3) | ||
|  | 				{ | ||
|  | 					printf("error in btPolyhedralContactClipping depth = %f\n", depth); | ||
|  | 					printf("likely wrong separatingNormal passed in\n"); | ||
|  | 				}  | ||
|  | #endif				
 | ||
|  | 				resultOut.addContactPoint(separatingNormal,point,depth); | ||
|  | #endif
 | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | #ifdef ONLY_REPORT_DEEPEST_POINT
 | ||
|  | 	if (curMaxDist<maxDist) | ||
|  | 	{ | ||
|  | 		resultOut.addContactPoint(separatingNormal,point,curMaxDist); | ||
|  | 	} | ||
|  | #endif //ONLY_REPORT_DEEPEST_POINT
 | ||
|  | 
 | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | void	btPolyhedralContactClipping::clipHullAgainstHull(const btVector3& separatingNormal1, const btConvexPolyhedron& hullA, const btConvexPolyhedron& hullB, const btTransform& transA,const btTransform& transB, const btScalar minDist, btScalar maxDist,btVertexArray& worldVertsB1,btVertexArray& worldVertsB2,btDiscreteCollisionDetectorInterface::Result& resultOut) | ||
|  | { | ||
|  | 
 | ||
|  | 	btVector3 separatingNormal = separatingNormal1.normalized(); | ||
|  | //	const btVector3 c0 = transA * hullA.m_localCenter;
 | ||
|  | //	const btVector3 c1 = transB * hullB.m_localCenter;
 | ||
|  | 	//const btVector3 DeltaC2 = c0 - c1;
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 	int closestFaceB=-1; | ||
|  | 	btScalar dmax = -FLT_MAX; | ||
|  | 	{ | ||
|  | 		for(int face=0;face<hullB.m_faces.size();face++) | ||
|  | 		{ | ||
|  | 			const btVector3 Normal(hullB.m_faces[face].m_plane[0], hullB.m_faces[face].m_plane[1], hullB.m_faces[face].m_plane[2]); | ||
|  | 			const btVector3 WorldNormal = transB.getBasis() * Normal; | ||
|  | 			btScalar d = WorldNormal.dot(separatingNormal); | ||
|  | 			if (d > dmax) | ||
|  | 			{ | ||
|  | 				dmax = d; | ||
|  | 				closestFaceB = face; | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | 	worldVertsB1.resize(0); | ||
|  | 				{ | ||
|  | 					const btFace& polyB = hullB.m_faces[closestFaceB]; | ||
|  | 					const int numVertices = polyB.m_indices.size(); | ||
|  | 					for(int e0=0;e0<numVertices;e0++) | ||
|  | 					{ | ||
|  | 						const btVector3& b = hullB.m_vertices[polyB.m_indices[e0]]; | ||
|  | 						worldVertsB1.push_back(transB*b); | ||
|  | 					} | ||
|  | 				} | ||
|  | 
 | ||
|  | 	 | ||
|  | 	if (closestFaceB>=0) | ||
|  | 		clipFaceAgainstHull(separatingNormal, hullA, transA,worldVertsB1, worldVertsB2,minDist, maxDist,resultOut); | ||
|  | 
 | ||
|  | } |