Jolt Physics
最近给小引擎接入了刚体物理系统,发现这个东西真的很简单,在此记录一下
关于物理系统
主流的物理系统接口都很相似,而且制作的非常完善,像刚体物理这种比较基础的模块,接起来十分简单
目前大多数物理引擎,还是在CPU多线程模拟,英伟达有一套基于GPU的,但没有开源
我接入的是Jolt Physics,是一个非常轻量级的物理系统
cmake
代码拉取
https://github.com/jrouwe/JoltPhysics.git
构建(动态库)
if(NOT TARGET JoltPhysics) set(BUILD_SHARED_LIBS ON) add_subdirectory(JoltPhysics/Build) set_property(TARGET Jolt PROPERTY FOLDER "ThirdParty") endif()
|
链接
target_link_libraries(Engine PUBLIC Jolt)
|
简单的刚体物理
初始化
JPH::RegisterDefaultAllocator(); JPH::Trace = PhysicsManager::TraceImpl; JPH::AssertFailed = PhysicsManager::AssertFailedImpl; JPH::Factory::sInstance = new JPH::Factory(); JPH::RegisterTypes(); m_temp_allocator = new JPH::TempAllocatorImpl(10 * 1024 * 1024); m_job_system = new JPH::JobSystemThreadPool(m_max_job_count, m_max_barrier_count, m_max_concurrent_job_count); m_physics_system = new JPH::PhysicsSystem(); m_physics_system->Init(m_max_body_count, m_max_body_count, m_max_body_pairs, m_max_contact_constraints, layer_interface, ob_layer_filter, oo_layer_filter);
|
添加监听
body_activation_listener = new MyBodyActivationListener(); m_physics_system->SetBodyActivationListener(body_activation_listener); contact_listener = new MyContactListener(); m_physics_system->SetContactListener(contact_listener);
|
设置重力方向(默认是y轴,我的小引擎是z轴朝上)
JPH::Vec3 m_gravity{ 0.f, 0.f, -9.8f }; m_physics_system->SetGravity(m_gravity);
|
监听
class MyContactListener : public JPH::ContactListener { public: virtual JPH::ValidateResult OnContactValidate(const JPH::Body& inBody1, const JPH::Body& inBody2, JPH::RVec3Arg inBaseOffset, const JPH::CollideShapeResult& inCollisionResult) override; virtual void OnContactAdded(const JPH::Body& inBody1, const JPH::Body& inBody2, const JPH::ContactManifold& inManifold, JPH::ContactSettings& ioSettings) override; virtual void OnContactPersisted(const JPH::Body& inBody1, const JPH::Body& inBody2, const JPH::ContactManifold& inManifold, JPH::ContactSettings& ioSettings) override; virtual void OnContactRemoved(const JPH::SubShapeIDPair& inSubShapePair) override; };
class MyBodyActivationListener : public JPH::BodyActivationListener { virtual void OnBodyActivated(const JPH::BodyID& inBodyID, uint64_t inBodyUserData) override; virtual void OnBodyDeactivated(const JPH::BodyID& inBodyID, uint64_t inBodyUserData) override; };
|
Interface
物理系统有一个粗粒度的碰撞检测和逐物体的精细检测
粗粒度的原理是根据坐标轴简单判断,叫BroadPhase
namespace Layers { static constexpr JPH::ObjectLayer NON_MOVING = 0; static constexpr JPH::ObjectLayer MOVING = 1; static constexpr JPH::ObjectLayer NUM_LAYERS = 2; }; namespace BroadPhaseLayers { static constexpr JPH::BroadPhaseLayer NON_MOVING(0); static constexpr JPH::BroadPhaseLayer MOVING(1); static constexpr unsigned int NUM_LAYERS(2); };
class BPLayerInterfaceImpl final : public JPH::BroadPhaseLayerInterface { public: BPLayerInterfaceImpl(); virtual unsigned int GetNumBroadPhaseLayers() const override; virtual JPH::BroadPhaseLayer GetBroadPhaseLayer(JPH::ObjectLayer inLayer) const override; virtual const char* GetBroadPhaseLayerName(JPH::BroadPhaseLayer inLayer) const override; private: JPH::BroadPhaseLayer m_object_to_broad_phase[Layers::NUM_LAYERS]; };
class ObjectVsBroadPhaseLayerFilterImpl : public JPH::ObjectVsBroadPhaseLayerFilter { public: virtual bool ShouldCollide(JPH::ObjectLayer inLayer1, JPH::BroadPhaseLayer inLayer2) const override; };
class ObjectLayerPairFilterImpl : public JPH::ObjectLayerPairFilter { public: virtual bool ShouldCollide(JPH::ObjectLayer inObject1, JPH::ObjectLayer inObject2) const override; };
|
构建物理场景
添加静态的Box和动态的Sphere
JPH::BodyInterface& body_interface = m_physics_system->GetBodyInterface(); for (uint32_t i = 0; i < scene.go_id_list.size(); i++) { uint32_t go_id = scene.go_id_list[i]; Bounding& bounding = scene.bounding_list[i]; if (bounding.type == BoundingType::Box) { JPH::BoxShapeSettings floor_shape_settings(JPH::Vec3(bounding.data[0], bounding.data[1], bounding.data[2])); JPH::ShapeSettings::ShapeResult floor_shape_result = floor_shape_settings.Create(); JPH::ShapeRefC floor_shape = floor_shape_result.Get(); JPH::BodyCreationSettings floor_settings(floor_shape, JPH::RVec3(bounding.position[0], bounding.position[1], bounding.position[2]), JPH::Quat::sIdentity(), JPH::EMotionType::Static, Layers::NON_MOVING); JPH::Body* box = body_interface.CreateBody(floor_settings); body_interface.AddBody(box->GetID(), JPH::EActivation::DontActivate); m_go_id_to_body_id[go_id] = box->GetID(); } else if (bounding.type == BoundingType::Sphere) { JPH::BodyCreationSettings sphere_settings(new JPH::SphereShape(bounding.data[0]), JPH::RVec3(bounding.position[0], bounding.position[1], bounding.position[2]), JPH::Quat::sIdentity(), JPH::EMotionType::Dynamic, Layers::MOVING); JPH::BodyID sphere_id = body_interface.CreateAndAddBody(sphere_settings, JPH::EActivation::Activate); m_go_id_to_body_id[go_id] = sphere_id; } }
m_physics_system->OptimizeBroadPhase();
|
模拟
void PhysicsManager::tick() { float dt = Time::getInstance().getDeltaTime(); m_physics_system->Update(dt, 1, m_temp_allocator, m_job_system); JPH::BodyInterface& body_interface = m_physics_system->GetBodyInterface(); JPH::RVec3 position = body_interface.GetCenterOfMassPosition(m_go_id_to_body_id[1]); m_scene.mesh_transform_list[1].position = { position.GetX(), position.GetY(), position.GetZ() }; }
|