S-H clipping

Please don't post Bullet support questions here, use the above forums instead.
Post Reply
c0der
Posts: 74
Joined: Sun Jul 08, 2012 11:32 am

S-H clipping

Post by c0der »

Anyone have issues with S-H clipping with the Edge-Face case of an OBB? Sometimes, I get 1 contact instead of two, in the middle of a face.

Code: Select all

void getEdgeFaceClippedContactData(AMG3DPlane clippingPlanes[4], const AMG3DVector4 vSubjectVertices[2], const AMG3DContactID subjectIDs[2], 
								   AMG3DContactData *pContactData)
{
	AMG3DContactData clippedContactsInputList;
	AMG3DContactData clippedContactsOutputList;
	int iCountInputList=0;
	int iCountOutputList=0;

	for(int i=0; i<2; ++i) {
		clippedContactsOutputList.contacts[i].vContactPoint = vSubjectVertices[i];
		
		// The clipping edge
		clippedContactsOutputList.contacts[i].contactID.ec.iEdge1BoxID		= subjectIDs[i].ec.iEdge1BoxID;
		clippedContactsOutputList.contacts[i].contactID.ec.iEdge1Index		= subjectIDs[i].ec.iEdge1Index;
		
		// The subject edge
		clippedContactsOutputList.contacts[i].contactID.ec.iEdge2BoxID		= subjectIDs[i].ec.iEdge2BoxID;
		clippedContactsOutputList.contacts[i].contactID.ec.iEdge2Index		= subjectIDs[i].ec.iEdge2Index;
		
		// The third edge that makes up the subject vertex
		clippedContactsOutputList.contacts[i].contactID.ec.iEdge3BoxID		= subjectIDs[i].ec.iEdge3BoxID;
		clippedContactsOutputList.contacts[i].contactID.ec.iEdge3Index		= subjectIDs[i].ec.iEdge3Index;
	}

	iCountOutputList = 2;

	// For each clipping plane
	for(int i=0; i<4; ++i) {
		clippedContactsInputList = clippedContactsOutputList;
		iCountInputList = iCountOutputList;
		iCountOutputList = 0;
		AMG3DVector4 vS = clippedContactsInputList.contacts[iCountInputList-1].vContactPoint;
		int ivSIndex = iCountInputList-1;

		// Clip each subject vertex against clipping plane and store three edges for each contact to form contact ID
		for(int j=0; j<iCountInputList; ++j) {
			// Vertex J is inside the clipping plane
			AMG3DScalar fD; // Determines the penetration depth of each contact, not required here (face plane only)
			if(pointInsidePlane(clippedContactsInputList.contacts[j].vContactPoint, clippingPlanes[i], &fD)) {
				// Vertex S is outside the clipping plane, clip with respect to S
				if(!pointInsidePlane(vS, clippingPlanes[i], &fD)) {
					AMG3DLineSegment lineSegment(clippedContactsInputList.contacts[j].vContactPoint, vS);
					AMG3DScalar fT;
					AMG3DVector4 vIntersectionPoint;
					bool bIntersect = clippingPlanes[i].intersects(lineSegment, &fT, &vIntersectionPoint);
					clippedContactsOutputList.contacts[iCountOutputList].vContactPoint = vIntersectionPoint;
					
					AMG3DContactID contactvS = clippedContactsInputList.contacts[ivSIndex].contactID;

					if(contactvS.ec.iEdge1BoxID==1) { // Point has been previously clipped
						contactvS.ec.iEdge2BoxID = 1;
						contactvS.ec.iEdge2Index = i; // Now, this vertex ID consists of 2 clipping planes
					}
					else {
						contactvS.ec.iEdge1Index = i;
					}
					
					clippedContactsOutputList.contacts[iCountOutputList].contactID.ec.iEdge1BoxID		= 1;
					clippedContactsOutputList.contacts[iCountOutputList].contactID.ec.iEdge1Index		= contactvS.ec.iEdge1Index;
					clippedContactsOutputList.contacts[iCountOutputList].contactID.ec.iEdge2BoxID		= contactvS.ec.iEdge2BoxID;
					clippedContactsOutputList.contacts[iCountOutputList].contactID.ec.iEdge2Index		= contactvS.ec.iEdge2Index;
					clippedContactsOutputList.contacts[iCountOutputList].contactID.ec.iEdge3BoxID		= contactvS.ec.iEdge3BoxID;
					clippedContactsOutputList.contacts[iCountOutputList].contactID.ec.iEdge3Index		= contactvS.ec.iEdge3Index;

					iCountOutputList++;

					break; // Once vertex clipped against this plane, continue to the next plane
				}

				clippedContactsOutputList.contacts[iCountOutputList].vContactPoint = clippedContactsInputList.contacts[j].vContactPoint;

				AMG3DContactID contactIDs = clippedContactsInputList.contacts[j].contactID;

				// No change, store current subject edge IDs
				clippedContactsOutputList.contacts[iCountOutputList].contactID.ec.iEdge1BoxID		= contactIDs.ec.iEdge1BoxID;
				clippedContactsOutputList.contacts[iCountOutputList].contactID.ec.iEdge1Index		= contactIDs.ec.iEdge1Index;
				clippedContactsOutputList.contacts[iCountOutputList].contactID.ec.iEdge2BoxID		= contactIDs.ec.iEdge2BoxID;
				clippedContactsOutputList.contacts[iCountOutputList].contactID.ec.iEdge2Index		= contactIDs.ec.iEdge2Index;
				clippedContactsOutputList.contacts[iCountOutputList].contactID.ec.iEdge3BoxID		= contactIDs.ec.iEdge3BoxID;
				clippedContactsOutputList.contacts[iCountOutputList].contactID.ec.iEdge3Index		= contactIDs.ec.iEdge3Index;

				iCountOutputList++;	
			}
			else if(pointInsidePlane(vS, clippingPlanes[i], &fD)) { // Vertex J is outside the clipping plane, clip with respect to J
				AMG3DLineSegment lineSegment(clippedContactsInputList.contacts[j].vContactPoint, vS);				
				AMG3DScalar fT;
				AMG3DVector4 vIntersectionPoint;
				bool bIntersect = clippingPlanes[i].intersects(lineSegment, &fT, &vIntersectionPoint);
				clippedContactsOutputList.contacts[iCountOutputList].vContactPoint = vIntersectionPoint;
				
				AMG3DContactID contactvS = clippedContactsInputList.contacts[ivSIndex].contactID;
				AMG3DContactID contactJ = clippedContactsInputList.contacts[j].contactID;

				if(contactJ.ec.iEdge1BoxID==1) { // Point has been previously clipped
					contactvS.ec.iEdge2BoxID = 1;
					contactvS.ec.iEdge2Index = i;
				}
				else {
					contactvS.ec.iEdge1Index = i;
				}

				// Clipping, take 1 clipping edge and 1 subject edge
				clippedContactsOutputList.contacts[iCountOutputList].contactID.ec.iEdge1BoxID		= 1;
				clippedContactsOutputList.contacts[iCountOutputList].contactID.ec.iEdge1Index		= contactvS.ec.iEdge1Index;
				clippedContactsOutputList.contacts[iCountOutputList].contactID.ec.iEdge2BoxID		= contactvS.ec.iEdge2BoxID;
				clippedContactsOutputList.contacts[iCountOutputList].contactID.ec.iEdge2Index		= contactvS.ec.iEdge2Index;
				clippedContactsOutputList.contacts[iCountOutputList].contactID.ec.iEdge3BoxID		= contactvS.ec.iEdge3BoxID;
				clippedContactsOutputList.contacts[iCountOutputList].contactID.ec.iEdge3Index		= contactvS.ec.iEdge3Index;

				iCountOutputList++;

				break; // Once edge clipped against this plane, continue to the next plane
			}
			vS = clippedContactsInputList.contacts[j].vContactPoint;
			ivSIndex = j;
		}
	}

	(*pContactData) = clippedContactsOutputList;
	(*pContactData).iNumContacts = iCountOutputList;
}
With the face-face case, I sometimes get 6 contacts but this is because the clipping planes are not straight so there is some error. However the clipping points are on the edge of the clipping planes so I assume this is OK.

Thanks !
Post Reply