void FPhysScene::ProcessPhysScene(uint32 SceneType) { SCOPE_CYCLE_COUNTER(STAT_TotalPhysicsTime); SCOPE_CYCLE_COUNTER(STAT_PhysicsFetchDynamicsTime); check(SceneType < NumPhysScenes); if (bPhysXSceneExecuting[SceneType] == 0) { // Not executing this scene, must call TickPhysScene before calling this function again. UE_LOG(LogPhysics, Log, TEXT("WaitPhysScene`: Not executing this scene (%d) - aborting."), SceneType); return; } if (FrameLagAsync()) { static_assert(PST_MAX == 3, "Physics scene static test failed."); // Here we assume the PST_Sync is the master and never fame lagged if (SceneType == PST_Sync) { // the one frame lagged one should be done by now. check(!FrameLaggedPhysicsSubsceneCompletion[PST_Async].GetReference() || FrameLaggedPhysicsSubsceneCompletion[PST_Async]->IsComplete()); } else if (SceneType == PST_Async) { FrameLaggedPhysicsSubsceneCompletion[PST_Async] = NULL; } } // Reset execution flag //This fetches and gets active transforms. It's important that the function that calls this locks because getting the transforms and using the data must be an atomic operation #if WITH_PHYSX PxScene* PScene = GetPhysXScene(SceneType); check(PScene); PxU32 OutErrorCode = 0; #if !WITH_APEX PScene->lockWrite(); PScene->fetchResults(true, &OutErrorCode); PScene->unlockWrite(); #else // #if !WITH_APEX // The APEX scene calls the fetchResults function for the PhysX scene, so we only call ApexScene->fetchResults(). NxApexScene* ApexScene = GetApexScene(SceneType); check(ApexScene); ApexScene->fetchResults(true, &OutErrorCode); #endif // #if !WITH_APEX UpdateActiveTransforms(SceneType); if (OutErrorCode != 0) { UE_LOG(LogPhysics, Log, TEXT("PHYSX FETCHRESULTS ERROR: %d"), OutErrorCode); } #endif // WITH_PHYSX PhysicsSubsceneCompletion[SceneType] = NULL; bPhysXSceneExecuting[SceneType] = false; }
void FPhysScene::ProcessPhysScene(uint32 SceneType) { SCOPE_CYCLE_COUNTER(STAT_TotalPhysicsTime); SCOPE_CYCLE_COUNTER(STAT_PhysicsFetchDynamicsTime); check(SceneType < NumPhysScenes); if( bPhysXSceneExecuting[SceneType] == 0 ) { // Not executing this scene, must call TickPhysScene before calling this function again. UE_LOG(LogPhysics, Log, TEXT("WaitPhysScene`: Not executing this scene (%d) - aborting."), SceneType); return; } PhysicsSubsceneCompletion[SceneType] = NULL; if (FrameLagAsync()) { checkAtCompileTime(PST_MAX == 2, Assumtiopns_about_physics_scenes); // Here we assume the PST_Sync is the master and never fame lagged if (SceneType == PST_Sync) { // the one frame lagged one should be done by now. check(!FrameLaggedPhysicsSubsceneCompletion[PST_Async].GetReference() || FrameLaggedPhysicsSubsceneCompletion[PST_Async]->IsComplete()); } else { FrameLaggedPhysicsSubsceneCompletion[PST_Async] = NULL; } } #if WITH_PHYSX PxScene* PScene = GetPhysXScene(SceneType); check(PScene); PxU32 OutErrorCode = 0; #if !WITH_APEX PScene->lockWrite(); PScene->fetchResults( true, &OutErrorCode ); PScene->unlockWrite(); #else // #if !WITH_APEX // The APEX scene calls the fetchResults function for the PhysX scene, so we only call ApexScene->fetchResults(). NxApexScene* ApexScene = GetApexScene(SceneType); check(ApexScene); ApexScene->fetchResults( true, &OutErrorCode ); #endif // #if !WITH_APEX if(OutErrorCode != 0) { UE_LOG(LogPhysics, Log, TEXT("PHYSX FETCHRESULTS ERROR: %d"), OutErrorCode); } #endif // WITH_PHYSX // Reset execution flag bPhysXSceneExecuting[SceneType] = false; }
void UDestructibleComponent::AddRadialForce(FVector Origin, float Radius, float Strength, ERadialImpulseFalloff Falloff, bool bAccelChange /* = false */) { #if WITH_APEX if(bIgnoreRadialForce) { return; } if (ApexDestructibleActor == NULL) { return; } PxRigidDynamic** PActorBuffer = NULL; PxU32 PActorCount = 0; if (ApexDestructibleActor->acquirePhysXActorBuffer(PActorBuffer, PActorCount, NxDestructiblePhysXActorQueryFlags::Dynamic)) { PxScene* LockedScene = NULL; while (PActorCount--) { PxRigidDynamic* PActor = *PActorBuffer++; if (PActor != NULL) { if (!LockedScene) { LockedScene = PActor->getScene(); LockedScene->lockWrite(); LockedScene->lockRead(); } AddRadialForceToPxRigidBody_AssumesLocked(*PActor, Origin, Radius, Strength, Falloff, bAccelChange); } if (LockedScene) { LockedScene->unlockRead(); LockedScene->unlockWrite(); LockedScene = NULL; } } ApexDestructibleActor->releasePhysXActorBuffer(); } #endif // #if WITH_APEX }
void UDestructibleComponent::SetCollisionResponseForAllActors(const FCollisionResponseContainer& ResponseOverride) { #if WITH_APEX if (ApexDestructibleActor == NULL) { return; } PxRigidDynamic** PActorBuffer = NULL; PxU32 PActorCount = 0; if (ApexDestructibleActor->acquirePhysXActorBuffer(PActorBuffer, PActorCount)) { PxScene* LockedScene = NULL; while (PActorCount--) { PxRigidDynamic* PActor = *PActorBuffer++; if (PActor != NULL) { FDestructibleChunkInfo* ChunkInfo = FPhysxUserData::Get<FDestructibleChunkInfo>(PActor->userData); if (ChunkInfo != NULL) { if (!LockedScene) { LockedScene = PActor->getScene(); LockedScene->lockWrite(); LockedScene->lockRead(); } SetCollisionResponseForActor(PActor, ChunkInfo->ChunkIndex, &ResponseOverride); // ChunkIndex is the last chunk made visible. But SetCollisionResponseForActor already doesn't respect per-chunk collision properties. } } } if (LockedScene) { LockedScene->unlockRead(); LockedScene->unlockWrite(); LockedScene = NULL; } ApexDestructibleActor->releasePhysXActorBuffer(); } #endif }
MirrorActor::MirrorActor(size_t actorHash, physx::PxRigidActor &actor, MirrorScene &mirrorScene) : mMirrorScene(mirrorScene), mPrimaryActor(&actor), mActorHash(actorHash) { mReleasePosted = false; mMirrorActor = NULL; mShapeCount = 0; PxScene *scene = actor.getScene(); PX_ASSERT(scene); if ( scene ) { scene->lockWrite(__FILE__,__LINE__); mPrimaryGlobalPose = actor.getGlobalPose(); PxPhysics *sdk = &scene->getPhysics(); if ( actor.getType() == physx::PxActorType::eRIGID_STATIC ) { mMirrorActor = CloneStatic(*sdk,actor.getGlobalPose(),actor, mirrorScene.getMirrorFilter()); } else { physx::PxRigidDynamic *rd = static_cast< physx::PxRigidDynamic *>(&actor); mMirrorActor = CloneDynamic(*sdk,actor.getGlobalPose(),*rd, mirrorScene.getMirrorFilter()); if ( mMirrorActor ) { rd = static_cast< physx::PxRigidDynamic *>(mMirrorActor); rd->setRigidDynamicFlag(physx::PxRigidDynamicFlag::eKINEMATIC,true); } } scene->unlockWrite(); if ( mMirrorActor ) { MirrorCommand mc(MCT_CREATE_ACTOR,this); mMirrorScene.postCommand(mc); } } }
/** Exposes ticking of physics-engine scene outside Engine. */ void FPhysScene::TickPhysScene(uint32 SceneType, FGraphEventRef& InOutCompletionEvent) { SCOPE_CYCLE_COUNTER(STAT_TotalPhysicsTime); SCOPE_CYCLE_COUNTER(STAT_PhysicsKickOffDynamicsTime); check(SceneType < NumPhysScenes); if (bPhysXSceneExecuting[SceneType] != 0) { // Already executing this scene, must call WaitPhysScene before calling this function again. UE_LOG(LogPhysics, Log, TEXT("TickPhysScene: Already executing scene (%d) - aborting."), SceneType); return; } #if WITH_SUBSTEPPING if (IsSubstepping(SceneType)) //we don't bother sub-stepping cloth { //We're about to start stepping so swap buffers. Might want to find a better place for this? PhysSubSteppers[SceneType]->SwapBuffers(); } #endif /** * clamp down... if this happens we are simming physics slower than real-time, so be careful with it. * it can improve framerate dramatically (really, it is the same as scaling all velocities down and * enlarging all timesteps) but at the same time, it will screw with networking (client and server will * diverge a lot more.) */ float UseDelta = FMath::Min(UseSyncTime(SceneType) ? SyncDeltaSeconds : DeltaSeconds, MaxPhysicsDeltaTime); // Only simulate a positive time step. if (UseDelta <= 0.f) { if (UseDelta < 0.f) { // only do this if negative. Otherwise, whenever we pause, this will come up UE_LOG(LogPhysics, Warning, TEXT("TickPhysScene: Negative timestep (%f) - aborting."), UseDelta); } return; } #if WITH_PHYSX GatherPhysXStats(GetPhysXScene(SceneType), SceneType); #endif /** * Weight frame time according to PhysScene settings. */ AveragedFrameTime[SceneType] *= FrameTimeSmoothingFactor[SceneType]; AveragedFrameTime[SceneType] += (1.0f - FrameTimeSmoothingFactor[SceneType])*UseDelta; // Set execution flag bPhysXSceneExecuting[SceneType] = true; check(!InOutCompletionEvent.GetReference()); // these should be gone because nothing is outstanding InOutCompletionEvent = FGraphEvent::CreateGraphEvent(); bool bTaskOutstanding = false; #if WITH_PHYSX #if WITH_VEHICLE if (VehicleManager && SceneType == PST_Sync) { float TickTime = AveragedFrameTime[SceneType]; #if WITH_SUBSTEPPING if (IsSubstepping(SceneType)) { TickTime = UseSyncTime(SceneType) ? SyncDeltaSeconds : DeltaSeconds; } #endif VehicleManager->PreTick(TickTime); #if WITH_SUBSTEPPING if (IsSubstepping(SceneType) == false) #endif { VehicleManager->Update(AveragedFrameTime[SceneType]); } } #endif #if !WITH_APEX PxScene* PScene = GetPhysXScene(SceneType); if (PScene && (UseDelta > 0.f)) { PhysXCompletionTask* Task = new PhysXCompletionTask(InOutCompletionEvent, PScene->getTaskManager()); PScene->lockWrite(); PScene->simulate(AveragedFrameTime[SceneType], Task); PScene->unlockWrite(); Task->removeReference(); bTaskOutstanding = true; } #else // #if !WITH_APEX // The APEX scene calls the simulate function for the PhysX scene, so we only call ApexScene->simulate(). NxApexScene* ApexScene = GetApexScene(SceneType); if(ApexScene && UseDelta > 0.f) { #if WITH_SUBSTEPPING if (IsSubstepping(SceneType)) //we don't bother sub-stepping cloth { bTaskOutstanding = SubstepSimulation(SceneType, InOutCompletionEvent); }else #endif { PhysXCompletionTask* Task = new PhysXCompletionTask(InOutCompletionEvent, ApexScene->getTaskManager()); ApexScene->simulate(AveragedFrameTime[SceneType], true, Task); Task->removeReference(); bTaskOutstanding = true; } } #endif // #if !WITH_APEX #endif // WITH_PHYSX if (!bTaskOutstanding) { InOutCompletionEvent->DispatchSubsequents(); // nothing to do, so nothing to wait for } #if WITH_SUBSTEPPING bSubstepping = UPhysicsSettings::Get()->bSubstepping; bSubsteppingAsync = UPhysicsSettings::Get()->bSubsteppingAsync; #endif }