// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // * Neither the name of NVIDIA CORPORATION nor the names of its // contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Copyright (c) 2008-2018 NVIDIA Corporation. All rights reserved. // Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. // Copyright (c) 2001-2004 NovodeX AG. All rights reserved. #ifndef GU_PCM_CONTACT_MESH_CALLBACK_H #define GU_PCM_CONTACT_MESH_CALLBACK_H #include "GuMidphaseInterface.h" #include "GuEntityReport.h" #include "GuHeightFieldUtil.h" #include "GuTriangleCache.h" #include "GuConvexEdgeFlags.h" namespace physx { namespace Gu { template struct PCMMeshContactGenerationCallback : MeshHitCallback { public: const Cm::FastVertex2ShapeScaling& mMeshScaling; const PxU8* PX_RESTRICT mExtraTrigData; bool mIdtMeshScale; static const PxU32 CacheSize = 16; Gu::TriangleCache mCache; PCMMeshContactGenerationCallback(const Cm::FastVertex2ShapeScaling& meshScaling, const PxU8* extraTrigData, bool idtMeshScale) : MeshHitCallback(CallbackMode::eMULTIPLE), mMeshScaling(meshScaling), mExtraTrigData(extraTrigData), mIdtMeshScale(idtMeshScale) { } void flushCache() { if (!mCache.isEmpty()) { (static_cast(this))->template processTriangleCache< CacheSize >(mCache); mCache.reset(); } } virtual PxAgain processHit( const PxRaycastHit& hit, const PxVec3& v0, const PxVec3& v1, const PxVec3& v2, PxReal&, const PxU32* vinds) { if (!(static_cast(this))->doTest(v0, v1, v2)) return true; PxVec3 v[3]; if(mIdtMeshScale) { v[0] = v0; v[1] = v1; v[2] = v2; } else { const PxI32 winding = mMeshScaling.flipsNormal() ? 1 : 0; v[0] = mMeshScaling * v0; v[1 + winding] = mMeshScaling * v1; v[2 - winding] = mMeshScaling * v2; } const PxU32 triangleIndex = hit.faceIndex; const PxU8 extraData = getConvexEdgeFlags(mExtraTrigData, triangleIndex); if (mCache.isFull()) { (static_cast(this))->template processTriangleCache< CacheSize >(mCache); mCache.reset(); } mCache.addTriangle(v, vinds, triangleIndex, extraData); return true; } protected: PCMMeshContactGenerationCallback& operator=(const PCMMeshContactGenerationCallback&); }; template struct PCMHeightfieldContactGenerationCallback : Gu::EntityReport { public: const Gu::HeightFieldUtil& mHfUtil; const PxTransform& mHeightfieldTransform; bool mBoundaryCollisions; PCMHeightfieldContactGenerationCallback(const Gu::HeightFieldUtil& hfUtil, const PxTransform& heightfieldTransform) : mHfUtil(hfUtil), mHeightfieldTransform(heightfieldTransform) { mBoundaryCollisions = !(hfUtil.getHeightField().getFlags() & PxHeightFieldFlag::eNO_BOUNDARY_EDGES); } // PT: TODO: refactor/unify with similar code in other places virtual PxAgain onEvent(PxU32 nb, PxU32* indices) { const PxU32 CacheSize = 16; Gu::TriangleCache cache; const PxU32 nbPasses = (nb+(CacheSize-1))/CacheSize; PxU32 nbTrigs = nb; PxU32* inds0 = indices; const PxU8 nextInd[] = {2,0,1}; for(PxU32 i = 0; i < nbPasses; ++i) { cache.mNumTriangles = 0; PxU32 trigCount = PxMin(nbTrigs, CacheSize); nbTrigs -= trigCount; while(trigCount--) { PxU32 triangleIndex = *(inds0++); PxU32 vertIndices[3]; PxTriangle currentTriangle; // in world space PxU32 adjInds[3]; mHfUtil.getTriangle(mHeightfieldTransform, currentTriangle, vertIndices, adjInds, triangleIndex, false, false); PxVec3 normal; currentTriangle.normal(normal); PxU8 triFlags = 0; //KS - temporary until we can calculate triFlags for HF for(PxU32 a = 0; a < 3; ++a) { if (adjInds[a] != 0xFFFFFFFF) { PxTriangle adjTri; PxU32 inds[3]; mHfUtil.getTriangle(mHeightfieldTransform, adjTri, inds, NULL, adjInds[a], false, false); //We now compare the triangles to see if this edge is active PX_ASSERT(inds[0] == vertIndices[a] || inds[1] == vertIndices[a] || inds[2] == vertIndices[a]); PX_ASSERT(inds[0] == vertIndices[(a + 1) % 3] || inds[1] == vertIndices[(a + 1) % 3] || inds[2] == vertIndices[(a + 1) % 3]); PxVec3 adjNormal; adjTri.denormalizedNormal(adjNormal); PxU32 otherIndex = nextInd[a]; PxF32 projD = adjNormal.dot(currentTriangle.verts[otherIndex] - adjTri.verts[0]); if (projD < 0.f) { adjNormal.normalize(); PxF32 proj = adjNormal.dot(normal); if (proj < 0.997f) { triFlags |= (1 << (a + 3)); } } } else if (mBoundaryCollisions) triFlags |= (1 << (a + 3)); //Mark as boudary active edge else triFlags |= (1 << a); //Mark as silhouette edge } cache.addTriangle(currentTriangle.verts, vertIndices, triangleIndex, triFlags); } PX_ASSERT(cache.mNumTriangles <= 16); (static_cast(this))->template processTriangleCache< CacheSize >(cache); } return true; } protected: PCMHeightfieldContactGenerationCallback& operator=(const PCMHeightfieldContactGenerationCallback&); }; }//Gu }//physx #endif