bool UWorld::OverlapSingle(struct FOverlapResult& OutOverlap,const FVector& Pos, const FQuat& Rot, const struct FCollisionShape & CollisionShape, const struct FCollisionQueryParams& Params, const struct FCollisionObjectQueryParams& ObjectQueryParams) const { #if WITH_PHYSX switch (CollisionShape.ShapeType) { case ECollisionShape::Box: { PxBoxGeometry PBoxGeom( U2PVector(CollisionShape.GetBox()) ); PxTransform PGeomPose = U2PTransform(FTransform(Rot, Pos)); return GeomOverlapSingle(this, PBoxGeom, PGeomPose, OutOverlap, DefaultCollisionChannel, Params, FCollisionResponseParams::DefaultResponseParam, ObjectQueryParams); } case ECollisionShape::Sphere: { PxSphereGeometry PSphereGeom( CollisionShape.GetSphereRadius() ); PxTransform PGeomPose(U2PVector(Pos), PxQuat::createIdentity()); return GeomOverlapSingle(this, PSphereGeom, PGeomPose, OutOverlap, DefaultCollisionChannel, Params, FCollisionResponseParams::DefaultResponseParam, ObjectQueryParams); } case ECollisionShape::Capsule: { PxCapsuleGeometry PCapsuleGeom( CollisionShape.GetCapsuleRadius(), CollisionShape.GetCapsuleAxisHalfLength() ); PxTransform PGeomPose = ConvertToPhysXCapsulePose( FTransform(Rot,Pos) ); return GeomOverlapSingle(this, PCapsuleGeom, PGeomPose, OutOverlap, DefaultCollisionChannel, Params, FCollisionResponseParams::DefaultResponseParam, ObjectQueryParams); } default: // invalid point ensure(false); } #endif //WITH_PHYSX return false; }
void FConstraintInstance::SetRefOrientation(EConstraintFrame::Type Frame, const FVector& PriAxis, const FVector& SecAxis) { #if WITH_PHYSX PxJointActorIndex::Enum PxFrame = U2PConstraintFrame(Frame); FVector RefPos; #endif if (Frame == EConstraintFrame::Frame1) { RefPos = Pos1; PriAxis1 = PriAxis; SecAxis1 = SecAxis; } else { RefPos = Pos2; PriAxis2 = PriAxis; SecAxis2 = SecAxis; } #if WITH_PHYSX if (PxD6Joint* Joint = GetUnbrokenJoint()) { FTransform URefTransform = FTransform(PriAxis1, SecAxis, PriAxis ^ SecAxis, RefPos); PxTransform PxRefFrame = U2PTransform(URefTransform); Joint->setLocalPose(PxFrame, PxRefFrame); } #endif }
void AddBoxesToRigidActor_AssumesLocked() const { float ContactOffsetFactor, MaxContactOffset; GetContactOffsetParams(ContactOffsetFactor, MaxContactOffset); for (int32 i = 0; i < BodySetup->AggGeom.BoxElems.Num(); i++) { const FKBoxElem& BoxElem = BodySetup->AggGeom.BoxElems[i]; PxBoxGeometry PBoxGeom; PBoxGeom.halfExtents.x = (0.5f * BoxElem.X * Scale3DAbs.X); PBoxGeom.halfExtents.y = (0.5f * BoxElem.Y * Scale3DAbs.Y); PBoxGeom.halfExtents.z = (0.5f * BoxElem.Z * Scale3DAbs.Z); FTransform BoxTransform = BoxElem.GetTransform() * RelativeTM; if (PBoxGeom.isValid() && BoxTransform.IsValid()) { PxTransform PLocalPose(U2PTransform(BoxTransform)); PLocalPose.p.x *= Scale3D.X; PLocalPose.p.y *= Scale3D.Y; PLocalPose.p.z *= Scale3D.Z; ensure(PLocalPose.isValid()); { const float ContactOffset = FMath::Min(MaxContactOffset, ContactOffsetFactor * PBoxGeom.halfExtents.minElement()); AttachShape_AssumesLocked(PBoxGeom, PLocalPose, ContactOffset); } } else { UE_LOG(LogPhysics, Warning, TEXT("AddBoxesToRigidActor: [%s] BoxElems[%d] invalid or has invalid transform"), *GetPathNameSafe(BodySetup->GetOuter()), i); } } }
/** Interpolates kinematic actor transform - Assumes caller has obtained writer lock */ void FPhysSubstepTask::InterpolateKinematicActor_AssumesLocked(const FPhysTarget& PhysTarget, FBodyInstance* BodyInstance, float InAlpha) { #if WITH_PHYSX PxRigidDynamic * PRigidDynamic = BodyInstance->GetPxRigidDynamic_AssumesLocked(); InAlpha = FMath::Clamp(InAlpha, 0.f, 1.f); /** Interpolate kinematic actors */ if (PhysTarget.bKinematicTarget) { //It's possible that the actor is no longer kinematic and is now simulating. In that case do nothing if (!BodyInstance->IsNonKinematic()) { const FKinematicTarget& KinematicTarget = PhysTarget.KinematicTarget; const FTransform& TargetTM = KinematicTarget.TargetTM; const FTransform& StartTM = KinematicTarget.OriginalTM; FTransform InterTM = FTransform::Identity; InterTM.SetLocation(FMath::Lerp(StartTM.GetLocation(), TargetTM.GetLocation(), InAlpha)); InterTM.SetRotation(FMath::Lerp(StartTM.GetRotation(), TargetTM.GetRotation(), InAlpha)); const PxTransform PNewPose = U2PTransform(InterTM); check(PNewPose.isValid()); PRigidDynamic->setKinematicTarget(PNewPose); } } #endif }
void FPhysScene::SetKinematicTarget(FBodyInstance * BodyInstance, const FTransform & TargetTransform) { TargetTransform.DiagnosticCheckNaN_All(); #if WITH_PHYSX if (PxRigidDynamic * PRigidDynamic = BodyInstance->GetPxRigidDynamic()) { #if WITH_SUBSTEPPING if (IsSubstepping()) { FPhysSubstepTask * PhysSubStepper = PhysSubSteppers[SceneType(BodyInstance)]; PhysSubStepper->SetKinematicTarget(BodyInstance, TargetTransform); } else #endif { const PxTransform PNewPose = U2PTransform(TargetTransform); check(PNewPose.isValid()); SCOPED_SCENE_WRITE_LOCK(PRigidDynamic->getScene()); PRigidDynamic->setKinematicTarget(PNewPose); } } #endif }
void AddTriMeshToRigidActor_AssumesLocked() const { float ContactOffsetFactor, MaxContactOffset; GetContactOffsetParams(ContactOffsetFactor, MaxContactOffset); for(PxTriangleMesh* TriMesh : BodySetup->TriMeshes) { PxTriangleMeshGeometry PTriMeshGeom; PTriMeshGeom.triangleMesh = TriMesh; PTriMeshGeom.scale.scale = U2PVector(Scale3D); if (BodySetup->bDoubleSidedGeometry) { PTriMeshGeom.meshFlags |= PxMeshGeometryFlag::eDOUBLE_SIDED; } if (PTriMeshGeom.isValid()) { PxTransform PElementTransform = U2PTransform(RelativeTM); // Create without 'sim shape' flag, problematic if it's kinematic, and it gets set later anyway. if (!AttachShape_AssumesLocked(PTriMeshGeom, PElementTransform, MaxContactOffset, PxShapeFlag::eSCENE_QUERY_SHAPE | PxShapeFlag::eVISUALIZATION)) { UE_LOG(LogPhysics, Log, TEXT("Can't create new mesh shape in AddShapesToRigidActor")); } } else { UE_LOG(LogPhysics, Log, TEXT("AddTriMeshToRigidActor: TriMesh invalid")); } } }
void FConstraintInstance::SetRefFrame(EConstraintFrame::Type Frame, const FTransform& RefFrame) { #if WITH_PHYSX PxJointActorIndex::Enum PxFrame = U2PConstraintFrame(Frame); #endif if(Frame == EConstraintFrame::Frame1) { Pos1 = RefFrame.GetTranslation(); PriAxis1 = RefFrame.GetUnitAxis( EAxis::X ); SecAxis1 = RefFrame.GetUnitAxis( EAxis::Y ); } else { Pos2 = RefFrame.GetTranslation(); PriAxis2 = RefFrame.GetUnitAxis( EAxis::X ); SecAxis2 = RefFrame.GetUnitAxis( EAxis::Y ); } #if WITH_PHYSX if (PxD6Joint* Joint = GetUnbrokenJoint()) { PxTransform PxRefFrame = U2PTransform(RefFrame); Joint->setLocalPose(PxFrame, PxRefFrame); } #endif }
/** Interpolates kinematic actor transform - Assumes caller has obtained writer lock */ void FPhysSubstepTask::InterpolateKinematicActor(const FPhysTarget & PhysTarget, FBodyInstance * BodyInstance, float Alpha) { #if WITH_PHYSX PxRigidDynamic * PRigidDynamic = BodyInstance->GetPxRigidDynamic(); Alpha = FMath::Clamp(Alpha, 0.f, 1.f); /** Interpolate kinematic actors */ if (PhysTarget.bKinematicTarget) { //We should only be interpolating kinematic actors check(!IsRigidDynamicNonKinematic(PRigidDynamic)); const FKinematicTarget & KinematicTarget = PhysTarget.KinematicTarget; const FTransform & TargetTM = KinematicTarget.TargetTM; const FTransform & StartTM = KinematicTarget.OriginalTM; FTransform InterTM = FTransform::Identity; InterTM.SetLocation(FMath::Lerp(StartTM.GetLocation(), TargetTM.GetLocation(), Alpha)); InterTM.SetRotation(FMath::Lerp(StartTM.GetRotation(), TargetTM.GetRotation(), Alpha)); const PxTransform PNewPose = U2PTransform(InterTM); check(PNewPose.isValid()); PRigidDynamic->setKinematicTarget(PNewPose); } #endif }
void AddConvexElemsToRigidActor_AssumesLocked() const { float ContactOffsetFactor, MaxContactOffset; GetContactOffsetParams(ContactOffsetFactor, MaxContactOffset); for (int32 i = 0; i < BodySetup->AggGeom.ConvexElems.Num(); i++) { const FKConvexElem& ConvexElem = BodySetup->AggGeom.ConvexElems[i]; if (ConvexElem.ConvexMesh) { PxTransform PLocalPose; bool bUseNegX = CalcMeshNegScaleCompensation(Scale3D, PLocalPose); PxConvexMeshGeometry PConvexGeom; PConvexGeom.convexMesh = bUseNegX ? ConvexElem.ConvexMeshNegX : ConvexElem.ConvexMesh; PConvexGeom.scale.scale = U2PVector(Scale3DAbs * ConvexElem.GetTransform().GetScale3D().GetAbs()); FTransform ConvexTransform = ConvexElem.GetTransform(); if (ConvexTransform.GetScale3D().X < 0 || ConvexTransform.GetScale3D().Y < 0 || ConvexTransform.GetScale3D().Z < 0) { UE_LOG(LogPhysics, Warning, TEXT("AddConvexElemsToRigidActor: [%s] ConvexElem[%d] has negative scale. Not currently supported"), *GetPathNameSafe(BodySetup->GetOuter()), i); } if (ConvexTransform.IsValid()) { PxTransform PElementTransform = U2PTransform(ConvexTransform * RelativeTM); PLocalPose.q *= PElementTransform.q; PLocalPose.p = PElementTransform.p; PLocalPose.p.x *= Scale3D.X; PLocalPose.p.y *= Scale3D.Y; PLocalPose.p.z *= Scale3D.Z; if (PConvexGeom.isValid()) { PxVec3 PBoundsExtents = PConvexGeom.convexMesh->getLocalBounds().getExtents(); ensure(PLocalPose.isValid()); { const float ContactOffset = FMath::Min(MaxContactOffset, ContactOffsetFactor * PBoundsExtents.minElement()); AttachShape_AssumesLocked(PConvexGeom, PLocalPose, ContactOffset); } } else { UE_LOG(LogPhysics, Warning, TEXT("AddConvexElemsToRigidActor: [%s] ConvexElem[%d] invalid"), *GetPathNameSafe(BodySetup->GetOuter()), i); } } else { UE_LOG(LogPhysics, Warning, TEXT("AddConvexElemsToRigidActor: [%s] ConvexElem[%d] has invalid transform"), *GetPathNameSafe(BodySetup->GetOuter()), i); } } else { UE_LOG(LogPhysics, Warning, TEXT("AddConvexElemsToRigidActor: ConvexElem is missing ConvexMesh (%d: %s)"), i, *BodySetup->GetPathName()); } } }
bool FConstraintInstance::CreatePxJoint(physx::PxRigidActor* PActor1, physx::PxRigidActor* PActor2, physx::PxScene* PScene, const float Scale) { ConstraintData = nullptr; FTransform Local1 = GetRefFrame(EConstraintFrame::Frame1); Local1.ScaleTranslation(FVector(Scale)); checkf(Local1.IsValid() && !Local1.ContainsNaN(), TEXT("%s"), *Local1.ToString()); FTransform Local2 = GetRefFrame(EConstraintFrame::Frame2); Local2.ScaleTranslation(FVector(Scale)); checkf(Local2.IsValid() && !Local2.ContainsNaN(), TEXT("%s"), *Local2.ToString()); SCOPED_SCENE_WRITE_LOCK(PScene); // Because PhysX keeps limits/axes locked in the first body reference frame, whereas Unreal keeps them in the second body reference frame, we have to flip the bodies here. PxD6Joint* PD6Joint = PxD6JointCreate(*GPhysXSDK, PActor2, U2PTransform(Local2), PActor1, U2PTransform(Local1)); if (PD6Joint == nullptr) { UE_LOG(LogPhysics, Log, TEXT("URB_ConstraintInstance::InitConstraint - Invalid 6DOF joint (%s)"), *JointName.ToString()); return false; } ///////// POINTERS PD6Joint->userData = &PhysxUserData; // Remember reference to scene index. FPhysScene* RBScene = FPhysxUserData::Get<FPhysScene>(PScene->userData); if (RBScene->GetPhysXScene(PST_Sync) == PScene) { SceneIndex = RBScene->PhysXSceneIndex[PST_Sync]; } else if (RBScene->GetPhysXScene(PST_Async) == PScene) { SceneIndex = RBScene->PhysXSceneIndex[PST_Async]; } else { UE_LOG(LogPhysics, Log, TEXT("URB_ConstraintInstance::InitConstraint: PxScene has inconsistent FPhysScene userData. No joint created.")); return false; } ConstraintData = PD6Joint; return true; }
void UBodySetup::AddBoxesToRigidActor(PxRigidActor* PDestActor, const FTransform& RelativeTM, const FVector& Scale3D, const FVector& Scale3DAbs, TArray<PxShape*>* NewShapes) const { float ContactOffsetFactor, MaxContactOffset; GetContactOffsetParams(ContactOffsetFactor, MaxContactOffset); PxMaterial* PDefaultMat = GetDefaultPhysMaterial(); for (int32 i = 0; i < AggGeom.BoxElems.Num(); i++) { const FKBoxElem& BoxElem = AggGeom.BoxElems[i]; PxBoxGeometry PBoxGeom; PBoxGeom.halfExtents.x = (0.5f * BoxElem.X * Scale3DAbs.X); PBoxGeom.halfExtents.y = (0.5f * BoxElem.Y * Scale3DAbs.Y); PBoxGeom.halfExtents.z = (0.5f * BoxElem.Z * Scale3DAbs.Z); FTransform BoxTransform = BoxElem.GetTransform() * RelativeTM; if (PBoxGeom.isValid() && BoxTransform.IsValid()) { PxTransform PLocalPose(U2PTransform(BoxTransform)); PLocalPose.p.x *= Scale3D.X; PLocalPose.p.y *= Scale3D.Y; PLocalPose.p.z *= Scale3D.Z; ensure(PLocalPose.isValid()); PxShape* NewShape = PDestActor->createShape(PBoxGeom, *PDefaultMat, PLocalPose); if (NewShapes) { NewShapes->Add(NewShape); } const float ContactOffset = FMath::Min(MaxContactOffset, ContactOffsetFactor * PBoxGeom.halfExtents.minElement()); NewShape->setContactOffset(ContactOffset); } else { UE_LOG(LogPhysics, Warning, TEXT("AddBoxesToRigidActor: [%s] BoxElems[%d] invalid or has invalid transform"), *GetPathNameSafe(GetOuter()), i); } } }
void FPhysScene::SetKinematicTarget_AssumesLocked(FBodyInstance* BodyInstance, const FTransform& TargetTransform, bool bAllowSubstepping) { TargetTransform.DiagnosticCheckNaN_All(); #if WITH_PHYSX if (PxRigidDynamic * PRigidDynamic = BodyInstance->GetPxRigidDynamic_AssumesLocked()) { #if WITH_SUBSTEPPING uint32 BodySceneType = SceneType_AssumesLocked(BodyInstance); if (bAllowSubstepping && IsSubstepping(BodySceneType)) { FPhysSubstepTask * PhysSubStepper = PhysSubSteppers[BodySceneType]; PhysSubStepper->SetKinematicTarget_AssumesLocked(BodyInstance, TargetTransform); } else #endif { const PxTransform PNewPose = U2PTransform(TargetTransform); check(PNewPose.isValid()); PRigidDynamic->setKinematicTarget(PNewPose); } } #endif }
bool UWorld::OverlapMulti(TArray<struct FOverlapResult>& OutOverlaps,const FVector& Pos, 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 WITH_PHYSX switch (CollisionShape.ShapeType) { case ECollisionShape::Box: { PxBoxGeometry PBoxGeom( U2PVector(CollisionShape.GetBox()) ); PxTransform PGeomPose = U2PTransform(FTransform(Rot, Pos)); GeomOverlapMulti(this, PBoxGeom, PGeomPose, OutOverlaps, DefaultCollisionChannel, Params, FCollisionResponseParams::DefaultResponseParam, ObjectQueryParams); } break; case ECollisionShape::Sphere: { PxSphereGeometry PSphereGeom( CollisionShape.GetSphereRadius() ); PxTransform PGeomPose(U2PVector(Pos), PxQuat::createIdentity()); GeomOverlapMulti(this, PSphereGeom, PGeomPose, OutOverlaps, DefaultCollisionChannel, Params, FCollisionResponseParams::DefaultResponseParam, ObjectQueryParams); } break; case ECollisionShape::Capsule: { PxCapsuleGeometry PCapsuleGeom( CollisionShape.GetCapsuleRadius(), CollisionShape.GetCapsuleAxisHalfLength() ); PxTransform PGeomPose = ConvertToPhysXCapsulePose( FTransform(Rot,Pos) ); GeomOverlapMulti(this, PCapsuleGeom, PGeomPose, OutOverlaps, DefaultCollisionChannel, Params, FCollisionResponseParams::DefaultResponseParam, ObjectQueryParams); } break; default: // invalid point ensure(false); } #endif //WITH_PHYSX return (OutOverlaps.Num() > 0); }
void UBodySetup::AddConvexElemsToRigidActor(PxRigidActor* PDestActor, const FTransform& RelativeTM, const FVector& Scale3D, const FVector& Scale3DAbs, TArray<PxShape*>* NewShapes) const { float ContactOffsetFactor, MaxContactOffset; GetContactOffsetParams(ContactOffsetFactor, MaxContactOffset); PxMaterial* PDefaultMat = GetDefaultPhysMaterial(); for (int32 i = 0; i < AggGeom.ConvexElems.Num(); i++) { const FKConvexElem& ConvexElem = AggGeom.ConvexElems[i]; if (ConvexElem.ConvexMesh) { PxTransform PLocalPose; bool bUseNegX = CalcMeshNegScaleCompensation(Scale3D, PLocalPose); PxConvexMeshGeometry PConvexGeom; PConvexGeom.convexMesh = bUseNegX ? ConvexElem.ConvexMeshNegX : ConvexElem.ConvexMesh; PConvexGeom.scale.scale = U2PVector(Scale3DAbs * ConvexElem.GetTransform().GetScale3D().GetAbs()); FTransform ConvexTransform = ConvexElem.GetTransform(); if (ConvexTransform.GetScale3D().X < 0 || ConvexTransform.GetScale3D().Y < 0 || ConvexTransform.GetScale3D().Z < 0) { UE_LOG(LogPhysics, Warning, TEXT("AddConvexElemsToRigidActor: [%s] ConvexElem[%d] has negative scale. Not currently supported"), *GetPathNameSafe(GetOuter()), i); } if (ConvexTransform.IsValid()) { PxTransform PElementTransform = U2PTransform(ConvexTransform * RelativeTM); PLocalPose.q *= PElementTransform.q; PLocalPose.p = PElementTransform.p; PLocalPose.p.x *= Scale3D.X; PLocalPose.p.y *= Scale3D.Y; PLocalPose.p.z *= Scale3D.Z; if (PConvexGeom.isValid()) { PxVec3 PBoundsExtents = PConvexGeom.convexMesh->getLocalBounds().getExtents(); ensure(PLocalPose.isValid()); PxShape* NewShape = PDestActor->createShape(PConvexGeom, *PDefaultMat, PLocalPose); if (NewShapes) { NewShapes->Add(NewShape); } const float ContactOffset = FMath::Min(MaxContactOffset, ContactOffsetFactor * PBoundsExtents.minElement()); NewShape->setContactOffset(ContactOffset); } else { UE_LOG(LogPhysics, Warning, TEXT("AddConvexElemsToRigidActor: [%s] ConvexElem[%d] invalid"), *GetPathNameSafe(GetOuter()), i); } } else { UE_LOG(LogPhysics, Warning, TEXT("AddConvexElemsToRigidActor: [%s] ConvexElem[%d] has invalid transform"), *GetPathNameSafe(GetOuter()), i); } } else { UE_LOG(LogPhysics, Warning, TEXT("AddConvexElemsToRigidActor: ConvexElem is missing ConvexMesh (%d: %s)"), i, *GetPathName()); } } }
void USkeletalMeshComponent::UpdateKinematicBonesToAnim(const TArray<FTransform>& InSpaceBases, ETeleportType Teleport, bool bNeedsSkinning) { SCOPE_CYCLE_COUNTER(STAT_UpdateRBBones); // This below code produces some interesting result here // - below codes update physics data, so if you don't update pose, the physics won't have the right result // - but if we just update physics bone without update current pose, it will have stale data // If desired, pass the animation data to the physics joints so they can be used by motors. // See if we are going to need to update kinematics const bool bUpdateKinematics = (KinematicBonesUpdateType != EKinematicBonesUpdateToPhysics::SkipAllBones); const bool bTeleport = Teleport == ETeleportType::TeleportPhysics; // If desired, update physics bodies associated with skeletal mesh component to match. if(!bUpdateKinematics && !(bTeleport && IsAnySimulatingPhysics())) { // nothing to do return; } // Get the scene, and do nothing if we can't get one. FPhysScene* PhysScene = nullptr; if (GetWorld() != nullptr) { PhysScene = GetWorld()->GetPhysicsScene(); } if(PhysScene == nullptr) { return; } const FTransform& CurrentLocalToWorld = ComponentToWorld; // Gracefully handle NaN if(CurrentLocalToWorld.ContainsNaN()) { return; } // If desired, draw the skeleton at the point where we pass it to the physics. if (bShowPrePhysBones && SkeletalMesh && InSpaceBases.Num() == SkeletalMesh->RefSkeleton.GetNum()) { for (int32 i = 1; i<InSpaceBases.Num(); i++) { FVector ThisPos = CurrentLocalToWorld.TransformPosition(InSpaceBases[i].GetLocation()); int32 ParentIndex = SkeletalMesh->RefSkeleton.GetParentIndex(i); FVector ParentPos = CurrentLocalToWorld.TransformPosition(InSpaceBases[ParentIndex].GetLocation()); GetWorld()->LineBatcher->DrawLine(ThisPos, ParentPos, AnimSkelDrawColor, SDPG_Foreground); } } // 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("USkeletalMeshComponent::UpdateKinematicBonesToAnim : Non-uniform scale factor (%s) can cause physics to mismatch for %s SkelMesh: %s"), *MeshScale3D.ToString(), *GetFullName(), SkeletalMesh ? *SkeletalMesh->GetFullName() : TEXT("NULL")); } #endif if (bEnablePerPolyCollision == false) { const UPhysicsAsset* const PhysicsAsset = GetPhysicsAsset(); if (PhysicsAsset && SkeletalMesh && Bodies.Num() > 0) { #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) if (!ensure(PhysicsAsset->BodySetup.Num() == Bodies.Num())) { // related to TTP 280315 UE_LOG(LogPhysics, Warning, TEXT("Mesh (%s) has PhysicsAsset(%s), and BodySetup(%d) and Bodies(%d) don't match"), *SkeletalMesh->GetName(), *PhysicsAsset->GetName(), PhysicsAsset->BodySetup.Num(), Bodies.Num()); return; } #endif #if WITH_PHYSX // Lock the scenes we need (flags set in InitArticulated) if(bHasBodiesInSyncScene) { SCENE_LOCK_WRITE(PhysScene->GetPhysXScene(PST_Sync)) } if (bHasBodiesInAsyncScene) { SCENE_LOCK_WRITE(PhysScene->GetPhysXScene(PST_Async)) } #endif // Iterate over each body for (int32 i = 0; i < Bodies.Num(); i++) { // If we have a physics body, and its kinematic... FBodyInstance* BodyInst = Bodies[i]; check(BodyInst); if (bTeleport || (BodyInst->IsValidBodyInstance() && !BodyInst->IsInstanceSimulatingPhysics())) { const int32 BoneIndex = BodyInst->InstanceBoneIndex; // If we could not find it - warn. if (BoneIndex == INDEX_NONE || BoneIndex >= GetNumSpaceBases()) { const FName BodyName = PhysicsAsset->BodySetup[i]->BoneName; UE_LOG(LogPhysics, Log, TEXT("UpdateRBBones: WARNING: Failed to find bone '%s' need by PhysicsAsset '%s' in SkeletalMesh '%s'."), *BodyName.ToString(), *PhysicsAsset->GetName(), *SkeletalMesh->GetName()); } else { #if WITH_PHYSX // update bone transform to world const FTransform BoneTransform = InSpaceBases[BoneIndex] * CurrentLocalToWorld; if(BoneTransform.ContainsNaN()) { const FName BodyName = PhysicsAsset->BodySetup[i]->BoneName; UE_LOG(LogPhysics, Warning, TEXT("UpdateKinematicBonesToAnim: Trying to set transform with bad data %s on PhysicsAsset '%s' in SkeletalMesh '%s' for bone '%s'"), *BoneTransform.ToHumanReadableString(), *PhysicsAsset->GetName(), *SkeletalMesh->GetName(), *BodyName.ToString()); continue; } // If kinematic and not teleporting, set kinematic target PxRigidDynamic* PRigidDynamic = BodyInst->GetPxRigidDynamic_AssumesLocked(); if (!IsRigidBodyNonKinematic_AssumesLocked(PRigidDynamic) && !bTeleport) { PhysScene->SetKinematicTarget_AssumesLocked(BodyInst, BoneTransform, true); } // Otherwise, set global pose else { const PxTransform PNewPose = U2PTransform(BoneTransform); ensure(PNewPose.isValid()); PRigidDynamic->setGlobalPose(PNewPose); } #endif // now update scale // if uniform, we'll use BoneTranform if (MeshScale3D.IsUniform()) { // @todo UE4 should we update scale when it's simulated? BodyInst->UpdateBodyScale(BoneTransform.GetScale3D()); } else { // @note When you have non-uniform scale on mesh base, // hierarchical bone transform can update scale too often causing performance issue // So we just use mesh scale for all bodies when non-uniform // This means physics representation won't be accurate, but // it is performance friendly by preventing too frequent physics update BodyInst->UpdateBodyScale(MeshScale3D); } } } else { //make sure you have physics weight or blendphysics on, otherwise, you'll have inconsistent representation of bodies // @todo make this to be kismet log? But can be too intrusive if (!bBlendPhysics && BodyInst->PhysicsBlendWeight <= 0.f && BodyInst->BodySetup.IsValid()) { UE_LOG(LogPhysics, Warning, TEXT("%s(Mesh %s, PhysicsAsset %s, Bone %s) is simulating, but no blending. "), *GetName(), *GetNameSafe(SkeletalMesh), *GetNameSafe(PhysicsAsset), *BodyInst->BodySetup.Get()->BoneName.ToString()); } } } #if WITH_PHYSX // Unlock the scenes if (bHasBodiesInSyncScene) { SCENE_UNLOCK_WRITE(PhysScene->GetPhysXScene(PST_Sync)) } if (bHasBodiesInAsyncScene) { SCENE_UNLOCK_WRITE(PhysScene->GetPhysXScene(PST_Async)) } #endif } } else { //per poly update requires us to update all vertex positions if (MeshObject)
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::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::ComponentOverlapTest(class UPrimitiveComponent* PrimComp, const FVector& Pos, const FRotator& Rot, const struct FComponentQueryParams& Params) const { if(GetPhysicsScene() == NULL) { return false; } if(PrimComp == NULL) { UE_LOG(LogCollision, Log, TEXT("ComponentOverlapMulti : No PrimComp")); return false; } // if target is skeletalmeshcomponent and do not support singlebody physics, we don't support this yet // talk to @JG, SP, LH if ( !PrimComp->ShouldTrackOverlaps() ) { UE_LOG(LogCollision, Log, TEXT("ComponentOverlapMulti : (%s) Does not support skeletalmesh with Physics Asset and destructibles."), *PrimComp->GetPathName()); return false; } #if WITH_PHYSX ECollisionChannel TraceChannel = PrimComp->GetCollisionObjectType(); PxRigidActor* PRigidActor = PrimComp->BodyInstance.GetPxRigidActor(); if(PRigidActor == NULL) { UE_LOG(LogCollision, Log, TEXT("ComponentOverlapMulti : (%s) No physics data"), *PrimComp->GetPathName()); return false; } // calculate the test global pose of the actor PxTransform PTestGlobalPose = U2PTransform(FTransform(Rot, Pos)); // Get all the shapes from the actor TArray<PxShape*, TInlineAllocator<8>> PShapes; PShapes.AddZeroed(PRigidActor->getNbShapes()); int32 NumShapes = PRigidActor->getShapes(PShapes.GetData(), PShapes.Num()); // Iterate over each shape for(int32 ShapeIdx=0; ShapeIdx<PShapes.Num(); ShapeIdx++) { PxShape* PShape = PShapes[ShapeIdx]; check(PShape); // Calc shape global pose PxTransform PLocalPose = PShape->getLocalPose(); PxTransform PShapeGlobalPose = PTestGlobalPose.transform(PLocalPose); GET_GEOMETRY_FROM_SHAPE(PGeom, PShape); if(PGeom != NULL) { if( GeomOverlapTest(this, *PGeom, PShapeGlobalPose, TraceChannel, Params, FCollisionResponseParams(PrimComp->GetCollisionResponseToChannels()))) { // in this test, it only matters true or false. // if we found first true, we don't care next test anymore. return true; } } } #endif //WITH_PHYSX return false; }