static FVector FindHeightFieldOpposingNormal(const PxLocationHit& PHit, const FVector& TraceDirectionDenorm, const FVector InNormal) { if (IsInvalidFaceIndex(PHit.faceIndex)) { return InNormal; } PxHeightFieldGeometry PHeightFieldGeom; const bool bReadGeomSuccess = PHit.shape->getHeightFieldGeometry(PHeightFieldGeom); check(bReadGeomSuccess); //we should only call this function when we have a heightfield if (PHeightFieldGeom.heightField) { const PxU32 TriIndex = PHit.faceIndex; const PxTransform PShapeWorldPose = PxShapeExt::getGlobalPose(*PHit.shape, *PHit.actor); PxTriangle Tri; PxMeshQuery::getTriangle(PHeightFieldGeom, PShapeWorldPose, TriIndex, Tri); PxVec3 TriNormal; Tri.normal(TriNormal); return P2UVector(TriNormal); } return InNormal; }
// 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); }
static bool FindHeightFieldOpposingNormal(const PxLocationHit& PHit, const FVector& TraceDirectionDenorm, FVector& OutNormal) { PxHeightFieldGeometry PHeightFieldGeom; bool bSuccess = PHit.shape->getHeightFieldGeometry(PHeightFieldGeom); check(bSuccess); //we should only call this function when we have a heightfield if (PHeightFieldGeom.heightField) { const PxU32 TriIndex = PHit.faceIndex; const PxTransform PShapeWorldPose = PxShapeExt::getGlobalPose(*PHit.shape, *PHit.actor); PxTriangle Tri; PxMeshQuery::getTriangle(PHeightFieldGeom, PShapeWorldPose, TriIndex, Tri); PxVec3 TriNormal; Tri.normal(TriNormal); OutNormal = P2UVector(TriNormal); return true; } return false; }
static PxU32 createInvisibleWalls(const CCTParams& params, const PxTriangle& currentTriangle, TriArray& worldTriangles, IntArray& triIndicesArray) { const PxF32 wallHeight = params.mInvisibleWallHeight; if(wallHeight==0.0f) return 0; PxU32 nbNewTris = 0; // Number of newly created tris const PxVec3& upDirection = params.mUpDirection; PxVec3 normal; currentTriangle.normal(normal); if(testSlope(normal, upDirection, params.mSlopeLimit)) { const PxVec3 upWall = upDirection*wallHeight; PxVec3 v0p = currentTriangle.verts[0] + upWall; PxVec3 v1p = currentTriangle.verts[1] + upWall; PxVec3 v2p = currentTriangle.verts[2] + upWall; // Extrude edge 0-1 PxVec3 faceNormal01; { // 0-1-0p const PxTriangle tri0_1_0p(currentTriangle.verts[0], currentTriangle.verts[1], v0p); worldTriangles.pushBack(tri0_1_0p); // 0p-1-1p const PxTriangle tri0p_1_1p(v0p, currentTriangle.verts[1], v1p); worldTriangles.pushBack(tri0p_1_1p); tri0p_1_1p.normal(faceNormal01); } // Extrude edge 1-2 PxVec3 faceNormal12; { // 1p-1-2p const PxTriangle tri1p_1_2p(v1p, currentTriangle.verts[1], v2p); worldTriangles.pushBack(tri1p_1_2p); // 2p-1-2 const PxTriangle tri2p_1_2(v2p, currentTriangle.verts[1], currentTriangle.verts[2]); worldTriangles.pushBack(tri2p_1_2); tri2p_1_2.normal(faceNormal12); } // Extrude edge 2-0 PxVec3 faceNormal20; { // 0p-2-0 const PxTriangle tri0p_2_0(v0p, currentTriangle.verts[2], currentTriangle.verts[0]); worldTriangles.pushBack(tri0p_2_0); // 0p-2p-2 const PxTriangle tri0p_2p_2(v0p, v2p, currentTriangle.verts[2]); worldTriangles.pushBack(tri0p_2p_2); tri0p_2p_2.normal(faceNormal20); } const PxU32 triIndex = PX_INVALID_U32; for(PxU32 i=0;i<6;i++) triIndicesArray.pushBack(triIndex); nbNewTris += 6; } return nbNewTris; }
// 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; }