// 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-2025 NVIDIA Corporation. All rights reserved. // Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. // Copyright (c) 2001-2004 NovodeX AG. All rights reserved. #include "common/PxProfileZone.h" #include "ScBodySim.h" #include "ScShapeSim.h" #include "ScArticulationSim.h" #include "ScScene.h" #include "DyIslandManager.h" using namespace physx; using namespace Sc; /////////////////////////////////////////////////////////////////////////////// void BodySim::addToSpeculativeCCDMap() { if(mNodeIndex.isValid()) { if(isArticulationLink()) mScene.setSpeculativeCCDArticulationLink(mNodeIndex.index()); else mScene.setSpeculativeCCDRigidBody(mNodeIndex.index()); } } void BodySim::removeFromSpeculativeCCDMap() { if(mNodeIndex.isValid()) { if(isArticulationLink()) mScene.resetSpeculativeCCDArticulationLink(mNodeIndex.index()); else mScene.resetSpeculativeCCDRigidBody(mNodeIndex.index()); } } // PT: TODO: consider using a non-member function for this one void BodySim::updateContactDistance(PxReal* contactDistance, PxReal dt, const Bp::BoundsArray& boundsArray) { const PxsRigidBody& llBody = getLowLevelBody(); const PxRigidBodyFlags flags = llBody.getCore().mFlags; // PT: TODO: no need to test eENABLE_SPECULATIVE_CCD if we parsed mSpeculativeCCDRigidBodyBitMap initially if((flags & PxRigidBodyFlag::eENABLE_SPECULATIVE_CCD) && !(llBody.mInternalFlags & PxsRigidBody::eFROZEN)) { // PT: if both CCD flags are enabled we're in "hybrid mode" and we only use speculative contacts for the angular part const PxReal linearInflation = (flags & PxRigidBodyFlag::eENABLE_CCD) ? 0.0f : llBody.getLinearVelocity().magnitude() * dt; const float angVelMagTimesDt = llBody.getAngularVelocity().magnitude() * dt; PxU32 nbElems = getNbElements(); ElementSim** elems = getElements(); while(nbElems--) { ShapeSim* current = static_cast(*elems++); const PxU32 index = current->getElementID(); const PxBounds3& bounds = boundsArray.getBounds(index); const PxReal radius = bounds.getExtents().magnitude(); //Heuristic for angular velocity... const PxReal angularInflation = angVelMagTimesDt * radius; contactDistance[index] = linearInflation + current->getContactOffset() + angularInflation; } } } void Sc::ArticulationSim::updateContactDistance(PxReal* contactDistance, PxReal dt, const Bp::BoundsArray& boundsArray) { const PxU32 size = mBodies.size(); for(PxU32 i=0; iupdateContactDistance(contactDistance, dt, boundsArray); } namespace { class SpeculativeCCDBaseTask : public Cm::Task { PX_NOCOPY(SpeculativeCCDBaseTask) public: const Bp::BoundsArray& mBoundsArray; float* mContactDistances; const float mDt; SpeculativeCCDBaseTask(PxU64 contextID, const Bp::BoundsArray& boundsArray, PxReal* contactDistances, PxReal dt) : Cm::Task (contextID), mBoundsArray (boundsArray), mContactDistances (contactDistances), mDt (dt) {} }; class SpeculativeCCDContactDistanceUpdateTask : public SpeculativeCCDBaseTask { public: static const PxU32 MaxBodies = 128; BodySim* mBodySims[MaxBodies]; PxU32 mNbBodies; SpeculativeCCDContactDistanceUpdateTask(PxU64 contextID, PxReal* contactDistances, PxReal dt, const Bp::BoundsArray& boundsArray) : SpeculativeCCDBaseTask (contextID, boundsArray, contactDistances, dt), mNbBodies (0) {} virtual void runInternal() { const PxU32 nb = mNbBodies; for(PxU32 i=0; iupdateContactDistance(mContactDistances, mDt, mBoundsArray); } virtual const char* getName() const { return "SpeculativeCCDContactDistanceUpdateTask"; } private: PX_NOCOPY(SpeculativeCCDContactDistanceUpdateTask) }; class SpeculativeCCDContactDistanceArticulationUpdateTask : public SpeculativeCCDBaseTask { public: ArticulationSim* mArticulation; SpeculativeCCDContactDistanceArticulationUpdateTask(PxU64 contextID, PxReal* contactDistances, PxReal dt, const Bp::BoundsArray& boundsArray, ArticulationSim* sim) : SpeculativeCCDBaseTask (contextID, boundsArray, contactDistances, dt), mArticulation (sim) {} virtual void runInternal() { mArticulation->updateContactDistance(mContactDistances, mDt, mBoundsArray); } virtual const char* getName() const { return "SpeculativeCCDContactDistanceArticulationUpdateTask"; } private: PX_NOCOPY(SpeculativeCCDContactDistanceArticulationUpdateTask) }; } static SpeculativeCCDContactDistanceUpdateTask* createCCDTask(Cm::FlushPool& pool, PxU64 contextID, PxReal* contactDistances, PxReal dt, const Bp::BoundsArray& boundsArray) { return PX_PLACEMENT_NEW(pool.allocate(sizeof(SpeculativeCCDContactDistanceUpdateTask)), SpeculativeCCDContactDistanceUpdateTask)(contextID, contactDistances, dt, boundsArray); } void Sc::Scene::updateContactDistances(PxBaseTask* continuation) { PX_PROFILE_ZONE("Scene.updateContactDistances", mContextId); Cm::FlushPool& pool = mLLContext->getTaskPool(); IG::IslandSim& islandSim = mSimpleIslandManager->getAccurateIslandSim(); bool hasContactDistanceChanged = mHasContactDistanceChanged; // PT: TODO: it is quite unfortunate that we cannot shortcut parsing the bitmaps. Consider switching to arrays. // We remove sleeping bodies from the map but we never shrink it.... // PT: TODO: why do we need to involve the island manager here? // PT: TODO: why do we do that on sleeping bodies? Why don't we use mActiveBodies? // PxArray mActiveBodies; // Sorted: kinematic before dynamic // ===> because we remove bodies from the bitmap in BodySim::deactivate() //calculate contact distance for speculative CCD shapes if(1) { PxBitMap::Iterator speculativeCCDIter(mSpeculativeCCDRigidBodyBitMap); SpeculativeCCDContactDistanceUpdateTask* ccdTask = createCCDTask(pool, mContextId, mContactDistance->begin(), mDt, *mBoundsArray); PxBitMapPinned& changedMap = mAABBManager->getChangedAABBMgActorHandleMap(); const size_t bodyOffset = PX_OFFSET_OF_RT(BodySim, getLowLevelBody()); //printf("\n"); //PxU32 count = 0; PxU32 nbBodies = 0; PxU32 index; while((index = speculativeCCDIter.getNext()) != PxBitMap::Iterator::DONE) { PxsRigidBody* rigidBody = getRigidBodyFromIG(islandSim, PxNodeIndex(index)); BodySim* bodySim = reinterpret_cast(reinterpret_cast(rigidBody)-bodyOffset); if(bodySim) { //printf("%d\n", bodySim->getActiveListIndex()); //printf("%d: %d\n", count++, bodySim->isActive()); hasContactDistanceChanged = true; ccdTask->mBodySims[nbBodies++] = bodySim; // PT: ### changedMap pattern #1 // PT: TODO: isn't there a problem here? The task function will only touch the shapes whose body has the // speculative flag and isn't frozen, but here we mark all shapes as changed no matter what. // // Also we test some bodySim data and one bit of each ShapeSim here, not great. PxU32 nbElems = bodySim->getNbElements(); ElementSim** elems = bodySim->getElements(); while(nbElems--) { ShapeSim* sim = static_cast(*elems++); if(sim->getFlags() & PxShapeFlag::eSIMULATION_SHAPE) changedMap.growAndSet(sim->getElementID()); } // PT: TODO: better load balancing? if(nbBodies == SpeculativeCCDContactDistanceUpdateTask::MaxBodies) { ccdTask->mNbBodies = nbBodies; nbBodies = 0; startTask(ccdTask, continuation); if(continuation) ccdTask = createCCDTask(pool, mContextId, mContactDistance->begin(), mDt, *mBoundsArray); else ccdTask->mNbBodies = 0; // PT: no need to create a new task in single-threaded mode } } } if(nbBodies) { ccdTask->mNbBodies = nbBodies; startTask(ccdTask, continuation); } } /* else { // PT: codepath without mSpeculativeCCDRigidBodyBitMap PxU32 nb = mActiveBodies.size(); BodyCore** bodies = mActiveBodies.begin(); while(nb--) { const BodyCore* current = *bodies++; BodySim* bodySim = current->getSim(); if(bodySim) { ... } } }*/ //calculate contact distance for articulation links { PxBitMap::Iterator articulateCCDIter(mSpeculativeCDDArticulationBitMap); PxU32 index; while((index = articulateCCDIter.getNext()) != PxBitMap::Iterator::DONE) { ArticulationSim* articulationSim = getArticulationSim(islandSim, PxNodeIndex(index)); if(articulationSim) { hasContactDistanceChanged = true; if(continuation) { SpeculativeCCDContactDistanceArticulationUpdateTask* articulationUpdateTask = PX_PLACEMENT_NEW(pool.allocate(sizeof(SpeculativeCCDContactDistanceArticulationUpdateTask)), SpeculativeCCDContactDistanceArticulationUpdateTask)(mContextId, mContactDistance->begin(), mDt, *mBoundsArray, articulationSim); articulationUpdateTask->setContinuation(continuation); articulationUpdateTask->removeReference(); } else { articulationSim->updateContactDistance(mContactDistance->begin(), mDt, *mBoundsArray); } } } } mHasContactDistanceChanged = hasContactDistanceChanged; } /////////////////////////////////////////////////////////////////////////////// #include "ScNPhaseCore.h" #include "ScShapeInteraction.h" #include "PxsCCD.h" #include "PxsSimulationController.h" #include "CmTransformUtils.h" void Sc::Scene::setCCDContactModifyCallback(PxCCDContactModifyCallback* callback) { mCCDContext->setCCDContactModifyCallback(callback); } PxCCDContactModifyCallback* Sc::Scene::getCCDContactModifyCallback() const { return mCCDContext->getCCDContactModifyCallback(); } void Sc::Scene::setCCDMaxPasses(PxU32 ccdMaxPasses) { mCCDContext->setCCDMaxPasses(ccdMaxPasses); } PxU32 Sc::Scene::getCCDMaxPasses() const { return mCCDContext->getCCDMaxPasses(); } void Sc::Scene::setCCDThreshold(PxReal t) { mCCDContext->setCCDThreshold(t); } PxReal Sc::Scene::getCCDThreshold() const { return mCCDContext->getCCDThreshold(); } void Sc::Scene::collectPostSolverVelocitiesBeforeCCD() { if(mContactReportsNeedPostSolverVelocity) { ActorPairReport*const* actorPairs = mNPhaseCore->getContactReportActorPairs(); PxU32 nbActorPairs = mNPhaseCore->getNbContactReportActorPairs(); for(PxU32 i=0; i < nbActorPairs; i++) { if(i < (nbActorPairs - 1)) PxPrefetchLine(actorPairs[i+1]); ActorPairReport* aPair = actorPairs[i]; ContactStreamManager& cs = aPair->getContactStreamManager(); PxU32 streamManagerFlag = cs.getFlags(); if(streamManagerFlag & ContactStreamManagerFlag::eINVALID_STREAM) continue; PxU8* stream = mNPhaseCore->getContactReportPairData(cs.bufferIndex); if(i + 1 < nbActorPairs) PxPrefetch(&(actorPairs[i+1]->getContactStreamManager())); if(!cs.extraDataSize) continue; else if (streamManagerFlag & ContactStreamManagerFlag::eNEEDS_POST_SOLVER_VELOCITY) cs.setContactReportPostSolverVelocity(stream, aPair->getActorA(), aPair->getActorB()); } } } void Sc::Scene::updateCCDMultiPass(PxBaseTask* parentContinuation) { getCcdBodies().forceSize_Unsafe(mSimulationControllerCallback->getNbCcdBodies()); // second run of the broadphase for making sure objects we have integrated did not tunnel. if(mPublicFlags & PxSceneFlag::eENABLE_CCD) { if(mContactReportsNeedPostSolverVelocity) { // the CCD code will overwrite the post solver body velocities, hence, we need to extract the info // first if any CCD enabled pair requested it. collectPostSolverVelocitiesBeforeCCD(); } //We use 2 CCD task chains to be able to chain together an arbitrary number of ccd passes if(mPostCCDPass.size() != 2) { mPostCCDPass.clear(); mUpdateCCDSinglePass.clear(); mCCDBroadPhase.clear(); mCCDBroadPhaseAABB.clear(); mPostCCDPass.reserve(2); mUpdateCCDSinglePass.reserve(2); mUpdateCCDSinglePass2.reserve(2); mUpdateCCDSinglePass3.reserve(2); mCCDBroadPhase.reserve(2); mCCDBroadPhaseAABB.reserve(2); for (int j = 0; j < 2; j++) { mPostCCDPass.pushBack(Cm::DelegateTask(mContextId, this, "ScScene.postCCDPass")); mUpdateCCDSinglePass.pushBack(Cm::DelegateTask(mContextId, this, "ScScene.updateCCDSinglePass")); mUpdateCCDSinglePass2.pushBack(Cm::DelegateTask(mContextId, this, "ScScene.updateCCDSinglePassStage2")); mUpdateCCDSinglePass3.pushBack(Cm::DelegateTask(mContextId, this, "ScScene.updateCCDSinglePassStage3")); mCCDBroadPhase.pushBack(Cm::DelegateTask(mContextId, this, "ScScene.ccdBroadPhase")); mCCDBroadPhaseAABB.pushBack(Cm::DelegateTask(mContextId, this, "ScScene.ccdBroadPhaseAABB")); } } //reset thread context in a place we know all tasks possibly accessing it, are in sync with. (see US6664) mLLContext->resetThreadContexts(); mCCDContext->updateCCDBegin(); mCCDBroadPhase[0].setContinuation(parentContinuation); mCCDBroadPhaseAABB[0].setContinuation(&mCCDBroadPhase[0]); mCCDBroadPhase[0].removeReference(); mCCDBroadPhaseAABB[0].removeReference(); } } namespace { class UpdateCCDBoundsTask : public Cm::Task { Bp::BoundsArray* mBoundArray; PxsTransformCache* mTransformCache; BodySim** mBodySims; PxU32 mNbToProcess; PxI32* mNumFastMovingShapes; public: static const PxU32 MaxPerTask = 256; UpdateCCDBoundsTask(PxU64 contextID, Bp::BoundsArray* boundsArray, PxsTransformCache* transformCache, BodySim** bodySims, PxU32 nbToProcess, PxI32* numFastMovingShapes) : Cm::Task (contextID), mBoundArray (boundsArray), mTransformCache (transformCache), mBodySims (bodySims), mNbToProcess (nbToProcess), mNumFastMovingShapes(numFastMovingShapes) { } virtual const char* getName() const { return "UpdateCCDBoundsTask";} PxIntBool updateSweptBounds(ShapeSim* sim, BodySim* body) { PX_ASSERT(body==sim->getBodySim()); const PxU32 elementID = sim->getElementID(); const ShapeCore& shapeCore = sim->getCore(); const PxTransform& endPose = mTransformCache->getTransformCache(elementID).transform; const PxGeometry& shapeGeom = shapeCore.getGeometry(); const PxsRigidBody& rigidBody = body->getLowLevelBody(); const PxsBodyCore& bodyCore = body->getBodyCore().getCore(); PX_ALIGN(16, PxTransform shape2World); Cm::getDynamicGlobalPoseAligned(rigidBody.mLastTransform, shapeCore.getShape2Actor(), bodyCore.getBody2Actor(), shape2World); const float ccdThreshold = computeCCDThreshold(shapeGeom); PxBounds3 bounds = Gu::computeBounds(shapeGeom, endPose); PxIntBool isFastMoving; if(1) { // PT: this alternative implementation avoids computing the start bounds for slow moving objects. isFastMoving = (shape2World.p - endPose.p).magnitudeSquared() >= ccdThreshold * ccdThreshold ? 1 : 0; if(isFastMoving) { const PxBounds3 startBounds = Gu::computeBounds(shapeGeom, shape2World); bounds.include(startBounds); } } else { const PxBounds3 startBounds = Gu::computeBounds(shapeGeom, shape2World); isFastMoving = (startBounds.getCenter() - bounds.getCenter()).magnitudeSquared() >= ccdThreshold * ccdThreshold ? 1 : 0; if(isFastMoving) bounds.include(startBounds); } PX_ASSERT(bounds.minimum.x <= bounds.maximum.x && bounds.minimum.y <= bounds.maximum.y && bounds.minimum.z <= bounds.maximum.z); mBoundArray->setBounds(bounds, elementID); return isFastMoving; } virtual void runInternal() { PxU32 activeShapes = 0; const PxU32 nb = mNbToProcess; for(PxU32 i=0; i(*elems++); if(sim->getFlags() & PxU32(PxShapeFlag::eSIMULATION_SHAPE | PxShapeFlag::eTRIGGER_SHAPE)) { const PxIntBool fastMovingShape = updateSweptBounds(sim, &bodySim); activeShapes += fastMovingShape; isFastMoving = isFastMoving | fastMovingShape; } } bodySim.getLowLevelBody().getCore().isFastMoving = isFastMoving!=0; } PxAtomicAdd(mNumFastMovingShapes, PxI32(activeShapes)); } }; } void Sc::Scene::ccdBroadPhaseAABB(PxBaseTask* continuation) { PX_PROFILE_START_CROSSTHREAD("Sim.ccdBroadPhaseComplete", mContextId); PX_PROFILE_ZONE("Sim.ccdBroadPhaseAABB", mContextId); PX_UNUSED(continuation); PxU32 currentPass = mCCDContext->getCurrentCCDPass(); Cm::FlushPool& flushPool = mLLContext->getTaskPool(); mNumFastMovingShapes = 0; //If we are on the 1st pass or we had some sweep hits previous CCD pass, we need to run CCD again if(currentPass == 0 || mCCDContext->getNumSweepHits()) { PxsTransformCache& transformCache = getLowLevelContext()->getTransformCache(); for(PxU32 i = 0; i < mCcdBodies.size(); i+= UpdateCCDBoundsTask::MaxPerTask) { const PxU32 nbToProcess = PxMin(UpdateCCDBoundsTask::MaxPerTask, mCcdBodies.size() - i); UpdateCCDBoundsTask* task = PX_PLACEMENT_NEW(flushPool.allocate(sizeof(UpdateCCDBoundsTask)), UpdateCCDBoundsTask)(mContextId, mBoundsArray, &transformCache, &mCcdBodies[i], nbToProcess, &mNumFastMovingShapes); task->setContinuation(continuation); task->removeReference(); } } } void Sc::Scene::ccdBroadPhase(PxBaseTask* continuation) { PX_PROFILE_ZONE("Sim.ccdBroadPhase", mContextId); PxU32 currentPass = mCCDContext->getCurrentCCDPass(); const PxU32 ccdMaxPasses = mCCDContext->getCCDMaxPasses(); mCCDPass = currentPass+1; //If we are on the 1st pass or we had some sweep hits previous CCD pass, we need to run CCD again if( (currentPass == 0 || mCCDContext->getNumSweepHits()) && mNumFastMovingShapes != 0) { const PxU32 currIndex = currentPass & 1; const PxU32 nextIndex = 1 - currIndex; //Initialize the CCD task chain unless this is the final pass if(currentPass != (ccdMaxPasses - 1)) { mCCDBroadPhase[nextIndex].setContinuation(continuation); mCCDBroadPhaseAABB[nextIndex].setContinuation(&mCCDBroadPhase[nextIndex]); } mPostCCDPass[currIndex].setContinuation(currentPass == ccdMaxPasses-1 ? continuation : &mCCDBroadPhaseAABB[nextIndex]); mUpdateCCDSinglePass3[currIndex].setContinuation(&mPostCCDPass[currIndex]); mUpdateCCDSinglePass2[currIndex].setContinuation(&mUpdateCCDSinglePass3[currIndex]); mUpdateCCDSinglePass[currIndex].setContinuation(&mUpdateCCDSinglePass2[currIndex]); //Do the actual broad phase PxBaseTask* continuationTask = &mUpdateCCDSinglePass[currIndex]; // const PxU32 numCpuTasks = continuationTask->getTaskManager()->getCpuDispatcher()->getWorkerCount(); mCCDBp = true; setupBroadPhaseFirstAndSecondPassTasks(continuationTask); //mAABBManager->updateAABBsAndBP(numCpuTasks, mLLContext->getTaskPool(), &mLLContext->getScratchAllocator(), false, continuationTask, NULL); //Allow the CCD task chain to continue mPostCCDPass[currIndex].removeReference(); mUpdateCCDSinglePass3[currIndex].removeReference(); mUpdateCCDSinglePass2[currIndex].removeReference(); mUpdateCCDSinglePass[currIndex].removeReference(); if(currentPass != (ccdMaxPasses - 1)) { mCCDBroadPhase[nextIndex].removeReference(); mCCDBroadPhaseAABB[nextIndex].removeReference(); } } else if (currentPass == 0) { PX_PROFILE_STOP_CROSSTHREAD("Sim.ccdBroadPhaseComplete", mContextId); mCCDContext->resetContactManagers(); } } void Sc::Scene::updateCCDSinglePass(PxBaseTask* continuation) { PX_PROFILE_ZONE("Sim.updateCCDSinglePass", mContextId); mReportShapePairTimeStamp++; // This will makes sure that new report pairs will get created instead of re-using the existing ones. mAABBManager->postBroadPhase(NULL, *getFlushPool()); finishBroadPhase(continuation); const PxU32 currentPass = mCCDContext->getCurrentCCDPass() + 1; // 0 is reserved for discrete collision phase if(currentPass == 1) // reset the handle map so we only update CCD objects from here on { PxBitMapPinned& changedAABBMgrActorHandles = mAABBManager->getChangedAABBMgActorHandleMap(); //changedAABBMgrActorHandles.clear(); for(PxU32 i = 0; i < mCcdBodies.size();i++) { // PT: ### changedMap pattern #1 PxU32 nbElems = mCcdBodies[i]->getNbElements(); ElementSim** elems = mCcdBodies[i]->getElements(); while(nbElems--) { ShapeSim* sim = static_cast(*elems++); if(sim->getFlags()&PxU32(PxShapeFlag::eSIMULATION_SHAPE | PxShapeFlag::eTRIGGER_SHAPE)) // TODO: need trigger shape here? changedAABBMgrActorHandles.growAndSet(sim->getElementID()); } } } } void Sc::Scene::updateCCDSinglePassStage2(PxBaseTask* continuation) { PX_PROFILE_ZONE("Sim.updateCCDSinglePassStage2", mContextId); postBroadPhaseStage2(continuation); } void Sc::Scene::updateCCDSinglePassStage3(PxBaseTask* continuation) { PX_PROFILE_ZONE("Sim.updateCCDSinglePassStage3", mContextId); mReportShapePairTimeStamp++; // This will makes sure that new report pairs will get created instead of re-using the existing ones. const PxU32 currentPass = mCCDContext->getCurrentCCDPass() + 1; // 0 is reserved for discrete collision phase finishBroadPhaseStage2(currentPass); PX_PROFILE_STOP_CROSSTHREAD("Sim.ccdBroadPhaseComplete", mContextId); //reset thread context in a place we know all tasks possibly accessing it, are in sync with. (see US6664) mLLContext->resetThreadContexts(); mCCDContext->updateCCD(mDt, continuation, mSimpleIslandManager->getAccurateIslandSim(), (mPublicFlags & PxSceneFlag::eDISABLE_CCD_RESWEEP), mNumFastMovingShapes); } static PX_FORCE_INLINE Sc::ShapeInteraction* getSI(PxvContactManagerTouchEvent& evt) { return reinterpret_cast(evt.getCMTouchEventUserData()); } void Sc::Scene::postCCDPass(PxBaseTask* /*continuation*/) { // - Performs sleep check // - Updates touch flags PxU32 currentPass = mCCDContext->getCurrentCCDPass(); PX_ASSERT(currentPass > 0); // to make sure changes to the CCD pass counting get noticed. For contact reports, 0 means discrete collision phase. PxU32 newTouchCount, lostTouchCount, ccdTouchCount; mLLContext->getManagerTouchEventCount(&newTouchCount, &lostTouchCount, &ccdTouchCount); PX_ALLOCA(newTouches, PxvContactManagerTouchEvent, newTouchCount); PX_ALLOCA(lostTouches, PxvContactManagerTouchEvent, lostTouchCount); PX_ALLOCA(ccdTouches, PxvContactManagerTouchEvent, ccdTouchCount); PxsContactManagerOutputIterator outputs = mLLContext->getNphaseImplementationContext()->getContactManagerOutputs(); // Note: For contact notifications it is important that the new touch pairs get processed before the lost touch pairs. // This allows to know for sure if a pair of actors lost all touch (see eACTOR_PAIR_LOST_TOUCH). mLLContext->fillManagerTouchEvents(newTouches, newTouchCount, lostTouches, lostTouchCount, ccdTouches, ccdTouchCount); for(PxU32 i=0; imanagerNewTouch(*si); si->managerNewTouch(currentPass, outputs); if (!si->readFlag(ShapeInteraction::CONTACTS_RESPONSE_DISABLED)) { mSimpleIslandManager->setEdgeConnected(si->getEdgeIndex(), IG::Edge::eCONTACT_MANAGER); } } for(PxU32 i=0; imanagerLostTouch(currentPass, outputs) && !si->readFlag(ShapeInteraction::CONTACTS_RESPONSE_DISABLED)) addToLostTouchList(si->getActor0(), si->getActor1()); mSimpleIslandManager->setEdgeDisconnected(si->getEdgeIndex()); } for(PxU32 i=0; isendCCDRetouch(currentPass, outputs); } checkForceThresholdContactEvents(currentPass); { PxBitMapPinned& changedAABBMgrActorHandles = mAABBManager->getChangedAABBMgActorHandleMap(); for (PxU32 i = 0, s = mCcdBodies.size(); i < s; i++) { BodySim*const body = mCcdBodies[i]; if(i+8 < s) PxPrefetch(mCcdBodies[i+8], 512); PX_ASSERT(body->getBody2World().p.isFinite()); PX_ASSERT(body->getBody2World().q.isFinite()); body->updateCached(&changedAABBMgrActorHandles); } ArticulationCore* const* articList = mArticulations.getEntries(); for(PxU32 i=0;igetSim()->updateCached(&changedAABBMgrActorHandles); } }