Comment on page
PhysX
PhysX is a useful library to represent entities (known as actors in PhysX) in 3D worlds, attaching to them various shapes, types of materials, handle collisions, etc.
Simulate allows the library to be used in a distributed way. It handles PhysX serialization when entities move between Simulate cells on the same and different machines. Therefore, only exposing the software developer to standard PhysX programming practice.
Prerequisites
Simulate supports version 4.1.0 of PhysX (refer to PhysX documentation). You must include the following in
simulate.hh
#include <PxPhysicsAPI.h>
#include <aether/physx/physx.hh>
Simulate's PhysX integration deals with managing the per-PhysX instance state, the per-entity/actor state and the complex serialization. The current API is that you include a
c_physx
component on your entity, call physx->add_actor(*actor)
to connect an actor and call physx->add_to_simulation()
to add the actor to the simulation. You create actors as you normally would in PhysX. The one gotcha to be careful of is that we do not yet support sharing of shapes, materials or other things between actors (you may get a segfault if you do share). Every actor must have at least a unique shape and material created for it.Cell initialization can be defined as follows (please note that the code uses ECS
physx_update_system
, but coding in non-ECS way is also allowed):void user_cell_state_impl::initialise_cell(const aether_state_type &aether_state) {
store.user_data = std::make_unique<aether::physx::physx_state>(aether::physx::physx_state::basic_scene(new event_callback(store)));
store.add_system<physx_update_system>();
// ...
}
In order to access the
physx_state
through the user_data
field of the ECS, you need to configure the ECS, like so:using user_cell_state = aether::ecs::ecs<octree_traits, component_types, std::unique_ptr<aether::physx::physx_state>>;
event_callback
is used to handle events from PhysX, e.g. onTrigger, onContact, onConstraintBreak, onSleep, onWake. event_callback
should inherit from physx::PxSimulationEventCallback
, and override the method you care about, such as onContact
in the tutorial. This allows you to get a callback when two PhysX objects come into contact.Cell deinitialization would be defined similarly. In this case, the state is properly destructed by the destructor of
unique_ptr
and aether::physx::physx_state
.initialise_world
would contain the initial world definition:void user_cell_state_impl::initialise_world(const aether_state_type &aether_state) {
aether::physx::physx_state *physx_state = store.user_data.get();
// ...
}
physx_update_system
ECS system needs to be defined by the user in the following way (see Game Logic and the ECS ):struct physx_update_system {
using accessed_components = std::tuple<c_physx>;
using ecs_type = aether::constrained_ecs<user_cell_state, accessed_components>;
void operator()(const aether_cell_state<octree_traits> &aether_state, ecs_type &store, float delta_time) {
aether::physx::physx_state *physx_state = store.user_data.get();
physx_state->scene->simulate(delta_time);
physx_state->scene->fetchResults(true);
// ...
}
};
New PhysX based entities can be created as follows using standard PhysX SDK functionalities mixed with Simulate ECS:
for (size_t i = 0; i < num_boxes; i++) {
physx::PxMaterial* material = physx_state->physics->createMaterial(0.5f, 0.5f, 1.0f);
physx::PxShape* shape = physx_state->physics->createShape(physx::PxSphereGeometry(halfExtent), *material);
vec3f position = vec3f{generate_random_f32(), generate_random_f32(), generate_random_f32()} * 64.0f;
vec3f velocity = vec3f::uniform_unit() * 20.0f;
PxTransform transform(PxVec3{position.x, position.y, position.z});
physx::PxRigidDynamic* actor = physx_state->physics->createRigidDynamic(transform);
actor->attachShape(*shape);
physx::PxRigidBodyExt::updateMassAndInertia(*actor, 10.0f);
actor->setLinearVelocity(PxVec3{velocity.x, velocity.y, velocity.z});
auto entity = update.new_entity_local();
auto physx = entity.create_component<c_physx>();
physx->add_actor(*actor);
physx->add_to_simulation();
auto trivial = entity.create_component<c_trivial>();
trivial->id = generate_random_u64();
material->release();
shape->release();
}