PxTransform UMatrix2PTransform(const FMatrix& UTM) { PxQuat PQuat = U2PQuat(UTM.ToQuat()); PxVec3 PPos = U2PVector(UTM.GetOrigin()); PxTransform Result(PPos, PQuat); return Result; }
PxTransform U2PTransform(const FTransform& UTransform) { PxQuat PQuat = U2PQuat(UTransform.GetRotation()); PxVec3 PPos = U2PVector(UTransform.GetLocation()); PxTransform Result(PPos, PQuat); return Result; }
void FConstraintInstance::UpdateDriveTarget() { #if WITH_PHYSX ExecuteOnUnbrokenJointReadWrite([&] (PxD6Joint* Joint) { FQuat OrientationTargetQuat(AngularOrientationTarget); Joint->setDrivePosition(PxTransform(U2PVector(LinearPositionTarget), U2PQuat(OrientationTargetQuat))); Joint->setDriveVelocity(U2PVector(LinearVelocityTarget), U2PVector(RevolutionsToRads(AngularVelocityTarget))); }); #endif }
void FConstraintInstance::UpdateDriveTarget() { #if WITH_PHYSX if (PxD6Joint* PJoint = GetUnbrokenJoint()) { FQuat OrientationTargetQuat(AngularOrientationTarget); PJoint->setDrivePosition(PxTransform(U2PVector(LinearPositionTarget), U2PQuat(OrientationTargetQuat))); PJoint->setDriveVelocity(U2PVector(LinearVelocityTarget), U2PVector(RevolutionsToRads(AngularVelocityTarget))); } #endif }
void UBodySetup::AddSphylsToRigidActor(PxRigidActor* PDestActor, const FTransform& RelativeTM, const FVector& Scale3D, const FVector& Scale3DAbs, TArray<PxShape*>* NewShapes) const { float ContactOffsetFactor, MaxContactOffset; GetContactOffsetParams(ContactOffsetFactor, MaxContactOffset); PxMaterial* PDefaultMat = GetDefaultPhysMaterial(); float ScaleRadius = FMath::Max(Scale3DAbs.X, Scale3DAbs.Y); float ScaleLength = Scale3DAbs.Z; for (int32 i = 0; i < AggGeom.SphylElems.Num(); i++) { const FKSphylElem& SphylElem = AggGeom.SphylElems[i]; // this is a bit confusing since radius and height is scaled // first apply the scale first float Radius = FMath::Max(SphylElem.Radius * ScaleRadius, 0.1f); float Length = SphylElem.Length + SphylElem.Radius * 2.f; float HalfLength = Length * ScaleLength * 0.5f; Radius = FMath::Clamp(Radius, 0.1f, HalfLength); //radius is capped by half length float HalfHeight = HalfLength - Radius; HalfHeight = FMath::Max(0.1f, HalfHeight); PxCapsuleGeometry PCapsuleGeom; PCapsuleGeom.halfHeight = HalfHeight; PCapsuleGeom.radius = Radius; if (PCapsuleGeom.isValid()) { // The stored sphyl transform assumes the sphyl axis is down Z. In PhysX, it points down X, so we twiddle the matrix a bit here (swap X and Z and negate Y). PxTransform PLocalPose(U2PVector(RelativeTM.TransformPosition(SphylElem.Center)), U2PQuat(SphylElem.Orientation) * U2PSphylBasis); PLocalPose.p.x *= Scale3D.X; PLocalPose.p.y *= Scale3D.Y; PLocalPose.p.z *= Scale3D.Z; ensure(PLocalPose.isValid()); PxShape* NewShape = PDestActor->createShape(PCapsuleGeom, *PDefaultMat, PLocalPose); if (NewShapes) { NewShapes->Add(NewShape); } const float ContactOffset = FMath::Min(MaxContactOffset, ContactOffsetFactor * PCapsuleGeom.radius); NewShape->setContactOffset(ContactOffset); } else { UE_LOG(LogPhysics, Warning, TEXT("AddSphylsToRigidActor: [%s] SphylElems[%d] invalid"), *GetPathNameSafe(GetOuter()), i); } } }
void UPhysicsHandleComponent::UpdateHandleTransform(const FTransform& NewTransform) { if(!KinActorData) { return; } #if WITH_PHYSX bool bChangedPosition = true; bool bChangedRotation = true; PxRigidDynamic* KinActor = KinActorData; // Check if the new location is worthy of change PxVec3 PNewLocation = U2PVector(NewTransform.GetTranslation()); PxVec3 PCurrentLocation = KinActor->getGlobalPose().p; if((PNewLocation - PCurrentLocation).magnitudeSquared() <= 0.01f*0.01f) { PNewLocation = PCurrentLocation; bChangedPosition = false; } // Check if the new rotation is worthy of change PxQuat PNewOrientation = U2PQuat(NewTransform.GetRotation()); PxQuat PCurrentOrientation = KinActor->getGlobalPose().q; if(!(FMath::Abs(PNewOrientation.dot(PCurrentOrientation)) < (1.f - KINDA_SMALL_NUMBER))) { PNewOrientation = PCurrentOrientation; bChangedRotation = false; } // Don't call moveKinematic if it hasn't changed - that will stop bodies from going to sleep. if (bChangedPosition || bChangedRotation) { KinActor->setKinematicTarget(PxTransform(PNewLocation, PNewOrientation)); //LOC_MOD //PxD6Joint* Joint = (PxD6Joint*) HandleData; //if(Joint)// && (PNewLocation - PCurrentLocation).magnitudeSquared() > 0.01f*0.01f) //{ // PxRigidActor* Actor0, *Actor1; // Joint->getActors(Actor0, Actor1); // //Joint->setDrivePosition(PxTransform(Actor0->getGlobalPose().transformInv(PNewLocation))); // Joint->setDrivePosition(PxTransform::createIdentity()); // //Joint->setDriveVelocity(PxVec3(0), PxVec3(0)); //} } #endif // WITH_PHYSX }
void UDestructibleComponent::OnUpdateTransform(bool bSkipPhysicsMove) { // We are handling the physics move below, so don't handle it at higher levels Super::OnUpdateTransform(true); if (SkeletalMesh == NULL) { return; } if (!bPhysicsStateCreated || bSkipPhysicsMove) { return; } const FTransform& CurrentLocalToWorld = ComponentToWorld; if(CurrentLocalToWorld.ContainsNaN()) { return; } // warn if it has non-uniform scale const FVector& MeshScale3D = CurrentLocalToWorld.GetScale3D(); #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) if( !MeshScale3D.IsUniform() ) { UE_LOG(LogPhysics, Log, TEXT("UDestructibleComponent::SendPhysicsTransform : Non-uniform scale factor (%s) can cause physics to mismatch for %s SkelMesh: %s"), *MeshScale3D.ToString(), *GetFullName(), SkeletalMesh ? *SkeletalMesh->GetFullName() : TEXT("NULL")); } #endif #if WITH_APEX if (ApexDestructibleActor) { PxRigidDynamic* PRootActor = ApexDestructibleActor->getChunkPhysXActor(0); PxMat44 GlobalPose(PxMat33(U2PQuat(CurrentLocalToWorld.GetRotation())), U2PVector(CurrentLocalToWorld.GetTranslation())); if(!PRootActor || PRootActor->getScene()) //either root chunk is null meaning fractured (so there's a scene), or the root has a scene { ApexDestructibleActor->setGlobalPose(GlobalPose); }else { PRootActor->setGlobalPose(PxTransform(GlobalPose)); //we're not in a scene yet, so place the root actor in this new position } } #endif // #if WITH_APEX }
void UGripMotionControllerComponent::UpdatePhysicsHandleTransform(const FBPActorGripInformation &GrippedActor, const FTransform& NewTransform) { if (!GrippedActor.Actor && !GrippedActor.Component) return; FBPActorPhysicsHandleInformation * HandleInfo = GetPhysicsGrip(GrippedActor); if (!HandleInfo || !HandleInfo->KinActorData) return; #if WITH_PHYSX bool bChangedPosition = true; bool bChangedRotation = true; PxRigidDynamic* KinActor = HandleInfo->KinActorData; PxScene* PScene = GetPhysXSceneFromIndex(HandleInfo->SceneIndex); SCOPED_SCENE_WRITE_LOCK(PScene); // Check if the new location is worthy of change PxVec3 PNewLocation = U2PVector(NewTransform.GetTranslation()); PxVec3 PCurrentLocation = KinActor->getGlobalPose().p; if ((PNewLocation - PCurrentLocation).magnitudeSquared() <= 0.01f*0.01f) { PNewLocation = PCurrentLocation; bChangedPosition = false; } // Check if the new rotation is worthy of change PxQuat PNewOrientation = U2PQuat(NewTransform.GetRotation()); PxQuat PCurrentOrientation = KinActor->getGlobalPose().q; if ((FMath::Abs(PNewOrientation.dot(PCurrentOrientation)) > (1.f - SMALL_NUMBER))) { PNewOrientation = PCurrentOrientation; bChangedRotation = false; } // Don't call moveKinematic if it hasn't changed - that will stop bodies from going to sleep. if (bChangedPosition || bChangedRotation) { KinActor->setKinematicTarget(PxTransform(PNewLocation, PNewOrientation)); } #endif // WITH_PHYSX }
bool UWorld::SweepMulti(TArray<struct FHitResult>& OutHits,const FVector& Start,const FVector& End, const FQuat& Rot, const struct FCollisionShape & CollisionShape, const struct FCollisionQueryParams& Params, const struct FCollisionObjectQueryParams& ObjectQueryParams) const { // object query returns true if any hit is found, not only blocking hit if(CollisionShape.IsNearlyZero()) { LineTraceMulti(OutHits, Start, End, Params, ObjectQueryParams); } #if WITH_PHYSX else { switch (CollisionShape.ShapeType) { case ECollisionShape::Box: { const PxBoxGeometry PBoxGeom( U2PVector(CollisionShape.GetBox()) ); const PxQuat PGeomRot = U2PQuat(Rot); GeomSweepMulti(this, PBoxGeom, PGeomRot, OutHits, Start, End, DefaultCollisionChannel, Params, FCollisionResponseParams::DefaultResponseParam, ObjectQueryParams); } break; case ECollisionShape::Sphere: { PxSphereGeometry PSphereGeom( CollisionShape.GetSphereRadius()); PxQuat PGeomRot = PxQuat::createIdentity(); GeomSweepMulti(this, PSphereGeom, PGeomRot, OutHits, Start, End, DefaultCollisionChannel, Params, FCollisionResponseParams::DefaultResponseParam, ObjectQueryParams); } break; case ECollisionShape::Capsule: { PxCapsuleGeometry PCapsuleGeom( CollisionShape.GetCapsuleRadius(), CollisionShape.GetCapsuleAxisHalfLength() ); const PxQuat PGeomRot = ConvertToPhysXCapsuleRot(Rot); GeomSweepMulti(this, PCapsuleGeom, PGeomRot, OutHits, Start, End, DefaultCollisionChannel, Params, FCollisionResponseParams::DefaultResponseParam, ObjectQueryParams); } break; default: // invalid point ensure(false); } } #endif //WITH_PHYSX return (OutHits.Num() > 0); }
/** Function for setting target angular position. */ void FConstraintInstance::SetAngularOrientationTarget(const FQuat& InPosTarget) { FRotator OrientationTargetRot(InPosTarget); // If settings are the same, don't do anything. if( AngularOrientationTarget == OrientationTargetRot ) { return; } #if WITH_PHYSX if (PxD6Joint* Joint = ConstraintData) { PxQuat Quat = U2PQuat(InPosTarget); Joint->setDrivePosition(PxTransform(Joint->getDrivePosition().p, Quat)); } #endif AngularOrientationTarget = OrientationTargetRot; }
bool UWorld::SweepSingle(struct FHitResult& OutHit,const FVector& Start,const FVector& End, const FQuat& Rot, const struct FCollisionShape & CollisionShape, const struct FCollisionQueryParams& Params, const struct FCollisionObjectQueryParams& ObjectQueryParams) const { if(CollisionShape.IsNearlyZero()) { return LineTraceSingle(OutHit, Start, End, Params, ObjectQueryParams); } #if WITH_PHYSX switch (CollisionShape.ShapeType) { case ECollisionShape::Box: { const PxBoxGeometry PBoxGeom( U2PVector(CollisionShape.GetBox()) ); const PxQuat PGeomRot = U2PQuat(Rot); return GeomSweepSingle(this, PBoxGeom, PGeomRot, OutHit, Start, End, DefaultCollisionChannel, Params, FCollisionResponseParams::DefaultResponseParam, ObjectQueryParams); } case ECollisionShape::Sphere: { PxSphereGeometry PSphereGeom( CollisionShape.GetSphereRadius()); PxQuat PGeomRot = PxQuat::createIdentity(); return GeomSweepSingle(this, PSphereGeom, PGeomRot, OutHit, Start, End, DefaultCollisionChannel, Params, FCollisionResponseParams::DefaultResponseParam, ObjectQueryParams); } case ECollisionShape::Capsule: { PxCapsuleGeometry PCapsuleGeom( CollisionShape.GetCapsuleRadius(), CollisionShape.GetCapsuleAxisHalfLength() ); const PxQuat PGeomRot = ConvertToPhysXCapsuleRot(Rot); return GeomSweepSingle(this, PCapsuleGeom, PGeomRot, OutHit, Start, End, DefaultCollisionChannel, Params, FCollisionResponseParams::DefaultResponseParam, ObjectQueryParams); } default: // invalid point ensure(false); } #endif //WITH_PHYSX OutHit.TraceStart = Start; OutHit.TraceEnd = End; return false; }
bool UWorld::SweepTest(const FVector& Start, const FVector& End, const FQuat& Rot, ECollisionChannel TraceChannel, const struct FCollisionShape & CollisionShape, const struct FCollisionQueryParams& Params, const struct FCollisionResponseParams& ResponseParam) const { if(CollisionShape.IsNearlyZero()) { // if extent is 0, we'll just do linetrace instead return LineTraceTest(Start, End, TraceChannel, Params); } #if WITH_PHYSX switch (CollisionShape.ShapeType) { case ECollisionShape::Box: { const PxBoxGeometry PBoxGeom( U2PVector(CollisionShape.GetBox()) ); const PxQuat PGeomRot = U2PQuat(Rot); return GeomSweepTest(this, PBoxGeom, PGeomRot, Start, End, TraceChannel, Params, ResponseParam, FCollisionObjectQueryParams::DefaultObjectQueryParam); } case ECollisionShape::Sphere: { PxSphereGeometry PSphereGeom( CollisionShape.GetSphereRadius()); PxQuat PGeomRot = PxQuat::createIdentity(); return GeomSweepTest(this, PSphereGeom, PGeomRot, Start, End, TraceChannel, Params, ResponseParam, FCollisionObjectQueryParams::DefaultObjectQueryParam); } case ECollisionShape::Capsule: { PxCapsuleGeometry PCapsuleGeom( CollisionShape.GetCapsuleRadius(), CollisionShape.GetCapsuleAxisHalfLength() ); const PxQuat PGeomRot = ConvertToPhysXCapsuleRot(Rot); return GeomSweepTest(this, PCapsuleGeom, PGeomRot, Start, End, TraceChannel, Params, ResponseParam, FCollisionObjectQueryParams::DefaultObjectQueryParam); } default: // invalid point ensure(false); } #endif //WITH_PHYSX return false; }
void UDestructibleComponent::OnUpdateTransform(bool bSkipPhysicsMove) { // We are handling the physics move below, so don't handle it at higher levels Super::OnUpdateTransform(true); if (SkeletalMesh == NULL) { return; } if (!bPhysicsStateCreated || bSkipPhysicsMove) { return; } const FTransform& CurrentLocalToWorld = ComponentToWorld; if(CurrentLocalToWorld.ContainsNaN()) { return; } // warn if it has non-uniform scale const FVector & MeshScale3D = CurrentLocalToWorld.GetScale3D(); #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) if( !MeshScale3D.IsUniform() ) { UE_LOG(LogPhysics, Log, TEXT("UDestructibleComponent::SendPhysicsTransform : Non-uniform scale factor (%s) can cause physics to mismatch for %s SkelMesh: %s"), *MeshScale3D.ToString(), *GetFullName(), SkeletalMesh ? *SkeletalMesh->GetFullName() : TEXT("NULL")); } #endif #if WITH_APEX if (ApexDestructibleActor != NULL && !BodyInstance.bSimulatePhysics) { PxMat44 GlobalPose(PxMat33(U2PQuat(CurrentLocalToWorld.GetRotation())), U2PVector(CurrentLocalToWorld.GetTranslation())); ApexDestructibleActor->setGlobalPose(GlobalPose); } #endif // #if WITH_APEX }
bool UWorld::ComponentSweepSingle(struct FHitResult& OutHit,class UPrimitiveComponent* PrimComp, const FVector& Start, const FVector& End, const FRotator& Rot, const struct FComponentQueryParams& Params) const { OutHit.TraceStart = Start; OutHit.TraceEnd = End; if(GetPhysicsScene() == NULL) { return false; } if(PrimComp == NULL) { UE_LOG(LogCollision, Log, TEXT("ComponentSweepSingle : No PrimComp")); return false; } // if target is skeletalmeshcomponent and do not support singlebody physics if ( !PrimComp->ShouldTrackOverlaps() ) { UE_LOG(LogCollision, Log, TEXT("ComponentSweepSingle : (%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 RaycastSingle(this, OutHit, 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; } // Get all the shapes from the actor TArray<PxShape*, TInlineAllocator<8>> PShapes; PShapes.AddZeroed(PRigidActor->getNbShapes()); int32 NumShapes = 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 for(int32 ShapeIdx=0; ShapeIdx<PShapes.Num(); ShapeIdx++) { PxShape* PShape = PShapes[ShapeIdx]; check(PShape); // 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) { // @todo UE4, this might not be the best behavior. If we're looking for the most closest, this have to change to save the result, and find the closest one or // any other options, right now if anything hits first, it will return if (GeomSweepSingle(this, *PGeom, PShapeRot, OutHit, P2UVector(PShapeGlobalStartPose.p), P2UVector(PShapeGlobalEndPose.p), TraceChannel, Params, FCollisionResponseParams(PrimComp->GetCollisionResponseToChannels()))) { bHaveBlockingHit = true; break; } } } return bHaveBlockingHit; #endif //WITH_PHYSX return false; }
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; }
bool UWorld::ComponentSweepMulti(TArray<struct FHitResult>& OutHits, class UPrimitiveComponent* PrimComp, const FVector& Start, const FVector& End, const FQuat& Quat, const struct FComponentQueryParams& Params) const { if (GetPhysicsScene() == NULL) { return false; } if (PrimComp == NULL) { UE_LOG(LogCollision, Log, TEXT("ComponentSweepMulti : No PrimComp")); return false; } ECollisionChannel TraceChannel = PrimComp->GetCollisionObjectType(); // if extent is 0, do line trace if (PrimComp->IsZeroExtent()) { return RaycastMulti(this, OutHits, Start, End, TraceChannel, Params, FCollisionResponseParams(PrimComp->GetCollisionResponseToChannels())); } OutHits.Reset(); #if UE_WITH_PHYSICS const FBodyInstance* BodyInstance = PrimComp->GetBodyInstance(); if (!BodyInstance || !BodyInstance->IsValidBodyInstance()) { UE_LOG(LogCollision, Log, TEXT("ComponentSweepMulti : (%s) No physics data"), *PrimComp->GetReadableName()); return false; } #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) if(PrimComp->IsA(USkeletalMeshComponent::StaticClass())) { UE_LOG(LogCollision, Warning, TEXT("ComponentSweepMulti : SkeletalMeshComponent support only root body (%s) "), *PrimComp->GetReadableName()); } #endif #endif SCOPE_CYCLE_COUNTER(STAT_Collision_GeomSweepMultiple); bool bHaveBlockingHit = false; #if WITH_PHYSX ExecuteOnPxRigidActorReadOnly(BodyInstance, [&] (const PxRigidActor* PRigidActor) { // Get all the shapes from the actor FInlinePxShapeArray PShapes; const int32 NumShapes = FillInlinePxShapeArray(PShapes, *PRigidActor); // calculate the test global pose of the actor const PxQuat PGeomRot = U2PQuat(Quat); const PxTransform PGlobalStartPose = PxTransform(U2PVector(Start), PGeomRot); const PxTransform PGlobalEndPose = PxTransform(U2PVector(End), PGeomRot); // Iterate over each shape for(int32 ShapeIdx=0; ShapeIdx<NumShapes; ShapeIdx++) { PxShape* PShape = PShapes[ShapeIdx]; check(PShape); GET_GEOMETRY_FROM_SHAPE(PGeom, PShape); if (PGeom != NULL) { // Calc shape global pose const PxTransform PLocalShape = PShape->getLocalPose(); const PxTransform PShapeGlobalStartPose = PGlobalStartPose.transform(PLocalShape); const PxTransform PShapeGlobalEndPose = PGlobalEndPose.transform(PLocalShape); // consider localshape rotation for shape rotation const PxQuat PShapeRot = PGeomRot * PLocalShape.q; if (GeomSweepMulti_PhysX(this, *PGeom, PShapeRot, OutHits, P2UVector(PShapeGlobalStartPose.p), P2UVector(PShapeGlobalEndPose.p), TraceChannel, Params, FCollisionResponseParams(PrimComp->GetCollisionResponseToChannels()))) { bHaveBlockingHit = true; } } } }); #endif //WITH_PHYSX //@TODO: BOX2D: Implement UWorld::ComponentSweepMulti #if WITH_BOX2D // if (b2Body* BodyInstance = PrimComp->BodyInstance.BodyInstancePtr) // { // // } #endif return bHaveBlockingHit; }
void UDestructibleComponent::CreatePhysicsState() { // to avoid calling PrimitiveComponent, I'm just calling ActorComponent::CreatePhysicsState // @todo lh - fix me based on the discussion with Bryan G UActorComponent::CreatePhysicsState(); bPhysicsStateCreated = true; // What we want to do with BodySetup is simply use it to store a PhysicalMaterial, and possibly some other relevant fields. Set up pointers from the BodyInstance to the BodySetup and this component UBodySetup* BodySetup = GetBodySetup(); BodyInstance.OwnerComponent = this; BodyInstance.BodySetup = BodySetup; BodyInstance.InstanceBodyIndex = 0; #if WITH_APEX if( SkeletalMesh == NULL ) { return; } FPhysScene* PhysScene = World->GetPhysicsScene(); check(PhysScene); if( GApexModuleDestructible == NULL ) { UE_LOG(LogPhysics, Log, TEXT("UDestructibleComponent::CreatePhysicsState(): APEX must be enabled to init UDestructibleComponent physics.") ); return; } if( ApexDestructibleActor != NULL ) { UE_LOG(LogPhysics, Log, TEXT("UDestructibleComponent::CreatePhysicsState(): NxDestructibleActor already created.") ); return; } UDestructibleMesh* TheDestructibleMesh = GetDestructibleMesh(); if( TheDestructibleMesh == NULL || TheDestructibleMesh->ApexDestructibleAsset == NULL) { UE_LOG(LogPhysics, Log, TEXT("UDestructibleComponent::CreatePhysicsState(): No DestructibleMesh or missing ApexDestructibleAsset.") ); return; } int32 ChunkCount = TheDestructibleMesh->ApexDestructibleAsset->getChunkCount(); // Ensure the chunks start off invisible. RefreshBoneTransforms should make them visible. for (int32 ChunkIndex = 0; ChunkIndex < ChunkCount; ++ChunkIndex) { SetChunkVisible(ChunkIndex, false); } #if WITH_EDITOR if (GIsEditor && !World->IsGameWorld()) { // In the editor, only set the 0 chunk to be visible. if (TheDestructibleMesh->ApexDestructibleAsset->getChunkCount() > 0) { SetChunkVisible(0, true); } return; } #endif // WITH_EDITOR // Only create physics in the game if( !World->IsGameWorld() ) { return; } // Set template actor/body/shape properties // Find the PhysicalMaterial we need to apply to the physics bodies. UPhysicalMaterial* PhysMat = BodyInstance.GetSimplePhysicalMaterial(); // Get the default actor descriptor NxParameterized data from the asset NxParameterized::Interface* ActorParams = TheDestructibleMesh->GetDestructibleActorDesc(PhysMat); // Create PhysX transforms from ComponentToWorld const PxMat44 GlobalPose(PxMat33(U2PQuat(ComponentToWorld.GetRotation())), U2PVector(ComponentToWorld.GetTranslation())); const PxVec3 Scale = U2PVector(ComponentToWorld.GetScale3D()); // Set the transform in the actor descriptor verify( NxParameterized::setParamMat44(*ActorParams,"globalPose",GlobalPose) ); verify( NxParameterized::setParamVec3(*ActorParams,"scale",Scale) ); // Set the (initially) dynamic flag in the actor descriptor // See if we are 'static' verify( NxParameterized::setParamBool(*ActorParams,"dynamic", BodyInstance.bSimulatePhysics != false) ); // Set the sleep velocity frame decay constant (was sleepVelocitySmoothingFactor) - a new feature that should help sleeping in large piles verify( NxParameterized::setParamF32(*ActorParams,"sleepVelocityFrameDecayConstant", 20.0f) ); // Set up the shape desc template // Get collision channel and response PxFilterData PQueryFilterData, PSimFilterData; uint8 MoveChannel = GetCollisionObjectType(); FCollisionResponseContainer CollResponse; if(IsCollisionEnabled()) { // Only enable a collision response if collision is enabled CollResponse = GetCollisionResponseToChannels(); LargeChunkCollisionResponse.SetCollisionResponseContainer(CollResponse); SmallChunkCollisionResponse.SetCollisionResponseContainer(CollResponse); SmallChunkCollisionResponse.SetResponse(ECC_Pawn, ECR_Overlap); } else { // now since by default it will all block, if collision is disabled, we need to set to ignore MoveChannel = ECC_WorldStatic; CollResponse.SetAllChannels(ECR_Ignore); LargeChunkCollisionResponse.SetAllChannels(ECR_Ignore); SmallChunkCollisionResponse.SetAllChannels(ECR_Ignore); } const bool bEnableImpactDamage = IsImpactDamageEnabled(TheDestructibleMesh, 0); const bool bEnableContactModification = TheDestructibleMesh->DefaultDestructibleParameters.DamageParameters.bCustomImpactResistance && TheDestructibleMesh->DefaultDestructibleParameters.DamageParameters.ImpactResistance > 0.f; // Passing AssetInstanceID = 0 so we'll have self-collision AActor* Owner = GetOwner(); CreateShapeFilterData(MoveChannel, GetUniqueID(), CollResponse, 0, 0, PQueryFilterData, PSimFilterData, BodyInstance.bUseCCD, bEnableImpactDamage, false, bEnableContactModification); // Build filterData variations for complex and simple PSimFilterData.word3 |= EPDF_SimpleCollision | EPDF_ComplexCollision; PQueryFilterData.word3 |= EPDF_SimpleCollision | EPDF_ComplexCollision; // Set the filterData in the shape descriptor verify( NxParameterized::setParamU32(*ActorParams,"p3ShapeDescTemplate.simulationFilterData.word0", PSimFilterData.word0 ) ); verify( NxParameterized::setParamU32(*ActorParams,"p3ShapeDescTemplate.simulationFilterData.word1", PSimFilterData.word1 ) ); verify( NxParameterized::setParamU32(*ActorParams,"p3ShapeDescTemplate.simulationFilterData.word2", PSimFilterData.word2 ) ); verify( NxParameterized::setParamU32(*ActorParams,"p3ShapeDescTemplate.simulationFilterData.word3", PSimFilterData.word3 ) ); verify( NxParameterized::setParamU32(*ActorParams,"p3ShapeDescTemplate.queryFilterData.word0", PQueryFilterData.word0 ) ); verify( NxParameterized::setParamU32(*ActorParams,"p3ShapeDescTemplate.queryFilterData.word1", PQueryFilterData.word1 ) ); verify( NxParameterized::setParamU32(*ActorParams,"p3ShapeDescTemplate.queryFilterData.word2", PQueryFilterData.word2 ) ); verify( NxParameterized::setParamU32(*ActorParams,"p3ShapeDescTemplate.queryFilterData.word3", PQueryFilterData.word3 ) ); // Set the PhysX material in the shape descriptor PxMaterial* PMaterial = PhysMat->GetPhysXMaterial(); verify( NxParameterized::setParamU64(*ActorParams,"p3ShapeDescTemplate.material", (physx::PxU64)PMaterial) ); // Set the rest depth to match the skin width in the shape descriptor const physx::PxCookingParams& CookingParams = GApexSDK->getCookingInterface()->getParams(); verify( NxParameterized::setParamF32(*ActorParams,"p3ShapeDescTemplate.restOffset", -CookingParams.skinWidth) ); // Set the PhysX material in the actor descriptor verify( NxParameterized::setParamBool(*ActorParams,"p3ActorDescTemplate.flags.eDISABLE_GRAVITY",false) ); verify( NxParameterized::setParamBool(*ActorParams,"p3ActorDescTemplate.flags.eVISUALIZATION",true) ); // Set the PxActor's and PxShape's userData fields to this component's body instance verify( NxParameterized::setParamU64(*ActorParams,"p3ActorDescTemplate.userData", 0 ) ); // All shapes created by this DestructibleActor will have the userdata of the owning component. // We need this, as in some cases APEX is moving shapes accross actors ( ex. FormExtended structures ) verify( NxParameterized::setParamU64(*ActorParams,"p3ShapeDescTemplate.userData", (PxU64)&PhysxUserData ) ); // Set up the body desc template in the actor descriptor verify( NxParameterized::setParamF32(*ActorParams,"p3BodyDescTemplate.angularDamping", BodyInstance.AngularDamping ) ); verify( NxParameterized::setParamF32(*ActorParams,"p3BodyDescTemplate.linearDamping", BodyInstance.LinearDamping ) ); const PxTolerancesScale& PScale = GPhysXSDK->getTolerancesScale(); PxF32 SleepEnergyThreshold = 0.00005f*PScale.speed*PScale.speed; // 1/1000 Default, since the speed scale is quite high if (BodyInstance.SleepFamily == ESleepFamily::Sensitive) { SleepEnergyThreshold /= 20.0f; } verify( NxParameterized::setParamF32(*ActorParams,"p3BodyDescTemplate.sleepThreshold", SleepEnergyThreshold) ); // NxParameterized::setParamF32(*ActorParams,"bodyDescTemplate.sleepDamping", SleepDamping ); verify( NxParameterized::setParamF32(*ActorParams,"p3BodyDescTemplate.density", 0.001f*PhysMat->Density) ); // Convert from g/cm^3 to kg/cm^3 // Enable CCD if requested verify( NxParameterized::setParamBool(*ActorParams,"p3BodyDescTemplate.flags.eENABLE_CCD", BodyInstance.bUseCCD != 0) ); // Ask the actor to create chunk events, for more efficient visibility updates verify( NxParameterized::setParamBool(*ActorParams,"createChunkEvents", true) ); // Enable hard sleeping if requested verify( NxParameterized::setParamBool(*ActorParams,"useHardSleeping", bEnableHardSleeping) ); // 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; NxApexScene* ApexScene = PhysScene->GetApexScene(SceneType); PxScene* PScene = PhysScene->GetPhysXScene(SceneType); BodyInstance.SceneIndexSync = SceneType == PST_Sync ? PhysScene->PhysXSceneIndex[PST_Sync] : 0; BodyInstance.SceneIndexAsync = SceneType == PST_Async ? PhysScene->PhysXSceneIndex[PST_Async] : 0; check(ApexScene); ChunkInfos.Reset(ChunkCount); ChunkInfos.AddZeroed(ChunkCount); PhysxChunkUserData.Reset(ChunkCount); PhysxChunkUserData.AddZeroed(ChunkCount); // Create an APEX NxDestructibleActor from the Destructible asset and actor descriptor ApexDestructibleActor = static_cast<NxDestructibleActor*>(TheDestructibleMesh->ApexDestructibleAsset->createApexActor(*ActorParams, *ApexScene)); check(ApexDestructibleActor); // Make a backpointer to this component PhysxUserData = FPhysxUserData(this); ApexDestructibleActor->userData = &PhysxUserData; // Cache cooked collision data // BRGTODO : cook in asset ApexDestructibleActor->cacheModuleData(); // BRGTODO : Per-actor LOD setting // ApexDestructibleActor->forcePhysicalLod( DestructibleActor->LOD ); // Start asleep if requested PxRigidDynamic* PRootActor = ApexDestructibleActor->getChunkPhysXActor(0); // Put to sleep or wake up only if the component is physics-simulated if (PRootActor != NULL && BodyInstance.bSimulatePhysics) { SCOPED_SCENE_WRITE_LOCK(PScene); //Question, since apex is defer adding actors do we need to lock? Locking the async scene is expensive! PRootActor->setActorFlag(PxActorFlag::eDISABLE_GRAVITY, !BodyInstance.bEnableGravity); // Sleep/wake up as appropriate if (!BodyInstance.bStartAwake) { ApexDestructibleActor->setChunkPhysXActorAwakeState(0, false); } } UpdateBounds(); #endif // #if WITH_APEX }