void UDestructibleComponent::SetCollisionResponseForActor(const FCollisionResponse& ColResponse, PxRigidDynamic* Actor, int32 ChunkIdx) { // Get collision channel and response PxFilterData PQueryFilterData, PSimFilterData; uint8 MoveChannel = GetCollisionObjectType(); if(IsCollisionEnabled()) { AActor* Owner = GetOwner(); CreateShapeFilterData(MoveChannel, (Owner ? Owner->GetUniqueID() : 0), ColResponse.GetResponseContainer(), 0, ChunkIdxToBoneIdx(ChunkIdx), PQueryFilterData, PSimFilterData, BodyInstance.bUseCCD, BodyInstance.bNotifyRigidBodyCollision, false); PQueryFilterData.word3 |= EPDF_SimpleCollision | EPDF_ComplexCollision; SCOPED_SCENE_WRITE_LOCK(Actor->getScene()); TArray<PxShape*> Shapes; Shapes.AddUninitialized(Actor->getNbShapes()); int ShapeCount = Actor->getShapes(Shapes.GetTypedData(), Shapes.Num()); for (int32 i=0; i < ShapeCount; ++i) { PxShape* Shape = Shapes[i]; Shape->setQueryFilterData(PQueryFilterData); Shape->setSimulationFilterData(PSimFilterData); Shape->setFlag(PxShapeFlag::eSCENE_QUERY_SHAPE, true); Shape->setFlag(PxShapeFlag::eSIMULATION_SHAPE, true); Shape->setFlag(PxShapeFlag::eVISUALIZATION, true); } } }
void CPhysicsObject::EnableCollisions(bool enable) { if (IsCollisionEnabled() == enable) return; if (enable) { m_pObject->setCollisionFlags(m_pObject->getCollisionFlags() & ~btCollisionObject::CF_NO_CONTACT_RESPONSE); } else { m_pObject->setCollisionFlags(m_pObject->getCollisionFlags() | btCollisionObject::CF_NO_CONTACT_RESPONSE); } }
void CPhysicsObject::OutputDebugInfo() const { Msg("-----------------\n"); if (m_pName) Msg("Object: %s\n", m_pName); Msg("Mass: %f (inv %f)\n", GetMass(), GetInvMass()); Vector pos; QAngle ang; GetPosition(&pos, &ang); Msg("Position: %f %f %f\nAngle: %f %f %f\n", pos.x, pos.y, pos.z, ang.x, ang.y, ang.z); Vector inertia = GetInertia(); Vector invinertia = GetInvInertia(); Msg("Inertia: %f %f %f (inv %f %f %f)\n", inertia.x, inertia.y, inertia.z, invinertia.x, invinertia.y, invinertia.z); Vector vel; AngularImpulse angvel; GetVelocity(&vel, &angvel); Msg("Velocity: %f, %f, %f\nAng Velocity: %f, %f, %f\n", vel.x, vel.y, vel.z, angvel.x, angvel.y, angvel.z); float dampspeed, damprot; GetDamping(&dampspeed, &damprot); Msg("Damping %f linear, %f angular\n", dampspeed, damprot); Vector dragBasis; Vector angDragBasis; ConvertPosToHL(m_dragBasis, dragBasis); ConvertDirectionToHL(m_angDragBasis, angDragBasis); Msg("Linear Drag: %f, %f, %f (factor %f)\n", dragBasis.x, dragBasis.y, dragBasis.z, m_dragCoefficient); Msg("Angular Drag: %f, %f, %f (factor %f)\n", angDragBasis.x, angDragBasis.y, angDragBasis.z, m_angDragCoefficient); // TODO: Attached to x controllers Msg("State: %s, Collision %s, Motion %s, Drag %s, Flags %04X (game %04x, index %d)\n", IsAsleep() ? "Asleep" : "Awake", IsCollisionEnabled() ? "Enabled" : "Disabled", IsStatic() ? "Static" : IsMotionEnabled() ? "Enabled" : "Disabled", IsDragEnabled() ? "Enabled" : "Disabled", m_pObject->getFlags(), GetGameFlags(), GetGameIndex() ); const char *pMaterialStr = g_SurfaceDatabase.GetPropName(m_materialIndex); surfacedata_t *surfaceData = g_SurfaceDatabase.GetSurfaceData(m_materialIndex); if (surfaceData) { Msg("Material: %s : density(%f), thickness(%f), friction(%f), elasticity(%f)\n", pMaterialStr, surfaceData->physics.density, surfaceData->physics.thickness, surfaceData->physics.friction, surfaceData->physics.elasticity); } Msg("-- COLLISION SHAPE INFO --\n"); g_PhysicsCollision.OutputDebugInfo((CPhysCollide *)m_pObject->getCollisionShape()->getUserPointer()); }
void UDestructibleComponent::SetCollisionResponseForActor(PxRigidDynamic* Actor, int32 ChunkIdx, const FCollisionResponseContainer* ResponseOverride /*= NULL*/) { #if WITH_APEX if (ApexDestructibleActor == NULL) { return; } // Get collision channel and response PxFilterData PQueryFilterData, PSimFilterData; uint8 MoveChannel = GetCollisionObjectType(); if(IsCollisionEnabled()) { UDestructibleMesh* TheDestructibleMesh = GetDestructibleMesh(); AActor* Owner = GetOwner(); bool bLargeChunk = IsChunkLarge(ChunkIdx); const FCollisionResponseContainer& UseResponse = ResponseOverride == NULL ? (bLargeChunk ? LargeChunkCollisionResponse.GetResponseContainer() : SmallChunkCollisionResponse.GetResponseContainer()) : *ResponseOverride; physx::PxU32 SupportDepth = TheDestructibleMesh->ApexDestructibleAsset->getChunkDepth(ChunkIdx); const bool bEnableImpactDamage = IsImpactDamageEnabled(TheDestructibleMesh, SupportDepth); CreateShapeFilterData(MoveChannel, GetUniqueID(), UseResponse, 0, ChunkIdxToBoneIdx(ChunkIdx), PQueryFilterData, PSimFilterData, BodyInstance.bUseCCD, bEnableImpactDamage, false); PQueryFilterData.word3 |= EPDF_SimpleCollision | EPDF_ComplexCollision; SCOPED_SCENE_WRITE_LOCK(Actor->getScene()); TArray<PxShape*> Shapes; Shapes.AddUninitialized(Actor->getNbShapes()); int ShapeCount = Actor->getShapes(Shapes.GetData(), Shapes.Num()); for (int32 i=0; i < ShapeCount; ++i) { PxShape* Shape = Shapes[i]; Shape->setQueryFilterData(PQueryFilterData); Shape->setSimulationFilterData(PSimFilterData); Shape->setFlag(PxShapeFlag::eSCENE_QUERY_SHAPE, true); Shape->setFlag(PxShapeFlag::eSIMULATION_SHAPE, true); Shape->setFlag(PxShapeFlag::eVISUALIZATION, true); } } #endif }
void UBoxComponent::SetBoxExtent(FVector NewBoxExtent, bool bUpdateOverlaps) { BoxExtent = NewBoxExtent; MarkRenderStateDirty(); // do this if already created // otherwise, it hasn't been really created yet if (bPhysicsStateCreated) { DestroyPhysicsState(); UpdateBodySetup(); CreatePhysicsState(); if ( bUpdateOverlaps && IsCollisionEnabled() && GetOwner() ) { UpdateOverlaps(); } } }
void UCapsuleComponent::SetCapsuleSize(float NewRadius, float NewHalfHeight, bool bUpdateOverlaps) { CapsuleHalfHeight = FMath::Max(NewHalfHeight, NewRadius); CapsuleRadius = NewRadius; MarkRenderStateDirty(); // do this if already created // otherwise, it hasn't been really created yet if (bPhysicsStateCreated) { DestroyPhysicsState(); UpdateBodySetup(); CreatePhysicsState(); if ( bUpdateOverlaps && IsCollisionEnabled() && GetOwner() ) { UpdateOverlaps(); } } }
void CPhysicsObject::WriteToTemplate( vphysics_save_cphysicsobject_t &objectTemplate ) { if ( m_collideType == COLLIDE_BALL ) { objectTemplate.pCollide = NULL; objectTemplate.sphereRadius = GetSphereRadius(); } else { objectTemplate.pCollide = GetCollide(); objectTemplate.sphereRadius = 0; } objectTemplate.isStatic = IsStatic(); objectTemplate.collisionEnabled = IsCollisionEnabled(); objectTemplate.gravityEnabled = IsGravityEnabled(); objectTemplate.dragEnabled = IsDragEnabled(); objectTemplate.motionEnabled = IsMotionEnabled(); objectTemplate.isAsleep = IsAsleep(); objectTemplate.isTrigger = IsTrigger(); objectTemplate.materialIndex = m_materialIndex; objectTemplate.mass = GetMass(); objectTemplate.rotInertia = GetInertia(); GetDamping( &objectTemplate.speedDamping, &objectTemplate.rotSpeedDamping ); objectTemplate.massCenterOverride = m_massCenterOverride; objectTemplate.callbacks = m_callbacks; objectTemplate.gameFlags = m_gameFlags; objectTemplate.volume = GetVolume(); objectTemplate.dragCoefficient = m_dragCoefficient; objectTemplate.angDragCoefficient = m_angDragCoefficient; objectTemplate.pShadow = m_pShadow; objectTemplate.hasShadowController = (m_pShadow != NULL) ? true : false; //bool m_shadowTempGravityDisable; objectTemplate.collideType = m_collideType; objectTemplate.contentsMask = m_contentsMask; GetPosition( &objectTemplate.origin, &objectTemplate.angles ); GetVelocity( &objectTemplate.velocity, &objectTemplate.angVelocity ); }
void UDestructibleComponent::SetCollisionResponseForShape(PxShape* Shape, int32 ChunkIdx) { // Get collision channel and response PxFilterData PQueryFilterData, PSimFilterData; uint8 MoveChannel = GetCollisionObjectType(); if (IsCollisionEnabled()) { AActor* Owner = GetOwner(); bool bLargeChunk = IsChunkLarge(ChunkIdx); const FCollisionResponse& ColResponse = bLargeChunk ? LargeChunkCollisionResponse : SmallChunkCollisionResponse; //TODO: we currently assume chunks will not have impact damage as it's very expensive. Should look into exposing this a bit more CreateShapeFilterData(MoveChannel, (Owner ? Owner->GetUniqueID() : 0), ColResponse.GetResponseContainer(), 0, ChunkIdxToBoneIdx(ChunkIdx), PQueryFilterData, PSimFilterData, BodyInstance.bUseCCD, false, false); PQueryFilterData.word3 |= EPDF_SimpleCollision | EPDF_ComplexCollision; SCOPED_SCENE_WRITE_LOCK(Shape->getActor()->getScene()); Shape->setQueryFilterData(PQueryFilterData); Shape->setSimulationFilterData(PSimFilterData); Shape->setFlag(PxShapeFlag::eSCENE_QUERY_SHAPE, true); Shape->setFlag(PxShapeFlag::eSIMULATION_SHAPE, true); Shape->setFlag(PxShapeFlag::eVISUALIZATION, true); } }
bool UPaperGroupedSpriteComponent::ShouldCreatePhysicsState() const { return IsRegistered() && (bAlwaysCreatePhysicsState || IsCollisionEnabled()); }
void CCharEntity::OnStepBefore() { if (IsCollisionEnabled() && !IsRagdollActive()) { CEnvInfo EnvInfo; vector3 Pos = GetTransform().pos_component(); Pos.y += Height; float DistanceToGround; if (EnvQueryMgr->GetEnvInfoAt(Pos, EnvInfo, Height + 0.1f, GetUniqueID())) { DistanceToGround = Pos.y - Height - EnvInfo.WorldHeight; GroundMtl = EnvInfo.Material; } else { DistanceToGround = FLT_MAX; GroundMtl = InvalidMaterial; } CRigidBody* pMasterBody = Composite->GetMasterBody(); bool BodyIsEnabled = IsEnabled(); vector3 AngularVel = pMasterBody->GetAngularVelocity(); vector3 LinearVel = pMasterBody->GetLinearVelocity(); vector3 DesiredLVelChange = DesiredLinearVel - LinearVel; if (DistanceToGround <= 0.f) { // No torques now, angular velocity changes by impulse immediately to desired value bool Actuated = DesiredAngularVel != AngularVel.y; if (Actuated) { if (!BodyIsEnabled) SetEnabled(true); pMasterBody->SetAngularVelocity(vector3(0.f, DesiredAngularVel, 0.f)); } if (!DesiredLVelChange.isequal(vector3::Zero, 0.0001f)) { if (!Actuated) { Actuated = true; SetEnabled(true); } // Vertical movement for non-flying actors is impulse (jump). // Since speed if already clamped to actor caps, we save vertical desired velocity as is. // Spring force pushes us from below the ground. //!!!!!!!!!!!!!!! //!!!calc correct impulse for the spring! //!!!!!!!!!!!!!!! float VerticalDesVelChange = DesiredLVelChange.y - (50.0f * DistanceToGround); float Mass = pMasterBody->GetMass(); //!!!remove calcs for Y, it is zero (optimization)! dVector3 ODEForce; dWorldImpulseToForce(Level->GetODEWorldID(), dReal(Level->GetStepSize()), DesiredLVelChange.x * Mass, 0.f, DesiredLVelChange.z * Mass, ODEForce); float SqForceMagnitude = (float)dCalcVectorLengthSquare3(ODEForce); if (SqForceMagnitude > 0.f) { float MaxForceMagnitude = Mass * MaxHorizAccel; float SqMaxForceMagnitude = MaxForceMagnitude * MaxForceMagnitude; if (SqForceMagnitude > SqMaxForceMagnitude) dScaleVector3(ODEForce, MaxForceMagnitude / n_sqrt(SqForceMagnitude)); dBodyAddForce(pMasterBody->GetODEBodyID(), ODEForce[0], ODEForce[1], ODEForce[2]); } if (VerticalDesVelChange != 0.f) { dWorldImpulseToForce(Level->GetODEWorldID(), dReal(Level->GetStepSize()), 0.f, VerticalDesVelChange * Mass, 0.f, ODEForce); dBodyAddForce(pMasterBody->GetODEBodyID(), ODEForce[0], ODEForce[1], ODEForce[2]); } } if (BodyIsEnabled && !Actuated && DistanceToGround > -0.002f) { const float FreezeThreshold = 0.00001f; //???use TINY? bool AVelIsAlmostZero = n_fabs(AngularVel.y) < FreezeThreshold; bool LVelIsAlmostZero = n_fabs(LinearVel.x) * (float)Level->GetStepSize() < FreezeThreshold && n_fabs(LinearVel.z) * (float)Level->GetStepSize() < FreezeThreshold; if (AVelIsAlmostZero) pMasterBody->SetAngularVelocity(vector3::Zero); if (LVelIsAlmostZero) pMasterBody->SetLinearVelocity(vector3::Zero); if (AVelIsAlmostZero && LVelIsAlmostZero) SetEnabled(false); } } //???!!!else (when falling) apply damping?! } // NOTE: do NOT call the parent class, we don't need any damping }
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 }