void FPhysScene::UpdateActiveTransforms(uint32 SceneType) { if (SceneType == PST_Cloth) //cloth doesn't bother with updating components to bodies so we don't need to store any transforms { return; } PxScene* PScene = GetPhysXScene(SceneType); check(PScene); SCOPED_SCENE_READ_LOCK(PScene); PxU32 NumTransforms = 0; const PxActiveTransform* PActiveTransforms = PScene->getActiveTransforms(NumTransforms); ActiveBodyInstances[SceneType].Empty(NumTransforms); ActiveDestructibleActors[SceneType].Empty(NumTransforms); for (PxU32 TransformIdx = 0; TransformIdx < NumTransforms; ++TransformIdx) { const PxActiveTransform& PActiveTransform = PActiveTransforms[TransformIdx]; PxRigidActor* RigidActor = PActiveTransform.actor->isRigidActor(); ensure(!RigidActor->userData || !FPhysxUserData::IsGarbage(RigidActor->userData)); if (FBodyInstance* BodyInstance = FPhysxUserData::Get<FBodyInstance>(RigidActor->userData)) { if (BodyInstance->InstanceBodyIndex == INDEX_NONE && BodyInstance->OwnerComponent.IsValid() && BodyInstance->IsInstanceSimulatingPhysics()) { ActiveBodyInstances[SceneType].Add(BodyInstance); } } else if (const FDestructibleChunkInfo* DestructibleChunkInfo = FPhysxUserData::Get<FDestructibleChunkInfo>(RigidActor->userData)) { ActiveDestructibleActors[SceneType].Add(RigidActor); } } }
void UShapeComponent::CreateShapeBodySetupIfNeeded() { if (ShapeBodySetup == nullptr || ShapeBodySetup->IsPendingKill()) { ShapeBodySetup = NewObject<UBodySetup>(this); if (GUObjectArray.IsDisregardForGC(this)) { ShapeBodySetup->AddToRoot(); } ShapeBodySetup->CollisionTraceFlag = CTF_UseSimpleAsComplex; AddShapeToGeomArray<ShapeElemType>(); ShapeBodySetup->bNeverNeedsCookedCollisionData = true; bUseArchetypeBodySetup = false; //We're making our own body setup, so don't use the archetype's. //Update bodyinstance and shapes BodyInstance.BodySetup = ShapeBodySetup; { if(BodyInstance.IsValidBodyInstance()) { #if WITH_PHYSX SCOPED_SCENE_READ_LOCK(GetPhysXSceneFromIndex(BodyInstance.GetSceneIndex())); TArray<PxShape *> PShapes; BodyInstance.GetAllShapes_AssumesLocked(PShapes); check(PShapes.Num() == 1); //Shape component should only have 1 shape SetShapeToNewGeom<ShapeElemType>(PShapes[0]); #endif } } } }
bool FPhysScene::GetKinematicTarget(const FBodyInstance* BodyInstance, FTransform& OutTM) const { #if WITH_PHYSX if (PxRigidDynamic * PRigidDynamic = BodyInstance->GetPxRigidDynamic()) { #if WITH_SUBSTEPPING uint32 BodySceneType = SceneType(BodyInstance); if (IsSubstepping(BodySceneType)) { FPhysSubstepTask * PhysSubStepper = PhysSubSteppers[BodySceneType]; return PhysSubStepper->GetKinematicTarget(BodyInstance, OutTM); } else #endif { SCOPED_SCENE_READ_LOCK(PRigidDynamic->getScene()); PxTransform POutTM; bool validTM = PRigidDynamic->getKinematicTarget(POutTM); if (validTM) { OutTM = P2UTransform(POutTM); return true; } } } #endif return false; }
void GatherPhysXStats(PxScene* PScene, uint32 SceneType) { /** Gather PhysX stats */ if (SceneType == 0) { if (PScene) { SCOPED_SCENE_READ_LOCK(PScene); PxSimulationStatistics SimStats; PScene->getSimulationStatistics(SimStats); SET_DWORD_STAT(STAT_NumActiveConstraints, SimStats.nbActiveConstraints); SET_DWORD_STAT(STAT_NumActiveSimulatedBodies, SimStats.nbActiveDynamicBodies); SET_DWORD_STAT(STAT_NumActiveKinematicBodies, SimStats.nbActiveKinematicBodies); SET_DWORD_STAT(STAT_NumStaticBodies, SimStats.nbStaticBodies); SET_DWORD_STAT(STAT_NumMobileBodies, SimStats.nbDynamicBodies); SET_DWORD_STAT(STAT_NumBroadphaseAdds, SimStats.getNbBroadPhaseAdds(PxSimulationStatistics::VolumeType::eRIGID_BODY)); SET_DWORD_STAT(STAT_NumBroadphaseRemoves, SimStats.getNbBroadPhaseRemoves(PxSimulationStatistics::VolumeType::eRIGID_BODY)); uint32 NumShapes = 0; for (int32 GeomType = 0; GeomType < PxGeometryType::eGEOMETRY_COUNT; ++GeomType) { NumShapes += SimStats.nbShapes[GeomType]; } SET_DWORD_STAT(STAT_NumShapes, NumShapes); } } #if 0 //this is not reliable right now else if (SceneType == 1 & UPhysicsSettings::Get()->bEnableAsyncScene) { //Having to duplicate because of macros. In theory we can fix this but need to get this quickly PxSimulationStatistics SimStats; PScene->getSimulationStatistics(SimStats); SET_DWORD_STAT(STAT_NumActiveConstraintsAsync, SimStats.nbActiveConstraints); SET_DWORD_STAT(STAT_NumActiveSimulatedBodiesAsync, SimStats.nbActiveDynamicBodies); SET_DWORD_STAT(STAT_NumActiveKinematicBodiesAsync, SimStats.nbActiveKinematicBodies); SET_DWORD_STAT(STAT_NumStaticBodiesAsync, SimStats.nbStaticBodies); SET_DWORD_STAT(STAT_NumMobileBodiesAsync, SimStats.nbDynamicBodies); SET_DWORD_STAT(STAT_NumBroadphaseAddsAsync, SimStats.getNbBroadPhaseAdds(PxSimulationStatistics::VolumeType::eRIGID_BODY)); SET_DWORD_STAT(STAT_NumBroadphaseRemovesAsync, SimStats.getNbBroadPhaseRemoves(PxSimulationStatistics::VolumeType::eRIGID_BODY)); uint32 NumShapes = 0; for (int32 GeomType = 0; GeomType < PxGeometryType::eGEOMETRY_COUNT; ++GeomType) { NumShapes += SimStats.nbShapes[GeomType]; } SET_DWORD_STAT(STAT_NumShapesAsync, NumShapes); } #endif }
void UDestructibleComponent::RefreshBoneTransforms() { #if WITH_APEX if(ApexDestructibleActor != NULL && SkeletalMesh) { UDestructibleMesh* TheDestructibleMesh = GetDestructibleMesh(); // Save a pointer to the APEX NxDestructibleAsset physx::NxDestructibleAsset* ApexDestructibleAsset = TheDestructibleMesh->ApexDestructibleAsset; check(ApexDestructibleAsset); { // Lock here so we don't encounter race conditions with the destruction processing FPhysScene* PhysScene = World->GetPhysicsScene(); check(PhysScene); const uint32 SceneType = (BodyInstance.bUseAsyncScene && PhysScene->HasAsyncScene()) ? PST_Async : PST_Sync; PxScene* PScene = PhysScene->GetPhysXScene(SceneType); check(PScene); SCOPED_SCENE_WRITE_LOCK(PScene); SCOPED_SCENE_READ_LOCK(PScene); // Try to acquire event buffer const physx::NxDestructibleChunkEvent* EventBuffer; physx::PxU32 EventBufferSize; if (ApexDestructibleActor->acquireChunkEventBuffer(EventBuffer, EventBufferSize)) { // Buffer acquired while (EventBufferSize--) { const physx::NxDestructibleChunkEvent& Event = *EventBuffer++; // Right now the only events are visibility changes. So as an optimization we won't check for the event type. // if (Event.event & physx::NxDestructibleChunkEvent::VisibilityChanged) const bool bVisible = (Event.event & physx::NxDestructibleChunkEvent::ChunkVisible) != 0; SetChunkVisible(Event.chunkIndex, bVisible); } // Release buffer (will be cleared) ApexDestructibleActor->releaseChunkEventBuffer(); } } // Update poses for visible chunks const physx::PxU16* VisibleChunks = ApexDestructibleActor->getVisibleChunks(); physx::PxU16 VisibleChunkCount = ApexDestructibleActor->getNumVisibleChunks(); while (VisibleChunkCount--) { const physx::PxU16 ChunkIndex = *VisibleChunks++; // BRGTODO : Make a direct method to access the Px objects' quats const physx::PxMat44 ChunkPoseRT = ApexDestructibleActor->getChunkPose(ChunkIndex); // Unscaled const physx::PxTransform Transform(ChunkPoseRT); SetChunkWorldRT(ChunkIndex, P2UQuat(Transform.q), P2UVector(Transform.p)); } // Send bones to render thread at end of frame MarkRenderDynamicDataDirty(); } #endif // #if WITH_APEX }
bool FConstraintInstance::ExecuteOnUnbrokenJointReadOnly(TFunctionRef<void(const physx::PxD6Joint*)> Func) const { if(ConstraintData) { SCOPED_SCENE_READ_LOCK(ConstraintData->getScene()); if(!(ConstraintData->getConstraintFlags()&PxConstraintFlag::eBROKEN)) { Func(ConstraintData); return true; } } return false; }
void FPhysSubstepTask::AddTorque(FBodyInstance * Body, const FVector & Torque) { check(Body); PxRigidDynamic * PRigidDynamic = Body->GetPxRigidDynamic(); SCOPED_SCENE_READ_LOCK(PRigidDynamic->getScene()); //We should only apply torque on non kinematic actors if (IsRigidDynamicNonKinematic(PRigidDynamic)) { FTorqueTarget TorqueTarget; TorqueTarget.Torque = Torque; FPhysTarget & TargetState = PhysTargetBuffers[External].FindOrAdd(Body); TargetState.Torques.Add(TorqueTarget); } }
void FPhysSubstepTask::AddForce(FBodyInstance * Body, const FVector & Force) { check(Body); PxRigidDynamic * PRigidDynamic = Body->GetPxRigidDynamic(); SCOPED_SCENE_READ_LOCK(PRigidDynamic->getScene()); //We should only apply forces on non kinematic actors if (IsRigidDynamicNonKinematic(PRigidDynamic)) { FForceTarget ForceTarget; ForceTarget.bPosition = false; ForceTarget.Force = Force; FPhysTarget & TargetState = PhysTargetBuffers[External].FindOrAdd(Body); TargetState.Forces.Add(ForceTarget); } }
void FPhysSubstepTask::SetKinematicTarget(FBodyInstance * Body, const FTransform & TM) { check(Body); TM.DiagnosticCheckNaN_All(); PxRigidDynamic * PRigidDynamic = Body->GetPxRigidDynamic(); SCOPED_SCENE_READ_LOCK(PRigidDynamic->getScene()); //We only interpolate kinematic actors if (!IsRigidDynamicNonKinematic(PRigidDynamic)) { FKinematicTarget KinmaticTarget(Body, TM); FPhysTarget & TargetState = PhysTargetBuffers[External].FindOrAdd(Body); TargetState.bKinematicTarget = true; TargetState.KinematicTarget = KinmaticTarget; } }
bool FPhysSubstepTask::GetKinematicTarget(const FBodyInstance* Body, FTransform& OutTM) const { #if WITH_PHYSX const PxRigidDynamic * PRigidDynamic = Body->GetPxRigidDynamic(); SCOPED_SCENE_READ_LOCK(PRigidDynamic->getScene()); if (const FPhysTarget* TargetState = PhysTargetBuffers[External].Find(Body)) { if (TargetState->bKinematicTarget) { OutTM = TargetState->KinematicTarget.TargetTM; return true; } } #endif return false; }
bool UDestructibleComponent::ExecuteOnPhysicsReadOnly(TFunctionRef<void()> Func) const { #if WITH_APEX if (ApexDestructibleActor) { FPhysScene* PhysScene = GetWorld()->GetPhysicsScene(); // Destructibles are always dynamic or kinematic, and therefore only go into one of the scenes const uint32 SceneType = BodyInstance.UseAsyncScene(PhysScene) ? PST_Async : PST_Sync; PxScene* PScene = PhysScene->GetPhysXScene(SceneType); SCOPED_SCENE_READ_LOCK(PScene); Func(); return true; } #endif return false; }
void FPhysScene::SyncComponentsToBodies(uint32 SceneType) { SCOPE_CYCLE_COUNTER(STAT_TotalPhysicsTime); SCOPE_CYCLE_COUNTER(STAT_SyncComponentsToBodies); for (FBodyInstance* BodyInstance : ActiveBodyInstances[SceneType]) { if (BodyInstance == nullptr) { continue; } check(BodyInstance->OwnerComponent->IsRegistered()); // shouldn't have a physics body for a non-registered component! AActor* Owner = BodyInstance->OwnerComponent->GetOwner(); // See if the transform is actually different, and if so, move the component to match physics const FTransform NewTransform = BodyInstance->GetUnrealWorldTransform(); if (!NewTransform.EqualsNoScale(BodyInstance->OwnerComponent->ComponentToWorld)) { const FVector MoveBy = NewTransform.GetLocation() - BodyInstance->OwnerComponent->ComponentToWorld.GetLocation(); const FRotator NewRotation = NewTransform.Rotator(); //@warning: do not reference BodyInstance again after calling MoveComponent() - events from the move could have made it unusable (destroying the actor, SetPhysics(), etc) BodyInstance->OwnerComponent->MoveComponent(MoveBy, NewRotation, false, NULL, MOVECOMP_SkipPhysicsMove); } // Check if we didn't fall out of the world if (Owner != NULL && !Owner->IsPendingKill()) { Owner->CheckStillInWorld(); } } #if WITH_APEX if (ActiveDestructibleActors[SceneType].Num()) { SCOPED_SCENE_READ_LOCK(GetPhysXScene(SceneType)); UDestructibleComponent::UpdateDestructibleChunkTM(ActiveDestructibleActors[SceneType]); } #endif }
bool UWorld::ComponentSweepMulti(TArray<struct FHitResult>& OutHits, class UPrimitiveComponent* PrimComp, const FVector& Start, const FVector& End, const FRotator& Rot, const struct FComponentQueryParams& Params) const { if(GetPhysicsScene() == NULL) { return false; } if(PrimComp == NULL) { UE_LOG(LogCollision, Log, TEXT("ComponentSweepMulti : No PrimComp")); return false; } // if target is skeletalmeshcomponent and do not support singlebody physics if ( !PrimComp->ShouldTrackOverlaps() ) { UE_LOG(LogCollision, Log, TEXT("ComponentSweepMulti : (%s) Does not support skeletalmesh with Physics Asset and destructibles."), *PrimComp->GetPathName()); return false; } ECollisionChannel TraceChannel = PrimComp->GetCollisionObjectType(); #if WITH_PHYSX // if extent is 0, do line trace if (PrimComp->IsZeroExtent()) { return RaycastMulti(this, OutHits, Start, End, TraceChannel, Params, FCollisionResponseParams(PrimComp->GetCollisionResponseToChannels())); } PxRigidActor* PRigidActor = PrimComp->BodyInstance.GetPxRigidActor(); if(PRigidActor == NULL) { UE_LOG(LogCollision, Log, TEXT("ComponentSweepMulti : (%s) No physics data"), *PrimComp->GetPathName()); return false; } PxScene * const PScene = PRigidActor->getScene(); OutHits.Empty(); // Get all the shapes from the actor TArray<PxShape*, TInlineAllocator<8>> PShapes; { SCOPED_SCENE_READ_LOCK(PScene); PShapes.AddZeroed(PRigidActor->getNbShapes()); PRigidActor->getShapes(PShapes.GetData(), PShapes.Num()); } // calculate the test global pose of the actor PxTransform PGlobalStartPose = U2PTransform(FTransform(Start)); PxTransform PGlobalEndPose = U2PTransform(FTransform(End)); bool bHaveBlockingHit = false; PxQuat PGeomRot = U2PQuat(Rot.Quaternion()); // Iterate over each shape SCENE_LOCK_READ(PScene); for(int32 ShapeIdx=0; ShapeIdx<PShapes.Num(); ShapeIdx++) { PxShape* PShape = PShapes[ShapeIdx]; check(PShape); TArray<struct FHitResult> Hits; // Calc shape global pose PxTransform PLocalShape = PShape->getLocalPose(); PxTransform PShapeGlobalStartPose = PGlobalStartPose.transform(PLocalShape); PxTransform PShapeGlobalEndPose = PGlobalEndPose.transform(PLocalShape); // consider localshape rotation for shape rotation PxQuat PShapeRot = PGeomRot * PLocalShape.q; GET_GEOMETRY_FROM_SHAPE(PGeom, PShape); if(PGeom != NULL) { SCENE_UNLOCK_READ(PScene); if (GeomSweepMulti(this, *PGeom, PShapeRot, Hits, P2UVector(PShapeGlobalStartPose.p), P2UVector(PShapeGlobalEndPose.p), TraceChannel, Params, FCollisionResponseParams(PrimComp->GetCollisionResponseToChannels()))) { bHaveBlockingHit = true; } OutHits.Append(Hits); SCENE_LOCK_READ(PScene); } } SCENE_UNLOCK_READ(PScene); return bHaveBlockingHit; #endif //WITH_PHYSX return false; }