// PT: SAT-based version, in box space // AP: uninlining on SPU doesn't help int Gu::triBoxSweepTestBoxSpace(const PxTriangle& tri, const PxVec3& extents, const PxVec3& dir, const PxVec3& oneOverDir, float tmax, float& toi, bool doBackfaceCulling) { // Create triangle normal PxVec3 triNormal; tri.denormalizedNormal(triNormal); // Backface culling if(doBackfaceCulling && (triNormal.dot(dir)) >= 0.0f) // ">=" is important ! return 0; // The SAT test will properly detect initial overlaps, no need for extra tests return testSeparationAxes(tri, extents, triNormal, dir, oneOverDir, tmax, toi); }
// PT: test: new version for CCT, based on code for general sweeps. Just to check it works or not with rotations // TODO: refactor this and the similar code in sweptBox for box-vs-mesh. Not so easy though. static bool sweepBoxVsTriangles(PxU32 nbTris, const PxTriangle* triangles, const Box& box, const PxVec3& unitDir, const PxReal distance, PxSweepHit& sweepHit, PxHitFlags hintFlags, bool isDoubleSided, const PxU32* cachedIndex) { if(!nbTris) return false; const bool meshBothSides = hintFlags & PxHitFlag::eMESH_BOTH_SIDES; const bool doBackfaceCulling = !isDoubleSided && !meshBothSides; // Move to AABB space Matrix34 worldToBox; computeWorldToBoxMatrix(worldToBox, box); const PxVec3 localDir = worldToBox.rotate(unitDir); const PxVec3 localMotion = localDir * distance; bool status = false; sweepHit.distance = distance; //was PX_MAX_F32, but that may trigger an assert in the caller! const PxVec3 oneOverMotion( localDir.x!=0.0f ? 1.0f/localMotion.x : 0.0f, localDir.y!=0.0f ? 1.0f/localMotion.y : 0.0f, localDir.z!=0.0f ? 1.0f/localMotion.z : 0.0f); // PT: experimental code, don't clean up before I test it more and validate it // Project box /*float boxRadius0 = PxAbs(dir.x) * box.extents.x + PxAbs(dir.y) * box.extents.y + PxAbs(dir.z) * box.extents.z;*/ float boxRadius = PxAbs(localDir.x) * box.extents.x + PxAbs(localDir.y) * box.extents.y + PxAbs(localDir.z) * box.extents.z; if(gValidateBoxRadiusComputation) // PT: run this to check the box radius is correctly computed { PxVec3 boxVertices2[8]; box.computeBoxPoints(boxVertices2); float dpmin = FLT_MAX; float dpmax = -FLT_MAX; for(int i=0;i<8;i++) { const float dp = boxVertices2[i].dot(unitDir); if(dp<dpmin) dpmin = dp; if(dp>dpmax) dpmax = dp; } const float goodRadius = (dpmax-dpmin)/2.0f; PX_UNUSED(goodRadius); } const float dpc0 = box.center.dot(unitDir); float localMinDist = 1.0f; #ifdef PX_DEBUG PxU32 totalTestsExpected = nbTris; PxU32 totalTestsReal = 0; PX_UNUSED(totalTestsExpected); PX_UNUSED(totalTestsReal); #endif const PxU32 idx = cachedIndex ? *cachedIndex : 0; PxVec3 bestTriNormal(0.0f); for(PxU32 ii=0;ii<nbTris;ii++) { const PxU32 triangleIndex = getTriangleIndex(ii, idx); const PxTriangle& tri = triangles[triangleIndex]; #ifdef _XBOX if(cullTriangle(tri, unitDir, boxRadius, localMinDist*distance, dpc0)==0.0f) continue; #else if(!cullTriangle(tri, unitDir, boxRadius, localMinDist*distance, dpc0)) continue; #endif #ifdef PX_DEBUG totalTestsReal++; #endif // Move to box space const PxTriangle currentTriangle( worldToBox.transform(tri.verts[0]), worldToBox.transform(tri.verts[1]), worldToBox.transform(tri.verts[2])); PxF32 t = PX_MAX_F32; // could be better! if(triBoxSweepTestBoxSpace(currentTriangle, box.extents, localMotion, oneOverMotion, localMinDist, t, doBackfaceCulling)) { if(t <= localMinDist) { // PT: test if shapes initially overlap if(t==0.0f) { sweepHit.flags = PxHitFlag::eDISTANCE|PxHitFlag::eNORMAL; sweepHit.distance = 0.0f; sweepHit.faceIndex = triangleIndex; sweepHit.normal = -unitDir; return true; } localMinDist = t; sweepHit.distance = t * distance; sweepHit.faceIndex = triangleIndex; status = true; // PT: TODO: optimize this.... already computed in triBoxSweepTestBoxSpace... currentTriangle.denormalizedNormal(bestTriNormal); } } } if(status) { sweepHit.flags = PxHitFlag::eDISTANCE; if(hintFlags & (PxHitFlag::eNORMAL|PxHitFlag::ePOSITION)) { const PxTriangle& tri = triangles[sweepHit.faceIndex]; // Move to box space const PxTriangle currentTriangle( worldToBox.transform(tri.verts[0]), worldToBox.transform(tri.verts[1]), worldToBox.transform(tri.verts[2])); computeBoxTriImpactData(sweepHit.position, sweepHit.normal, box.extents, localDir, localMotion, oneOverMotion, currentTriangle); if(hintFlags & PxHitFlag::eNORMAL) { sweepHit.normal.normalize(); if(shouldFlipNormal(sweepHit.normal, meshBothSides, isDoubleSided, bestTriNormal, localDir)) sweepHit.normal = -sweepHit.normal; sweepHit.normal = box.rotate(sweepHit.normal); sweepHit.flags |= PxHitFlag::eNORMAL; } if(hintFlags & PxHitFlag::ePOSITION) { sweepHit.position = box.rotate(sweepHit.position) + box.center; sweepHit.flags |= PxHitFlag::ePOSITION; } } } return status; }