PfxInt32 pfxContactTriMeshSphere(
	PfxContactCache &contacts,
	const PfxTriMesh *meshA,
	const PfxTransform3 &transformA,
	const PfxSphere &sphereB,
	const PfxTransform3 &transformB,
	PfxFloat distanceThreshold)
{
	(void) distanceThreshold;

	PfxTransform3 transformAB,transformBA;
	PfxMatrix3 matrixBA;
	PfxVector3 offsetBA;

	// Bローカル→Aローカルへの変換
	transformAB = orthoInverse(transformA) * transformB;

	// Aローカル→Bローカルへの変換
	transformBA = orthoInverse(transformAB);

	matrixBA = transformBA.getUpper3x3();
	offsetBA = transformBA.getTranslation();

	//-------------------------------------------
	// 判定する面を絞り込む

	PfxUInt8 SCE_PFX_ALIGNED(16) selFacets[SCE_PFX_NUMMESHFACETS] = {0};
	PfxUInt32 numSelFacets = 0;

	PfxVector3 aabbB(sphereB.m_radius);
	numSelFacets = pfxGatherFacets(meshA,(PfxFloat*)&aabbB,offsetBA,matrixBA,selFacets);

	if(numSelFacets == 0) {
		return 0;
	}

	//-----------------------------------------------
	// 判定

	PfxContactCache localContacts;

	// TriangleMeshの面->sphereの判定
	// ※TriangleMesh座標系
	{
		for(PfxUInt32 f = 0; f < numSelFacets; f++ ) {
			const PfxFacet &facet = meshA->m_facets[selFacets[f]];

			const PfxVector3 facetNormal = pfxReadVector3(facet.m_normal);

			const PfxVector3 facetPnts[3] = {
				meshA->m_verts[facet.m_vertIds[0]],
				meshA->m_verts[facet.m_vertIds[1]],
				meshA->m_verts[facet.m_vertIds[2]],
			};
			
			const PfxEdge *edge[3] = {
				&meshA->m_edges[facet.m_edgeIds[0]],
				&meshA->m_edges[facet.m_edgeIds[1]],
				&meshA->m_edges[facet.m_edgeIds[2]],
			};
			
			PfxVector3 sepAxis,pntA,pntB;
			
			PfxUInt32 edgeChk = 
				((edge[0]->m_angleType==SCE_PFX_EDGE_CONVEX)?0x00:0x01) |
				((edge[1]->m_angleType==SCE_PFX_EDGE_CONVEX)?0x00:0x02) |
				((edge[2]->m_angleType==SCE_PFX_EDGE_CONVEX)?0x00:0x04);
			
			pfxContactTriangleSphere(localContacts,selFacets[f],
									facetNormal,facetPnts[0],facetPnts[1],facetPnts[2],
									facet.m_thickness,
									0.5f*SCE_PFX_PI*(edge[0]->m_tilt/255.0f),
									0.5f*SCE_PFX_PI*(edge[1]->m_tilt/255.0f),
									0.5f*SCE_PFX_PI*(edge[2]->m_tilt/255.0f),
									edgeChk,
									sphereB.m_radius,transformAB.getTranslation());
		}
	}

	for(int i=0;i<localContacts.getNumContacts();i++) {
		PfxSubData subData = localContacts.getSubData(i);
		
		const PfxFacet &facet = meshA->m_facets[subData.getFacetId()];
		
		PfxTriangle triangleA(
			meshA->m_verts[facet.m_vertIds[0]],
			meshA->m_verts[facet.m_vertIds[1]],
			meshA->m_verts[facet.m_vertIds[2]]);
		
		PfxFloat s=0.0f,t=0.0f;
		pfxGetLocalCoords(PfxVector3(localContacts.getLocalPointA(i)),triangleA,s,t);
		subData.m_type = PfxSubData::MESH_INFO;
		subData.setFacetLocalS(s);
		subData.setFacetLocalT(t);
		
		contacts.addContactPoint(
			localContacts.getDistance(i),
			transformA.getUpper3x3() * localContacts.getNormal(i),
			localContacts.getLocalPointA(i),
			transformBA * localContacts.getLocalPointB(i),
			subData);
	}

	return contacts.getNumContacts();
}
PfxInt32 pfxContactLargeTriMesh(
				PfxContactCache &contacts,
				const PfxLargeTriMesh *lmeshA,
				const PfxTransform3 &transformA,
				const PfxShape &shapeB,
				const PfxTransform3 &transformB,
				PfxFloat distanceThreshold)
{
	PfxTransform3 transformAB;
	PfxMatrix3 matrixAB;
	PfxVector3 offsetAB;
	
	// Bローカル→Aローカルへの変換
	transformAB = orthoInverse(transformA) * transformB;
	matrixAB = transformAB.getUpper3x3();
	offsetAB = transformAB.getTranslation();
	
	// -----------------------------------------------------
	// LargeTriMeshに含まれるTriMeshのAABBと凸体のAABBを判定し、
	// 交差するものを個別に衝突判定する。※LargeMesh座標系
	
	PfxVector3 shapeHalf(0.0f);
	PfxVector3 shapeCenter = offsetAB;
	

	switch(shapeB.getType()) {
		case kPfxShapeSphere:
		shapeHalf = PfxVector3(shapeB.getSphere().m_radius);
		break;
		
		case kPfxShapeCapsule:
		{
			PfxCapsule capsule = shapeB.getCapsule();
			shapeHalf = absPerElem(matrixAB) * PfxVector3(capsule.m_halfLen+capsule.m_radius,capsule.m_radius,capsule.m_radius);
		}
		break;
		
		case kPfxShapeCylinder:
		{
			PfxCylinder cylinder = shapeB.getCylinder();
			shapeHalf = absPerElem(matrixAB) * PfxVector3(cylinder.m_halfLen,cylinder.m_radius,cylinder.m_radius);
		}
		break;
		
		case kPfxShapeBox:
		shapeHalf = absPerElem(matrixAB) * shapeB.getBox().m_half;
		break;
		
		case kPfxShapeConvexMesh:
	shapeHalf = absPerElem(matrixAB) * shapeB.getConvexMesh()->m_half;
		break;
		
		default:
		break;
	}

	// -----------------------------------------------------
	// アイランドとの衝突判定

	PfxVecInt3 aabbMinL,aabbMaxL;
	lmeshA->getLocalPosition((shapeCenter-shapeHalf),(shapeCenter+shapeHalf),aabbMinL,aabbMaxL);
	
	PfxUInt32 numIslands = lmeshA->m_numIslands;

	{
	for(PfxUInt32 i=0;i<numIslands;i++) {
		// AABBチェック
		PfxAabb16 aabbB = lmeshA->m_aabbList[i];
		if(aabbMaxL.getX() < pfxGetXMin(aabbB) || aabbMinL.getX() > pfxGetXMax(aabbB)) continue;
		if(aabbMaxL.getY() < pfxGetYMin(aabbB) || aabbMinL.getY() > pfxGetYMax(aabbB)) continue;
		if(aabbMaxL.getZ() < pfxGetZMin(aabbB) || aabbMinL.getZ() > pfxGetZMax(aabbB)) continue;
		
		PfxTriMesh *island = &lmeshA->m_islands[i];

			// 衝突判定
			PfxContactCache localContacts;
			switch(shapeB.getType()) {
				case kPfxShapeSphere:
				pfxContactTriMeshSphere(localContacts,island,transformA,shapeB.getSphere(),transformB,distanceThreshold);
				break;
				
				case kPfxShapeCapsule:
				pfxContactTriMeshCapsule(localContacts,island,transformA,shapeB.getCapsule(),transformB,distanceThreshold);
				break;
				
				case kPfxShapeBox:
				pfxContactTriMeshBox(localContacts,island,transformA,shapeB.getBox(),transformB,distanceThreshold);
				break;
				
				case kPfxShapeCylinder:
				pfxContactTriMeshCylinder(localContacts,island,transformA,shapeB.getCylinder(),transformB,distanceThreshold);
				break;
				
				case kPfxShapeConvexMesh:
			pfxContactTriMeshConvex(localContacts,island,transformA,*shapeB.getConvexMesh(),transformB,distanceThreshold);
				break;
				
				default:
				break;
			}

			
			// 衝突点を追加
			for(int j=0;j<localContacts.getNumContacts();j++) {
				PfxSubData subData = localContacts.getSubData(j);
				subData.setIslandId(i);
				contacts.addContactPoint(
					localContacts.getDistance(j),
					localContacts.getNormal(j),
					localContacts.getLocalPointA(j),
					localContacts.getLocalPointB(j),
					subData);
			}
		}
	}


	return contacts.getNumContacts();
}