抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

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);
};

// Broadphase use Axis test
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() };
}

评论