Skip to content

Getting Started with Physics

This guide demonstrates adding physics simulation to entities using the Astralix physics module powered by PhysX.

Creating Dynamic Objects

Add physics to a falling box:

cpp
#include <astralix/physics.hpp>

// Create entity
EntityID box = entity_manager().create_entity();

// Add transform
auto& transform = box->add_component<TransformComponent>();
transform.position = glm::vec3(0, 10, 0);
transform.rotation = glm::quat(1, 0, 0, 0);
transform.scale = glm::vec3(1, 1, 1);

// Add rigid body (dynamic) with parameters: rigid_type, gravity, velocity, acceleration, drag, mass
auto& rb = box->add_component<RigidBodyComponent>(
    RigidType::Dynamic,  // rigid_type
    0.5f,                // gravity
    2.0f,                // velocity
    2.0f,                // acceleration
    0.0f,                // drag
    1.0f                 // mass (note: currently hardcoded to 10.0f in implementation)
);

// Add mesh collision (creates AABB box from mesh bounds)
auto& collision = box->add_component<MeshCollisionComponent>();
// Vertices will be populated from mesh data

Creating Static Colliders

Create a static ground plane:

cpp
EntityID ground = entity_manager().create_entity();

auto& transform = ground->add_component<TransformComponent>();
transform.position = glm::vec3(0, 0, 0);

// Add rigid body (static) - only rigid_type parameter is required for static bodies
auto& rb = ground->add_component<RigidBodyComponent>(
    RigidType::Static  // rigid_type
);

// Add mesh collision component
auto& collision = ground->add_component<MeshCollisionComponent>();
// Collision shape is automatically generated from mesh bounds

Physics Simulation Control

The physics simulation can be toggled on and off:

cpp
// Physics simulation is off by default
// Press F4 to toggle simulation on/off

// The simulation state is controlled internally by the PhysicsSystem
// When enabled, it runs at a fixed timestep during fixed_update()

Note: Direct force/impulse application API is not currently exposed. Physics updates are handled automatically by the PhysicsSystem based on component properties.

Collision Detection

The physics module provides GJK-based collision detection through MeshCollisionComponent:

cpp
// Get collision components
auto* collision_a = entity_a->get_component<MeshCollisionComponent>();
auto* collision_b = entity_b->get_component<MeshCollisionComponent>();

// Check AABB intersection (fast broad-phase)
if (collision_a->aabb_intersect(collision_b)) {
    // Check precise collision using GJK algorithm
    if (collision_a->has_intersect(collision_b)) {
        // Entities are colliding
        std::cout << "Collision detected!" << std::endl;
    }
}

Note: Raycasting API is not currently implemented. Collision detection uses the GJK (Gilbert-Johnson-Keerthi) algorithm with AABB broad-phase.

Transform Synchronization

The PhysicsSystem automatically synchronizes between TransformComponent and PhysX actors:

cpp
// TransformComponent changes are synced to PhysX actors in pre_update()
auto& transform = entity->get_component<TransformComponent>();
transform.position = glm::vec3(10, 5, 0);
transform.rotation = glm::quat(1, 0, 0, 0);

// After simulation, PhysX results are synced back to TransformComponent in fixed_update()
// The system uses a dirty flag to avoid unnecessary updates

Note: Character controller and ground detection are not currently implemented. Direct impulse/force APIs are not exposed.

PhysX Visual Debugger (PVD)

The PhysicsSystem supports PhysX Visual Debugger for real-time simulation inspection:

cpp
// Configure PVD connection in PhysicsSystemConfig
PhysicsSystemConfig config;
config.pvd_host = "127.0.0.1";
config.pvd_port = 5425;
config.pvd_timeout = 10;

// PVD connection is established during PhysicsSystem initialization
// Connect with PhysX Visual Debugger tool to inspect simulation state

Note: Collision callbacks (OnCollisionEnter/Exit, OnTriggerEnter/Exit) are not currently implemented.

Math Type Conversions

The physics module provides conversion utilities between GLM and PhysX types:

cpp
#include <astralix/physics/utils/math.hpp>

// GLM to PhysX
glm::vec3 glm_position(1.0f, 2.0f, 3.0f);
physx::PxVec3 px_position = GlmVec3ToPxVec3(glm_position);

glm::quat glm_rotation(1.0f, 0.0f, 0.0f, 0.0f);
physx::PxQuat px_rotation = GlmQuatToPxQuat(glm_rotation);

glm::mat4 glm_transform(1.0f);
physx::PxMat44 px_transform = GlmMat4ToPxMat44(glm_transform);

// PhysX to GLM
glm::mat4 result_transform = PxMat44ToGlmMat4(px_transform);
glm::quat result_rotation = PxQuatToGlmQuat(px_rotation);

Physics System Configuration

Configure the physics system via PhysicsSystemConfig:

cpp
PhysicsSystemConfig config;

// Backend selection (e.g., "PhysX")
config.backend = "PhysX";

// Gravity vector
config.gravity = glm::vec3(0, -9.81f, 0);

// PhysX Visual Debugger settings
config.pvd_host = "127.0.0.1";
config.pvd_port = 5425;
config.pvd_timeout = 10;

// Create physics system with config
auto physics_system = PhysicsSystem(config);

Implementation details:

  • CPU dispatcher uses 2 threads (hardcoded)
  • Default material properties: 0.5 static friction, 0.5 dynamic friction, 0.6 restitution
  • Simulation is off by default; toggle with F4 key

Collision Shape Details

MeshCollisionComponent creates axis-aligned bounding box (AABB) collision shapes:

cpp
// Add mesh collision component
auto& collision = entity->add_component<MeshCollisionComponent>();

// Populate vertices from mesh data
collision.vertices = mesh->get_vertices();

// The component will:
// 1. Calculate AABB from vertices
// 2. Create PhysX box geometry from bounds
// 3. Attach shape to rigid body with material properties

Current limitations:

  • Only box collision shapes are supported (generated from mesh AABB)
  • No sphere, capsule, or custom mesh colliders
  • Trigger volumes are not implemented

Component Serialization

Both physics components support serialization:

cpp
#include <astralix/physics/components/rigidbody/serializers/rigidbody-component-serializer.hpp>
#include <astralix/physics/components/mesh-collision/serializers/mesh-collision-component-serializer.hpp>

// Create serializers
auto rb_serializer = RigidBodyComponentSerializer(rigidbody_component);
auto collision_serializer = MeshCollisionComponentSerializer(mesh_collision_component);

// Serialize components
rb_serializer.serialize();
collision_serializer.serialize();

// Deserialize components
rb_serializer.deserialize();
collision_serializer.deserialize();

Note: Serializer implementations are currently stubs with empty deserialize() methods.

Known Issues

  • Mass parameter ignored: RigidBodyComponent constructor accepts a mass parameter, but the implementation hardcodes 10.0f when calling PxRigidBodyExt::updateMassAndInertia()
  • AABB bug: The aabb_intersect() logic appears inverted (returns false on intersection, true on no intersection)
  • Commented gravity: RigidBodyComponent::update() has gravity application code commented out

Next Steps