void UDestructibleComponent::AddImpulse( FVector Impulse, FName BoneName /*= NAME_None*/, bool bVelChange /*= false*/ ) { #if WITH_APEX int32 ChunkIdx = BoneIdxToChunkIdx(GetBoneIndex(BoneName)); PxRigidDynamic* PActor = ApexDestructibleActor->getChunkPhysXActor(ChunkIdx); if (PActor != NULL) { SCOPED_SCENE_WRITE_LOCK(PActor->getScene()); PActor->addForce(U2PVector(Impulse), bVelChange ? PxForceMode::eVELOCITY_CHANGE : PxForceMode::eIMPULSE); } #endif }
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 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::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 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; } }
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 }
void FPhysSubstepTask::SubstepInterpolation(float InAlpha) { #if WITH_PHYSX #if WITH_APEX PxScene * PScene = PAScene->getPhysXScene(); #else PxScene * PScene = PAScene; #endif PhysTargetMap & Targets = PhysTargetBuffers[!External]; /** Note: We lock the entire scene before iterating. The assumption is that removing an FBodyInstance from the map will also be wrapped by this lock */ SCENE_LOCK_WRITE(PScene); for (PhysTargetMap::TIterator Itr = Targets.CreateIterator(); Itr; ++Itr) { FPhysTarget & PhysTarget = Itr.Value(); FBodyInstance* BodyInstance = Itr.Key(); PxRigidDynamic * PRigidDynamic = BodyInstance->GetPxRigidDynamic(); if (PRigidDynamic == NULL) { continue; } //We should only be iterating over actors that belong to this scene check(PRigidDynamic->getScene() == PScene); ApplyForces(PhysTarget, BodyInstance); ApplyTorques(PhysTarget, BodyInstance); InterpolateKinematicActor(PhysTarget, BodyInstance, InAlpha); } /** Final substep */ if (InAlpha >= 1.f) { Targets.Empty(Targets.Num()); } SCENE_UNLOCK_WRITE(PScene); #endif }
DestructibleActorJointImpl::DestructibleActorJointImpl(const DestructibleActorJointDesc& desc, DestructibleScene& dscene) : joint(NULL) { if (desc.destructible[0] == NULL && desc.destructible[1] == NULL) { APEX_DEBUG_WARNING("Both destructible actors in DestructibleActorJoint are NULL."); return; } PxRigidActor* actor[2] = {desc.actor[0], desc.actor[1]}; PxVec3 localAxis[2] = {desc.localAxis[0], desc.localAxis[1]}; PxVec3 localAnchor[2] = {desc.localAnchor[0], desc.localAnchor[1]}; PxVec3 localNormal[2] = {desc.localNormal[0], desc.localNormal[1]}; PxTransform localFrame[2]; for (int i = 0; i < 2; ++i) { if (desc.destructible[i] == NULL) { structure[i] = NULL; attachmentChunkIndex[i] = ModuleDestructibleConst::INVALID_CHUNK_INDEX; if(NULL == actor[i]) { // World constrained PxMat33 rot(desc.globalAxis[i],desc.globalNormal[i],desc.globalAxis[i].cross(desc.globalNormal[i])); localFrame[i].p = desc.globalAnchor[i]; localFrame[i].q = PxQuat(rot); localFrame[i].q.normalize(); } else { // Constrained to physics object PxMat33 rot(localAxis[i], localNormal[i], localAxis[i].cross(localNormal[i])); localFrame[i].p = localAnchor[i]; localFrame[i].q = PxQuat(rot); localFrame[i].q.normalize(); } continue; } PxRigidDynamic* attachActor = NULL; DestructibleActorImpl& destructible = ((DestructibleActorProxy*)desc.destructible[i])->impl; structure[i] = destructible.getStructure(); attachmentChunkIndex[i] = desc.attachmentChunkIndex[i]; if (attachmentChunkIndex[i] >= 0 && attachmentChunkIndex[i] < (int32_t)destructible.getDestructibleAsset()->getChunkCount()) { DestructibleStructure::Chunk& chunk = structure[i]->chunks[destructible.getFirstChunkIndex() + attachmentChunkIndex[i]]; attachActor = structure[i]->dscene->chunkIntact(chunk); } SCOPED_PHYSX_LOCK_READ(dscene.getModulePhysXScene()); if (attachActor == NULL) { float minDistance = PX_MAX_F32; for (uint32_t j = 0; j < destructible.getDestructibleAsset()->getChunkCount(); ++j) { DestructibleAssetParametersNS::Chunk_Type& source = destructible.getDestructibleAsset()->mParams->chunks.buf[j]; const bool hasChildren = source.numChildren != 0; if (!hasChildren) // Only attaching to lowest-level chunks, initially { DestructibleStructure::Chunk& chunk = structure[i]->chunks[destructible.getFirstChunkIndex() + j]; PxRigidDynamic* actor = structure[i]->dscene->chunkIntact(chunk); if (actor) { const float distance = (actor->getGlobalPose().transform(chunk.localSphereCenter) - desc.globalAnchor[i]).magnitude(); if (distance < minDistance) { attachActor = actor; attachmentChunkIndex[i] = (int32_t)(destructible.getFirstChunkIndex() + j); minDistance = distance; } } } } } if (attachActor == NULL) { APEX_DEBUG_WARNING("No physx actor could be found in destructible actor %p to attach the joint.", desc.destructible[i]); return; } actor[i] = (PxRigidActor*)attachActor; if (attachActor->getScene() != NULL && dscene.getModulePhysXScene() != attachActor->getScene()) { APEX_DEBUG_WARNING("Trying to joint actors from a scene different from the joint scene."); return; } localAnchor[i] = attachActor->getGlobalPose().transformInv(desc.globalAnchor[i]); localAxis[i] = attachActor->getGlobalPose().rotateInv(desc.globalAxis[i]); localNormal[i] = attachActor->getGlobalPose().rotateInv(desc.globalNormal[i]); PxMat33 rot(localAxis[i], localNormal[i], localAxis[i].cross(localNormal[i])); localFrame[i].p = localAnchor[i]; localFrame[i].q = PxQuat(rot); localFrame[i].q.normalize(); } dscene.getModulePhysXScene()->lockRead(); switch (desc.type) { case PxJointConcreteType::eD6: joint = PxD6JointCreate(dscene.getModulePhysXScene()->getPhysics(), actor[0], localFrame[0], actor[1], localFrame[1]); break; case PxJointConcreteType::eDISTANCE: joint = PxDistanceJointCreate(dscene.getModulePhysXScene()->getPhysics(), actor[0], localFrame[0], actor[1], localFrame[1]); break; case PxJointConcreteType::eFIXED: joint = PxFixedJointCreate(dscene.getModulePhysXScene()->getPhysics(), actor[0], localFrame[0], actor[1], localFrame[1]); break; case PxJointConcreteType::ePRISMATIC: joint = PxPrismaticJointCreate(dscene.getModulePhysXScene()->getPhysics(), actor[0], localFrame[0], actor[1], localFrame[1]); break; case PxJointConcreteType::eREVOLUTE: joint = PxRevoluteJointCreate(dscene.getModulePhysXScene()->getPhysics(), actor[0], localFrame[0], actor[1], localFrame[1]); break; case PxJointConcreteType::eSPHERICAL: joint = PxSphericalJointCreate(dscene.getModulePhysXScene()->getPhysics(), actor[0], localFrame[0], actor[1], localFrame[1]); break; default: PX_ALWAYS_ASSERT(); break; } dscene.getModulePhysXScene()->unlockRead(); PX_ASSERT(joint != NULL); }
void UPhysicsHandleComponent::GrabComponent(UPrimitiveComponent* InComponent, FName InBoneName, FVector Location, bool bConstrainRotation) { // If we are already holding something - drop it first. if(GrabbedComponent != NULL) { ReleaseComponent(); } if(!InComponent) { return; } #if WITH_PHYSX // Get the PxRigidDynamic that we want to grab. FBodyInstance* BodyInstance = InComponent->GetBodyInstance(InBoneName); if (!BodyInstance) { return; } PxRigidDynamic* Actor = BodyInstance->GetPxRigidDynamic(); if (!Actor) return; // Get the scene the PxRigidDynamic we want to grab is in. PxScene* Scene = Actor->getScene(); check(Scene); // Get transform of actor we are grabbing PxVec3 KinLocation = U2PVector(Location); PxTransform GrabbedActorPose = Actor->getGlobalPose(); PxTransform KinPose(KinLocation, GrabbedActorPose.q); // set target and current, so we don't need another "Tick" call to have it right TargetTransform = CurrentTransform = P2UTransform(KinPose); // If we don't already have a handle - make one now. if (!HandleData) { // Create kinematic actor we are going to create joint with. This will be moved around with calls to SetLocation/SetRotation. PxRigidDynamic* KinActor = Scene->getPhysics().createRigidDynamic(KinPose); KinActor->setRigidDynamicFlag(PxRigidDynamicFlag::eKINEMATIC, true); KinActor->setMass(1.0f); KinActor->setMassSpaceInertiaTensor(PxVec3(1.0f, 1.0f, 1.0f)); // No bodyinstance KinActor->userData = NULL; // Add to Scene Scene->addActor(*KinActor); // Save reference to the kinematic actor. KinActorData = KinActor; // Create the joint PxVec3 LocalHandlePos = GrabbedActorPose.transformInv(KinLocation); PxD6Joint* NewJoint = PxD6JointCreate(Scene->getPhysics(), KinActor, PxTransform::createIdentity(), Actor, PxTransform(LocalHandlePos)); if(!NewJoint) { HandleData = 0; } else { // No constraint instance NewJoint->userData = NULL; HandleData = NewJoint; // Remember the scene index that the handle joint/actor are in. FPhysScene* RBScene = FPhysxUserData::Get<FPhysScene>(Scene->userData); const uint32 SceneType = InComponent->BodyInstance.UseAsyncScene() ? PST_Async : PST_Sync; SceneIndex = RBScene->PhysXSceneIndex[SceneType]; // Setting up the joint NewJoint->setMotion(PxD6Axis::eX, PxD6Motion::eFREE); NewJoint->setMotion(PxD6Axis::eY, PxD6Motion::eFREE); NewJoint->setMotion(PxD6Axis::eZ, PxD6Motion::eFREE); NewJoint->setDrive(PxD6Drive::eX, PxD6JointDrive(LinearStiffness, LinearDamping, PX_MAX_F32, PxD6JointDriveFlag::eACCELERATION)); NewJoint->setDrive(PxD6Drive::eY, PxD6JointDrive(LinearStiffness, LinearDamping, PX_MAX_F32, PxD6JointDriveFlag::eACCELERATION)); NewJoint->setDrive(PxD6Drive::eZ, PxD6JointDrive(LinearStiffness, LinearDamping, PX_MAX_F32, PxD6JointDriveFlag::eACCELERATION)); NewJoint->setDrivePosition(PxTransform(PxVec3(0,0,0))); NewJoint->setMotion(PxD6Axis::eTWIST, PxD6Motion::eFREE); NewJoint->setMotion(PxD6Axis::eSWING1, PxD6Motion::eFREE); NewJoint->setMotion(PxD6Axis::eSWING2, PxD6Motion::eFREE); bRotationConstrained = bConstrainRotation; if (bRotationConstrained) { NewJoint->setDrive(PxD6Drive::eSLERP, PxD6JointDrive(AngularStiffness, AngularDamping, PX_MAX_F32, PxD6JointDriveFlag::eACCELERATION)); //NewJoint->setDrive(PxD6Drive::eTWIST, PxD6JointDrive(AngularStiffness, AngularDamping, PX_MAX_F32, PxD6JointDriveFlag::eACCELERATION)); //NewJoint->setDrive(PxD6Drive::eSWING, PxD6JointDrive(AngularStiffness, AngularDamping, PX_MAX_F32, PxD6JointDriveFlag::eACCELERATION)); //PosJointDesc.setGlobalAxis(NxVec3(0,0,1)); } } } #endif // WITH_PHYSX GrabbedComponent = InComponent; GrabbedBoneName = InBoneName; }
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(); ChunkCollisionResponse.SetCollisionResponseContainer(CollResponse); ChunkCollisionResponse.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); ChunkCollisionResponse.SetAllChannels(ECR_Ignore); } // Passing AssetInstanceID = 0 so we'll have self-collision AActor* Owner = GetOwner(); CreateShapeFilterData(MoveChannel, (Owner ? Owner->GetUniqueID() : 0), CollResponse, 0, 0, PQueryFilterData, PSimFilterData, BodyInstance.bUseCCD, BodyInstance.bNotifyRigidBodyCollision, false); // 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 == SF_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() ? PST_Async : PST_Sync; NxApexScene* ApexScene = PhysScene->GetApexScene(SceneType); check(ApexScene); // 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; // Setup chunk user data arrays. We have to make sure PhysxChunkUserData will not be reallocated when growing, so we // reserver ChunkCount here already ChunkInfos.Empty(ChunkCount); PhysxChunkUserData.Empty(ChunkCount); // 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(PRootActor->getScene()); // Sleep/wake up as appropriate if (BodyInstance.bStartAwake) { PRootActor->wakeUp(); } else { PRootActor->putToSleep(); } } UpdateBounds(); #endif // #if WITH_APEX }