This library also contains an extension for synchronizing Blast state:
In order to use it create ExtPxManager:
ExtPxManager* pxManager = ExtPxManager::create(m_physics, m_tkFramework);
For every TkAsset prepare ExtPxAsset. Which contains TkAsset + collection of physics geometry for every chunk. Every chunk can contain any number of subchunks. Where each subchunk is basically PxConvexMeshGeometry with transform. Also every chunk can be marked as static (isStatic flag). If actor contains at least one static chunks in it's support graph it makes an actor kinematic (static), otherwise it's dynamic. Having zero subchunks makes chunk invisible in physics scene, it can be used for example to represent 'earth' as a special invisible static chunk and connect all near earth chunks to it.
To create a ExtPxFamily from an ExtPxAsset:
ExtPxFamilyDesc familyDesc; familyDesc.pxAsset = pxAsset; familyDesc.group = tkGroup; familyDesc.actorDesc.initialBondHealths = nullptr; familyDesc.actorDesc.initialSupportChunkHealths = nullptr; familyDesc.actorDesc.uniformInitialBondHealth = BOND_HEALTH_MAX; familyDesc.actorDesc.uniformInitialLowerSupportChunkHealth = 1.0f; ExtPxFamily* family = pxManager->createFamily(desc);
You can subscribe to family events in order to sync graphics (or anything else) with physics:
family->subscribe(listener);
Listener will be notified with all physics actors added and removed.
And finally spawn the family in some world position (the first actor/actors will be created and event will be fired to the listener):
ExtPxSpawnSettings spawnSettings = {
&pxScene,
defaultPxMaterial,
RIGIDBODY_DENSITY
};
family->spawn(PxTransform(0, 0, 0), spawnSettings);
You can get families actor's either from listening to events or by calling getActors(). Every ExtPxActor matches 1 <-> 1 with TkActor (which matches NvBlastActor accordingly).
ExtPxActor* actor = ....;
physx::PxRigidDynamic rigidDynamic = actor->getPxActor(); //
ExtPxActor remains internally unchanged through it's life time. Use ExtPxActor getChunkIndices() and getPxActor() to update graphics representation. Sample code:
const uint32_t* chunkIndices; size_t chunkIndexCount; actor.getChunkIndices(chunkIndices, chunkIndexCount); for (uint32_t i = 0; i < chunkIndexCount; i++) { uint32_t chunkIndex = chunkIndices[i]; for (Renderable* r : m_chunks[chunkIndex].renderables) { r->setTransform(actor.getPxActor()->getGlobalPose() * pxAsset.chunks[chunkIndex].convexes[0].transform); } }
In order to use joints set joint create function with ExtPxManager::setCreateJointFunction(...). It will be called when new TkJoint's are being created. All the joint updates and remove will be handled by manager internally.
In order to use it create it:
ExtImpactDamageManager* impactManager = ExtImpactDamageManager::create(pxManager);
Call it's onContact method on every PxSimulationEventCallback onContact()
class EventCallback : public PxSimulationEventCallback { public: EventCallback(ExtImpactDamageManager* manager) : m_manager(manager) {} virtual void onContact(const PxContactPairHeader& pairHeader, const PxContactPair* pairs, uint32_t nbPairs) { m_manager->onContact(pairHeader, pairs, nbPairs); } private: ExtImpactDamageManager* m_manager; };
Call applyDamage() when you want the buffered damage to be applied:
impactManager->applyDamage();
Also important to enable contact notification with custom filter shader for PxScene. ImpactDamageManager has a reference filter shader implementation which can be used for that:
PxSceneDesc sceneDesc; sceneDesc.filterShader = ExtImpactDamageManager::FilterShader;
ExtStressSolver* stressSolver = ExtStressSolver::create(family);
And then call update() every frame:
bool doDamage = true; // if you want to actually apply stress and damage actors stressSolver->update(doDamage);
By default it will apply scene gravity on static actors and centrifugal force on dynamic actors. Also applyImpulse(...) can be called for additional stress to apply:
stressSolver->applyImpulse(actor, position, force);
It fully utilizes the fact that it knows initial support graph structure and does maximum of processing in create(...) method calls. After that all actors split calls are synced internally quite fast and only the actual stress propagation takes most of computational time. Computational time is linearly proprtional to bondIterationsPerFrame setting. To fine tune look for balance between bondIterationsPerFrame and graphReductionLevel . The more bond iterations are set the more precise computation will be. The smaller graph allows to make higher fidelity computations witihing the same bond iterations per frame (same time spent), but actual cracks (damaged bonds) will be more sparsed as the result.
The idea is that you can use it to write synchronization events to the buffer (on server for example) and then apply this buffer on a client. TkFamily ID should be properly set for that.
3 types of events are supported:
In order to use it create ExtSync:
ExtSync* sync = ExtSync::create();
Then let ExtSync insatnce listen to family fracture commands and write them to internal buffer:
TkFamily* family = ...; family->addListener(*sync); // fracture family // ....
You can fully record TkFamily state or ExtPxFamily state at any moment by calling:
sync->syncFamily(tkFamily);
// or
sync->syncFamily(pxFamily);
Now you can take sync buffer:
const ExtSyncEvent*const* buffer; uint32_t size; sync->acquireSyncBuffer(buffer, size); m_savedBuffer.resize(size); for (uint32_t i = 0; i < size; ++i) { m_savedBuffer[i] = buffer[i]->clone(); } sync->releaseSyncBuffer();
On the client you can then apply this buffer:
sync->applySyncBuffer(tkFramework, m_savedBuffer.data(), m_savedBuffer.size(), group, pxManager);
ExtPxManager is required only if sync buffer contains ExtSyncEventType::Physics events.