PfxBool pfxIntersectRayBox(const PfxRayInput &ray,PfxRayOutput &out,const PfxBox &box,const PfxTransform3 &transform)
{
	// レイをBoxのローカル座標へ変換
	PfxTransform3 transformBox = orthoInverse(transform);
	PfxVector3 rayStartPosition = transformBox.getUpper3x3() * ray.m_startPosition + transformBox.getTranslation();
	PfxVector3 rayDirection = transformBox.getUpper3x3() * ray.m_direction;
	
	// 交差判定
	PfxFloat tmpVariable=0.0f;
	PfxVector3 tmpNormal(0.0f);
	if(pfxIntersectRayAABB(rayStartPosition,rayDirection,PfxVector3(0.0f),box.m_half,tmpVariable,tmpNormal)) {
		if(tmpVariable > 0.0f && tmpVariable < out.m_variable) {
			out.m_contactFlag = true;
			out.m_variable = tmpVariable;
			out.m_contactPoint = ray.m_startPosition + tmpVariable * ray.m_direction;
			out.m_contactNormal = transform.getUpper3x3() * tmpNormal;
			out.m_subData.m_type = PfxSubData::NONE;
			return true;
		}
	}
	
	return false;
}
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();
}
EpxBool epxConvexConvexContact_local(
	const EpxConvexMesh &convexA,const EpxTransform3 &transformA,
	const EpxConvexMesh &convexB,const EpxTransform3 &transformB,
	EpxVector3 &normal,
	EpxFloat &penetrationDepth,
	EpxVector3 &contactPointA,
	EpxVector3 &contactPointB)
{
	EpxTransform3 transformAB,transformBA;
	EpxMatrix3 matrixAB,matrixBA;
	EpxVector3 offsetAB,offsetBA;
	
	// Bローカル→Aローカルへの変換
	transformAB = orthoInverse(transformA) * transformB;
	matrixAB = transformAB.getUpper3x3();
	offsetAB = transformAB.getTranslation();
	
	// Aローカル→Bローカルへの変換
	transformBA = orthoInverse(transformAB);
	matrixBA = transformBA.getUpper3x3();
	offsetBA = transformBA.getTranslation();
	
	// 最も浅い貫通深度とそのときの分離軸
	EpxFloat distanceMin = -EPX_FLT_MAX;
	EpxVector3 axisMin(0.0f);
	EpxSatType satType = EpxSatTypeEdgeEdge;
	EpxBool axisFlip;
	
	//----------------------------------------------------------------------------
	// 分離軸判定
	
	int satCount = 0;
	
	// 面法線の判定を優先させたいので、エッジ外積→面法線の順に判定
	
	// ConvexAとConvexBの外積を分離軸とする
	EpxUInt32 edgeIdMinA,edgeIdMinB;
	
	for(EpxUInt32 eA=0;eA<convexA.m_numEdges;eA++) {
		const EpxEdge &edgeA = convexA.m_edges[eA];
		if(edgeA.type != EpxEdgeTypeConvex) continue;

		const EpxVector3 edgeVecA = convexA.m_vertices[edgeA.vertId[1]] - convexA.m_vertices[edgeA.vertId[0]];
		
		for(EpxUInt32 eB=0;eB<convexB.m_numEdges;eB++) {
			const EpxEdge &edgeB = convexB.m_edges[eB];
			if(edgeB.type != EpxEdgeTypeConvex) continue;
				
			const EpxVector3 edgeVecB = matrixAB * (convexB.m_vertices[edgeB.vertId[1]] - convexB.m_vertices[edgeB.vertId[0]]);

			// Gauss map algorithm from GDC 2013 physics tutorial
			EpxVector3 eA0 = convexA.m_facets[edgeA.facetId[0]].normal;
			EpxVector3 eA1 = convexA.m_facets[edgeA.facetId[1]].normal;
			EpxVector3 eB0 = -matrixAB * convexB.m_facets[edgeB.facetId[0]].normal;
			EpxVector3 eB1 = -matrixAB * convexB.m_facets[edgeB.facetId[1]].normal;
			if(!isValidEdge(eA0,eA1,eB0,eB1)) continue;
			
			EpxVector3 separatingAxis = cross(edgeVecA,edgeVecB);
			if(lengthSqr(separatingAxis) < EPX_EPSILON*EPX_EPSILON) continue;
			
			separatingAxis = normalize(separatingAxis);

			EpxVector3 pA = convexA.m_vertices[edgeA.vertId[0]];
			EpxVector3 pB = offsetAB + matrixAB * convexB.m_vertices[edgeB.vertId[0]];

			if(dot(separatingAxis,pA) > 0.0f) { // 原点は必ずConvexの内側に存在すること
				separatingAxis = -separatingAxis;
			}
			
			EpxFloat d = dot(separatingAxis,pA - pB);
			
			satCount++;
			if(d >= 0.0f) {
				return false;
			}
			if(distanceMin < d) {
				distanceMin = d;
				axisMin = separatingAxis;
				satType = EpxSatTypeEdgeEdge;
				edgeIdMinA = eA;
				edgeIdMinB = eB;
			}
		}
	}
	
	// ConvexAの面法線を分離軸とする
	for(EpxUInt32 f=0;f<convexA.m_numFacets;f++) {
		const EpxFacet &facet = convexA.m_facets[f];
		const EpxVector3 separatingAxis = facet.normal;
		
		EpxVector3 axisB = matrixBA * separatingAxis;
		EpxVector3 pA = offsetBA + matrixBA * convexA.m_vertices[facet.vertId[0]];
		EpxFloat minB = EPX_FLT_MAX;
		for(EpxUInt32 i=0;i<convexB.m_numVertices;i++) {
			EpxFloat prj = dot(axisB,convexB.m_vertices[i] - pA);
			minB = EPX_MIN(minB,prj);
		}

		satCount++;
		if(minB >= 0.0f) {
			return false;
		}
		if(distanceMin < minB) {
			distanceMin = minB;
			axisMin = -separatingAxis;
			satType = EpxSatTypePointBFacetA;
			axisFlip = true;
		}
	}
		
	// ConvexBの面法線を分離軸とする
	for(EpxUInt32 f=0;f<convexB.m_numFacets;f++) {
		const EpxFacet &facet = convexB.m_facets[f];
		const EpxVector3 separatingAxis = matrixAB * facet.normal;
		
		EpxVector3 pB = offsetAB + matrixAB * convexB.m_vertices[facet.vertId[0]];
		EpxFloat minA = EPX_FLT_MAX;
		for(EpxUInt32 i=0;i<convexA.m_numVertices;i++) {
			EpxFloat prj = dot(separatingAxis,convexA.m_vertices[i] - pB);
			minA = EPX_MIN(minA,prj);
		}

		satCount++;
		if(minA >= 0.0f) {
			return false;
		}
		if(distanceMin < minA) {
			distanceMin = minA;
			axisMin = separatingAxis;
			satType = EpxSatTypePointAFacetB;
			axisFlip = false;
		}
	}
	
	// ここまで到達したので、2つの凸メッシュは交差している。
	// また、反発ベクトル(axisMin)と貫通深度(distanceMin)が求まった。
	// 反発ベクトルはAを押しだす方向をプラスにとる。
	
	//int satTotal = convexA.m_numFacets + convexB.m_numFacets + convexA.m_numEdges * convexB.m_numEdges;
	//epxPrintf("sat check count %d / %d\n",satCount,satTotal);
	
	//----------------------------------------------------------------------------
	// 衝突座標検出
	
	int collCount = 0;

	EpxFloat closestMinSqr = EPX_FLT_MAX;
	EpxVector3 closestPointA,closestPointB;
	EpxVector3 separation = 1.1f * fabs(distanceMin) * axisMin;

	if(satType == EpxSatTypeEdgeEdge) {
		const EpxEdge &edgeA = convexA.m_edges[edgeIdMinA];
		const EpxEdge &edgeB = convexB.m_edges[edgeIdMinB];
		
		EpxVector3 sA,sB;
		
		epxGetClosestTwoSegments(
			separation + convexA.m_vertices[edgeA.vertId[0]],
			separation + convexA.m_vertices[edgeA.vertId[1]],
			offsetAB + matrixAB * convexB.m_vertices[edgeB.vertId[0]],
			offsetAB + matrixAB * convexB.m_vertices[edgeB.vertId[1]],
			sA,sB);
		
		EpxFloat dSqr = lengthSqr(sA-sB);
		closestMinSqr = dSqr;
		closestPointA = sA;
		closestPointB = sB;

		collCount++;
	}
	else {
		// 分離平面を挟んで向かい合う面を抽出
		EpxUInt8 facetsA[EPX_CONVEX_MESH_MAX_FACETS];
		EpxUInt8 facetsB[EPX_CONVEX_MESH_MAX_FACETS];
		EpxUInt8 numFacetsA = 0;
		EpxUInt8 numFacetsB = 0;
		
		if(satType == EpxSatTypePointBFacetA) {
			for(EpxUInt8 fA=0;fA<convexA.m_numFacets;fA++) {
				const EpxFacet &facetA = convexA.m_facets[fA];

				EpxFloat checkA = dot(facetA.normal,-axisMin);
				if(checkA < 0.99f && axisFlip) {
					// 判定軸が面Aの法線のとき、向きの違うAの面は判定しない
					continue;
				}
					
				if(checkA < 0.0f) {
					// 衝突面と逆に向いている面は判定しない
					continue;
				}
				
				facetsA[numFacetsA++] = (EpxUInt8)fA;
			}
			
			EpxFloat checkBMax = -1.0f;
			for(EpxUInt8 fB=0;fB<convexB.m_numFacets;fB++) {
				const EpxFacet &facetB = convexB.m_facets[fB];
				
				EpxFloat checkB = dot(facetB.normal,matrixBA * axisMin);
				
				if(checkB > checkBMax) {
					checkBMax = checkB;
					facetsB[0] = fB;
					numFacetsB = 1;
				}
				else if(checkB > checkBMax - EPX_EPSILON) { // checkB == checkBMax
					facetsB[numFacetsB++] = fB;
				}
			}
		}
		else { // satType == EpxSatTypePointAFacetB
			for(EpxUInt8 fB=0;fB<convexB.m_numFacets;fB++) {
				const EpxFacet &facetB = convexB.m_facets[fB];

				EpxFloat checkB = dot(facetB.normal,matrixBA * axisMin);
				if(checkB < 0.99f && !axisFlip) {
					// 判定軸が面Bの法線のとき、向きの違うBの面は判定しない
					continue;
				}
				
				if(checkB < 0.0f) {
					// 衝突面と逆に向いている面は判定しない
					continue;
				}
				
				facetsB[numFacetsB++] = (EpxUInt8)fB;
			}

			EpxFloat checkAMax = -1.0f;
			for(EpxUInt8 fA=0;fA<convexA.m_numFacets;fA++) {
				const EpxFacet &facetA = convexA.m_facets[fA];
				
				EpxFloat checkA = dot(facetA.normal,-axisMin);
				
				if(checkA > checkAMax) {
					checkAMax = checkA;
					facetsA[0] = fA;
					numFacetsA = 1;
				}
				else if(checkA > checkAMax - EPX_EPSILON) { // checkA == checkAMax
					facetsA[numFacetsA++] = fA;
				}
			}
		}
		
		for(EpxUInt8 fA=0;fA<numFacetsA;fA++) {
			const EpxFacet &facetA = convexA.m_facets[facetsA[fA]];
			
			for(EpxUInt8 fB=0;fB<numFacetsB;fB++) {
				const EpxFacet &facetB = convexB.m_facets[facetsB[fB]];
				
				collCount++;
				
				// 面Aと面Bの最近接点を求める
				EpxVector3 triangleA[3] = {
					separation + convexA.m_vertices[facetA.vertId[0]],
					separation + convexA.m_vertices[facetA.vertId[1]],
					separation + convexA.m_vertices[facetA.vertId[2]],
				};
				
				EpxVector3 triangleB[3] = {
					offsetAB + matrixAB * convexB.m_vertices[facetB.vertId[0]],
					offsetAB + matrixAB * convexB.m_vertices[facetB.vertId[1]],
					offsetAB + matrixAB * convexB.m_vertices[facetB.vertId[2]],
				};
				
				// 頂点A→面Bの最近接点算出
				for(int i=0;i<3;i++) {
					EpxVector3 s;
					epxGetClosestPointTriangle(triangleA[i],triangleB[0],triangleB[1],triangleB[2],matrixAB * facetB.normal,s);
					EpxFloat dSqr = lengthSqr(triangleA[i]-s);
					if(dSqr < closestMinSqr) {
						closestMinSqr = dSqr;
						closestPointA = triangleA[i];
						closestPointB = s;
					}
				}
				
				// 頂点B→面Aの最近接点算出
				for(int i=0;i<3;i++) {
					EpxVector3 s;
					epxGetClosestPointTriangle(triangleB[i],triangleA[0],triangleA[1],triangleA[2],facetA.normal,s);
					EpxFloat dSqr = lengthSqr(triangleB[i]-s);
					if(dSqr < closestMinSqr) {
						closestMinSqr = dSqr;
						closestPointA = s;
						closestPointB = triangleB[i];
					}
				}
			}
		}
	}
	
	//epxPrintf("intersection check count %d\n",collCount);
	
	normal = transformA.getUpper3x3() * axisMin;
	penetrationDepth = distanceMin;
	contactPointA = closestPointA - separation;
	contactPointB = offsetBA + matrixBA * closestPointB;

	return true;
}
PfxBool pfxIntersectRayCapsule(const PfxRayInput &ray,PfxRayOutput &out,const PfxCapsule &capsule,const PfxTransform3 &transform)
{
	// レイをCapsuleのローカル座標へ変換
	PfxTransform3 transformCapsule = orthoInverse(transform);
	PfxVector3 startPosL = transformCapsule.getUpper3x3() * ray.m_startPosition + transformCapsule.getTranslation();
	PfxVector3 rayDirL = transformCapsule.getUpper3x3() * ray.m_direction;
	
	PfxFloat radSqr = capsule.m_radius * capsule.m_radius;

	// 始点がカプセルの内側にあるか判定
	{
		PfxFloat h = fabsf(startPosL[0]);
		if(h > capsule.m_halfLen) h = capsule.m_halfLen;
		PfxVector3 Px(out.m_variable,0,0);
		PfxFloat sqrLen = lengthSqr(startPosL-Px);
		if(sqrLen <= radSqr) return false;
	}

	// カプセルの胴体との交差判定
	do {
		PfxVector3 P(startPosL);
		PfxVector3 D(rayDirL);
		
		P[0] = 0.0f;
		D[0] = 0.0f;
		
		PfxFloat a = dot(D,D);
		PfxFloat b = dot(P,D);
		PfxFloat c = dot(P,P) - radSqr;
		
		PfxFloat d = b * b - a * c;
		
		if(d < 0.0f || fabs(a) < 0.00001f) return false;
		
		PfxFloat tt = ( -b - sqrtf(d) ) / a;
		
		if(tt < 0.0f)
			break;
		else if(tt > 1.0f)
			return false;
		
		if(tt < out.m_variable) {
			PfxVector3 cp = startPosL + tt * rayDirL;
			
			if(fabsf(cp[0]) <= capsule.m_halfLen) {
				out.m_contactFlag = true;
				out.m_variable = tt;
				out.m_contactPoint = PfxVector3(transform * PfxPoint3(cp));
				out.m_contactNormal = transform.getUpper3x3() * normalize(cp);
				out.m_subData.m_type = PfxSubData::NONE;
				return true;
			}
		}
	} while(0);
	
	// カプセルの両端にある球体との交差判定
	PfxFloat a = dot(rayDirL,rayDirL);
	if(fabs(a) < 0.00001f) return false;
	
	do {
		PfxVector3 center(capsule.m_halfLen,0.0f,0.0f);
		PfxVector3 v = startPosL - center;

		PfxFloat b = dot(v,rayDirL);
		PfxFloat c = dot(v,v) - radSqr;

		PfxFloat d = b * b - a * c;
		
		if(d < 0.0f) break;
		
		PfxFloat tt = ( -b - sqrtf(d) ) / a;
		
		if(tt < 0.0f || tt > 1.0f) break;
		
		if(tt < out.m_variable) {
			PfxVector3 cp = startPosL + tt * rayDirL;
			out.m_contactFlag = true;
			out.m_variable = tt;
			out.m_contactPoint = ray.m_startPosition + tt * ray.m_direction;
			out.m_contactNormal = transform.getUpper3x3() * normalize(cp-center);
			out.m_subData.m_type = PfxSubData::NONE;
			return true;
		}
	} while(0);
	
	{
		PfxVector3 center(-capsule.m_halfLen,0.0f,0.0f);
		PfxVector3 v = startPosL - center;

		PfxFloat b = dot(v,rayDirL);
		PfxFloat c = dot(v,v) - radSqr;

		PfxFloat d = b * b - a * c;
		
		if(d < 0.0f) return false;
		
		PfxFloat tt = ( -b - sqrtf(d) ) / a;
		
		if(tt < 0.0f || tt > 1.0f) return false;
		
		if(tt < out.m_variable) {
			PfxVector3 cp = startPosL + out.m_variable * rayDirL;
			out.m_contactFlag = true;
			out.m_variable = tt;
			out.m_contactPoint = ray.m_startPosition + tt * ray.m_direction;
			out.m_contactNormal = transform.getUpper3x3() * normalize(cp-center);
			out.m_subData.m_type = PfxSubData::NONE;
			return true;
		}
	}
	
	return false;
}
PfxBool pfxIntersectRayCylinder(const PfxRayInput &ray,PfxRayOutput &out,const PfxCylinder &cylinder,const PfxTransform3 &transform)
{
	// レイを円柱のローカル座標へ変換
	PfxTransform3 transformCapsule = orthoInverse(transform);
	PfxVector3 startPosL = transformCapsule.getUpper3x3() * ray.m_startPosition + transformCapsule.getTranslation();
	PfxVector3 rayDirL = transformCapsule.getUpper3x3() * ray.m_direction;
	
	PfxFloat radSqr = cylinder.m_radius * cylinder.m_radius;

	// 始点が円柱の内側にあるか判定
	{
		PfxFloat h = startPosL[0];
		if(-cylinder.m_halfLen <= h && h <= cylinder.m_halfLen) {
			PfxVector3 Px(h,0,0);
			PfxFloat sqrLen = lengthSqr(startPosL-Px);
			if(sqrLen <= radSqr) return false;
		}
	}

	// 円柱の胴体との交差判定
	do {
		PfxVector3 P(startPosL);
		PfxVector3 D(rayDirL);
		
		P[0] = 0.0f;
		D[0] = 0.0f;
		
		PfxFloat a = dot(D,D);
		PfxFloat b = dot(P,D);
		PfxFloat c = dot(P,P) - radSqr;
		
		PfxFloat d = b * b - a * c;
		
		if(d < 0.0f) return false; // レイは逸れている
		if(pfxAbsf(a) < 0.00001f) break; // レイがX軸に平行
		
		PfxFloat tt = ( -b - sqrtf(d) ) / a;
		
		if(tt < 0.0f || tt > 1.0f) break;
		
		if(tt < out.m_variable) {
			PfxVector3 cp = startPosL + tt * rayDirL;
			
			if(pfxAbsf(cp[0]) <= cylinder.m_halfLen) {
				out.m_contactFlag = true;
				out.m_variable = tt;
				out.m_contactPoint = PfxVector3(transform * PfxPoint3(cp));
				out.m_contactNormal = transform.getUpper3x3() * normalize(cp);
				out.m_subData.m_type = PfxSubData::NONE;
				return true;
			}
		}
	} while(0);
	
	// 円柱の両端にある平面との交差判定
	{
		if(pfxAbsf(rayDirL[0]) < 0.00001f) return false;
		
		PfxFloat t1 = ( cylinder.m_halfLen - startPosL[0] ) / rayDirL[0];
		PfxFloat t2 = ( - cylinder.m_halfLen - startPosL[0] ) / rayDirL[0];

		PfxFloat tt = SCE_PFX_MIN(t1,t2);
		
		if(tt < 0.0f || tt > 1.0f) return false;

		PfxVector3 p = startPosL + tt * rayDirL;
		p[0] = 0.0f;

		if(lengthSqr(p) < radSqr && tt < out.m_variable) {
			PfxVector3 cp = startPosL + tt * rayDirL;
			out.m_contactFlag = true;
			out.m_variable = tt;
			out.m_contactPoint = ray.m_startPosition + tt * ray.m_direction;
			out.m_contactNormal = transform.getUpper3x3() * ((cp[0]>0.0f)?PfxVector3(1.0,0.0,0.0):PfxVector3(-1.0,0.0,0.0));
			out.m_subData.m_type = PfxSubData::NONE;
			return true;
		}
	}
	
	return false;
}