void PhysXPhysics::AddShape(Actor* pActor, PxGeometry* geometry, float density, const std::string& physicsMaterial, bool gravityEnabled, float linearDamping, float angularDamping, const std::string& bodyType) { BE_ASSERT(pActor); ActorId actorId = pActor->GetId(); BE_ASSERTf(m_actorRigidBodyMap.find(actorId) == m_actorRigidBodyMap.end(), "Actor with more than one rigidbody"); Mat4x4 transform = Mat4x4::g_Identity; TransformComponent* pTransformComponent = pActor->GetComponent<TransformComponent>(TransformComponent::g_Name); if (pTransformComponent) { transform = pTransformComponent->GetTransform(); } else { //Doesnt work without transform BE_ERROR("Actor %s PhysicsComponent requires Shape to have Transform Component: %d", actorId); return; } PhysicsMaterialData material(LookupMaterialData(physicsMaterial)); PxMaterial* mat = m_pPhysicsSdk->createMaterial(material.m_friction, material.m_friction, material.m_restitution); Vec3 translation, scale; Quaternion rotation; bool ok = transform.Decompose(translation, rotation, scale); PxQuat pxRot; PxVec3 pxLoc; Vec3ToPxVec(translation, &pxLoc); QuaternionToPxQuat(rotation, &pxRot); PxTransform t(pxLoc, pxRot); if (bodyType == "Dynamic") { PxRigidDynamic* body = PxCreateDynamic(*m_pPhysicsSdk, t, *geometry, *mat, density); body->setActorFlag(PxActorFlag::eDISABLE_GRAVITY, !gravityEnabled); PxRigidBodyExt::updateMassAndInertia(*body, density); body->setLinearDamping(linearDamping); body->setAngularDamping(angularDamping); m_pScene->addActor(*body); m_actorRigidBodyMap[actorId] = body; m_rigidBodyActorMap[body] = actorId; } else { BE_ERROR("[Physics] BodyType not supported: %s", bodyType.c_str()); return; } }
void SampleSubmarine::explode(PxRigidActor* actor, const PxVec3& explosionPos, const PxReal explosionStrength) { size_t numRenderActors = mRenderActors.size(); for(PxU32 i = 0; i < numRenderActors; i++) { if(&(mRenderActors[i]->getPhysicsShape()->getActor()) == actor) { PxShape* shape = mRenderActors[i]->getPhysicsShape(); PxTransform pose = PxShapeExt::getGlobalPose(*shape); PxGeometryHolder geom = shape->getGeometry(); // create new actor from shape (to split compound) PxRigidDynamic* newActor = mPhysics->createRigidDynamic(pose); if(!newActor) fatalError("createRigidDynamic failed!"); PxShape* newShape = newActor->createShape(geom.any(), *mMaterial); newShape->userData = mRenderActors[i]; mRenderActors[i]->setPhysicsShape(newShape); newActor->setActorFlag(PxActorFlag::eVISUALIZATION, true); newActor->setLinearDamping(10.5f); newActor->setAngularDamping(0.5f); PxRigidBodyExt::updateMassAndInertia(*newActor, 1.0f); mScene->addActor(*newActor); mPhysicsActors.push_back(newActor); PxVec3 explosion = pose.p - explosionPos; PxReal len = explosion.normalize(); explosion *= (explosionStrength / len); newActor->setLinearVelocity(explosion); newActor->setAngularVelocity(PxVec3(1,2,3)); } } removeActor(actor); }
void SampleParticles::Raygun::update(float dtime) { if(!isEnabled()) return; PX_ASSERT(mSample && mForceSmokeCapsule && mForceWaterCapsule && mRenderActor); // access properties from sample PxScene& scene = mSample->getActiveScene(); PxVec3 position = mSample->getCamera().getPos(); PxTransform cameraPose = mSample->getCamera().getViewMatrix(); PxMat33 cameraBase(cameraPose.q); PxVec3 cameraForward = -cameraBase[2]; PxVec3 cameraUp = -cameraBase[1]; // perform raycast here and update impact point PxRaycastHit hit; mIsImpacting = scene.raycastSingle(cameraPose.p, cameraForward, 500.0f, PxSceneQueryFlags(0xffffffff), hit); float impactParam = mIsImpacting ? (hit.impact - position).magnitude() : FLT_MAX; PxTransform rayPose(position + cameraUp * 0.5f, cameraPose.q*PxQuat(PxHalfPi, PxVec3(0,1,0))); updateRayCapsule(mForceSmokeCapsule, rayPose, 1.0f); updateRayCapsule(mForceWaterCapsule, rayPose, 0.3f); mRenderActor->setTransform(rayPose); // if we had an impact if (impactParam < FLT_MAX) { PxVec3 impactPos = position + cameraForward*impactParam; // update emitter with new impact point and direction if(mSmokeEmitter.emitter) mSmokeEmitter.emitter->setLocalPose(PxTransform(impactPos, directionToQuaternion(-cameraForward))); if(mDebrisEmitter.emitter) mDebrisEmitter.emitter->setLocalPose(PxTransform(impactPos, directionToQuaternion(-cameraForward))); // spawn new RB debris if(mRbDebrisTimer < 0.0f && impactParam < FLT_MAX) { mRbDebrisTimer = RAYGUN_RB_DEBRIS_RATE; PxVec3 randDir(getSampleRandom().rand(-1.0f, 1.0f), getSampleRandom().rand(-1.0f, 1.0f), getSampleRandom().rand(-1.0f, 1.0f)); PxVec3 vel = -7.0f * (cameraForward + RAYGUN_RB_DEBRIS_ANGLE_RANDOMNESS * randDir.getNormalized()); PxVec3 dim(getSampleRandom().rand(0.0f, RAYGUN_RB_DEBRIS_SCALE), getSampleRandom().rand(0.0f, RAYGUN_RB_DEBRIS_SCALE), getSampleRandom().rand(0.0f, RAYGUN_RB_DEBRIS_SCALE)); // give spawn position, initial velocity and dimensions, spawn convex // which will not act in scene queries PxConvexMesh* convexMesh = generateConvex(mSample->getPhysics(), mSample->getCooking(), RAYGUN_RB_DEBRIS_SCALE); mSample->runtimeAssert(convexMesh, "Error generating convex for debris.\n"); PxRigidDynamic* debrisActor = PxCreateDynamic( mSample->getPhysics(), PxTransform(impactPos - cameraForward * 0.5f), PxConvexMeshGeometry(convexMesh), mSample->getDefaultMaterial(), 1.f); mSample->getActiveScene().addActor(*debrisActor); PX_ASSERT(debrisActor->getNbShapes() == 1); PxShape* debrisShape; debrisActor->getShapes(&debrisShape, 1); debrisShape->setFlag(PxShapeFlag::eSCENE_QUERY_SHAPE, false); debrisActor->setLinearVelocity(vel); debrisActor->setActorFlag(PxActorFlag::eVISUALIZATION, true); debrisActor->setAngularDamping(0.5f); // default material is green for debris RenderMaterial* debriMaterial = mSample->getMaterial(MATERIAL_HEIGHTFIELD); if(!debriMaterial) { debriMaterial = mSample->mRenderMaterials[MATERIAL_GREEN]; } mSample->createRenderObjectsFromActor(debrisActor, debriMaterial); mDebrisLifetime[debrisShape] = RAYGUN_RB_DEBRIS_LIFETIME; } } // update debris lifetime, remove if life ends DebrisLifetimeMap::iterator it = mDebrisLifetime.begin(); while(it != mDebrisLifetime.end()) { (*it).second -= dtime; if((*it).second < 0.0f) { PxShape* debrisShape = (*it).first; PX_ASSERT(debrisShape); // remove convex mesh PxConvexMeshGeometry geometry; bool isConvex = debrisShape->getConvexMeshGeometry(geometry); PX_ASSERT(isConvex); PX_UNUSED(isConvex); geometry.convexMesh->release(); // remove render and physics actor PxRigidActor& actorToRemove = debrisShape->getActor(); mSample->removeActor(&actorToRemove); actorToRemove.release(); // remove actor from lifetime map mDebrisLifetime.erase(it); it = mDebrisLifetime.begin(); continue; } ++it; } }
void SampleSubmarine::onTickPreRender(float dtime) { // handle mine (and submarine) explosion if(mSubmarineActor) { // explode all touched mines, apply damage and force to submarine PxVec3 subMarinePos = mSubmarineActor->getGlobalPose().p; const size_t nbExplodeSeamines = mMinesToExplode.size(); for(PxU32 i=0; i < nbExplodeSeamines; i++) { Seamine* mine = mMinesToExplode[i]; PxVec3 explosionPos = mine->mMineHead->getGlobalPose().p; // disable contact trigger callback of the chain & enable gravity const size_t nbLinks = mine->mLinks.size(); for(PxU32 j = 0; j < nbLinks; j++) { PxRigidDynamic* link = mine->mLinks[j]; setupFiltering(link, 0, 0); link->setActorFlag(PxActorFlag::eDISABLE_GRAVITY, false); } // remove mine head std::vector<Seamine*>::iterator mineIter = std::find(mSeamines.begin(), mSeamines.end(), mine); if(mineIter != mSeamines.end()) mSeamines.erase(mineIter); removeActor(mine->mMineHead); delete mine; // give damage to submarine static const PxReal strength = 400.0f; PxVec3 explosion = subMarinePos - explosionPos; PxReal len = explosion.normalize(); PxReal damage = strength * (1.0f/len); explosion *= damage; mSubmarineActor->addForce(explosion*300); gSubmarineHealth = PxMax(gSubmarineHealth-PxI32(damage), 0); if(gSubmarineHealth == 0) { mSubmarineCameraController->init(subMarinePos - getCamera().getViewDir()*10.0f, getCamera().getRot()); explode(mSubmarineActor, subMarinePos /*- explosion*0.2f*/, damage); mCameraAttachedToActor = NULL; mSubmarineCameraController->setFollowingMode(false); mSubmarineActor = NULL; break; } } mMinesToExplode.clear(); } // respawn Crabs const size_t nbCrabs = mCrabs.size(); for(PxU32 i = 0; i < nbCrabs; i++) { Crab* crab = mCrabs[i]; if(crab->needsRespawn()) { PxRigidDynamic* prevBody = crab->getCrabBody(); PxVec3 prevPos = prevBody->getGlobalPose().p; delete crab; mCrabs[i] = SAMPLE_NEW(Crab)(*this, prevPos, mManagedMaterials[MATERIAL_RED]); if(gCrab == crab) gCrab = mCrabs[i]; if(mCameraAttachedToActor == prevBody) mCameraAttachedToActor = mCrabs[i]->getCrabBody(); } } // update camera if(mCameraAttachedToActor) mSubmarineCameraController->updateFollowingMode(getCamera(), dtime, mCameraAttachedToActor->getGlobalPose().p); // start the simulation PhysXSample::onTickPreRender(dtime); }
Seamine* SampleSubmarine::createSeamine(const PxVec3& inPosition, PxReal inHeight) { static const PxReal chainLinkLength = 2.0f; static const PxReal linkSpacing = 0.05f; static const PxReal mineHeadRadius = 1.5f; const PxVec3 mineStartPos = inPosition; static const PxVec3 linkOffset = PxVec3(0, chainLinkLength + linkSpacing, 0); static const PxVec3 halfLinkOffset = linkOffset * 0.5f; static const PxVec3 linkDim = PxVec3(chainLinkLength*0.125f, chainLinkLength*0.5f, chainLinkLength*0.125f); PxU32 numLinks = PxU32((inHeight - 2.0f*mineHeadRadius) / (chainLinkLength + linkSpacing)); numLinks = numLinks ? numLinks : 1; Seamine* seamine = SAMPLE_NEW(Seamine); mSeamines.push_back(seamine); // create links from floor PxVec3 linkPos = mineStartPos + halfLinkOffset; PxRigidActor* prevActor = NULL; for(PxU32 i = 0; i < numLinks; i++) { // create the link actor PxRigidDynamic* link = createBox(linkPos, linkDim, NULL, mSeamineMaterial, 1.0f)->is<PxRigidDynamic>(); if(!link) fatalError("createBox failed!"); // back reference to mineHead link->userData = seamine; seamine->mLinks.push_back(link); setupFiltering(link, FilterGroup::eMINE_LINK, FilterGroup::eSUBMARINE); link->setLinearDamping(0.5f); link->setAngularDamping(0.5f); link->setActorFlag(PxActorFlag::eDISABLE_GRAVITY, true); // create distance joint between link and prevActor PxTransform linkFrameA = prevActor ? PxTransform(halfLinkOffset, PxQuat::createIdentity()) : PxTransform(mineStartPos, PxQuat::createIdentity()); PxTransform linkFrameB = PxTransform(-halfLinkOffset, PxQuat::createIdentity()); PxDistanceJoint *joint = PxDistanceJointCreate(getPhysics(), prevActor, linkFrameA, link, linkFrameB); if(!joint) fatalError("PxDistanceJointCreate failed!"); // set min & max distance to 0 joint->setMaxDistance(0.0f); joint->setMinDistance(0.0f); // setup damping & spring joint->setDamping(1.0f * link->getMass()); joint->setSpring(400.0f * link->getMass()); joint->setDistanceJointFlags(PxDistanceJointFlag::eMAX_DISTANCE_ENABLED | PxDistanceJointFlag::eMIN_DISTANCE_ENABLED | PxDistanceJointFlag::eSPRING_ENABLED); // add to joints array for cleanup mJoints.push_back(joint); prevActor = link; linkPos += linkOffset; } // create mine head linkPos.y += mineHeadRadius - (chainLinkLength*0.5f); PxRigidDynamic* mineHead = createSphere(linkPos, mineHeadRadius, NULL, mSeamineMaterial, 1.0f)->is<PxRigidDynamic>(); mineHead->userData = seamine; seamine->mMineHead = mineHead; mineHead->setLinearDamping(0.5f); mineHead->setAngularDamping(0.5f); mineHead->setActorFlag(PxActorFlag::eDISABLE_GRAVITY, true); // setup filtering to trigger contact reports when submarine touches the minehead setupFiltering(mineHead, FilterGroup::eMINE_HEAD, FilterGroup::eSUBMARINE); // create distance joint between mine head and prevActor PxTransform linkFrameA = PxTransform(halfLinkOffset, PxQuat::createIdentity()); PxTransform linkFrameB = PxTransform(PxVec3(0, -mineHeadRadius - linkSpacing*0.5f, 0), PxQuat::createIdentity()); PxDistanceJoint *joint = PxDistanceJointCreate(getPhysics(), prevActor, linkFrameA, mineHead, linkFrameB); if(!joint) fatalError("PxDistanceJointCreate failed!"); // set min & max distance to 0 joint->setMaxDistance(0.0f); joint->setMinDistance(0.0f); // setup damping & spring joint->setDamping(1.0f * mineHead->getMass()); joint->setSpring(400.0f * mineHead->getMass()); joint->setDistanceJointFlags(PxDistanceJointFlag::eMAX_DISTANCE_ENABLED | PxDistanceJointFlag::eMIN_DISTANCE_ENABLED | PxDistanceJointFlag::eSPRING_ENABLED); // add to joints array for cleanup mJoints.push_back(joint); return seamine; }
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 }