之前试了一下Bullet3物理引擎,但在linux上编译失败,于是放弃了。令我不满的还有另外一个原因,下载的发行包竟然有500M。C++的Bullet3代码根本用不了,大部分教程实际都是用的老版本。而且此项目还整了python版本,各种蹭人工智能的热度,感觉后面的维护者越来越不靠谱了。
于是我准备换用ode引擎,下面对bullet3的简单使用记录一下。
一、配置
# bullet3
# 3实际上没有教程,似乎已经弃坑(这里使用2的版本)
# https://github.com/bulletphysics/bullet3/issues/4002
include_directories(${CMAKE_SOURCE_DIR}/third/bullet3/src)
target_link_libraries(${PROJECT_NAME} PRIVATE LinearMath)
target_link_libraries(${PROJECT_NAME} PRIVATE BulletCollision)
target_link_libraries(${PROJECT_NAME} PRIVATE BulletDynamics)
在CMakePresets.json里需要加入以下变量到cacheVariables,关闭其他东西的构建:
"BUILD_EXTRAS": false,
"BUILD_UNIT_TESTS": false
二、使用
/**
* @file dl_physics.h
* @brief 3d物理,基于Bullet3
*
*
* @version 1.0
* @author lveyou
* @date 22-10-28
*
* @note
*/
#pragma once
#include <vector>
#include <btBulletDynamicsCommon.h>
#include "dl_type.h"
#include "math/dl_transform.h"
#include "dl_time.h"
#include "dl_rigid_body.h"
//Extras / BulletMultiThreaded 拥有多线程版本 碰撞调度和 解算器
namespace dl
{
inline btVector3 toBtVector3(const Position3& v)
{
return btVector3(v[0], v[1], v[2]);
}
class RigidBodyImp
{
public:
btRigidBody* _rigidBody;
btMotionState* _motion;//运动状态,可选 动态物体才有
size_t _idShape;//形状id
};
class Physics
{
public:
btDefaultCollisionConfiguration* _collConfig;//碰撞配置
btCollisionDispatcher* _collDispatcher;//碰撞调度
btBroadphaseInterface* _broadphase;//broad-phase
btSequentialImpulseConstraintSolver* _solver;//解算器
btDiscreteDynamicsWorld* _world;//世界
std::vector<btCollisionShape*> _allShape;//所有形状
Physics()
{
_collConfig = new btDefaultCollisionConfiguration;
_collDispatcher = new btCollisionDispatcher(_collConfig);
_broadphase = new btDbvtBroadphase;
_solver = new btSequentialImpulseConstraintSolver;
_world = new btDiscreteDynamicsWorld(_collDispatcher, _broadphase, _solver, _collConfig);
_world->setGravity(btVector3(0, 0, -Numbers::GRAVITY));
btCollisionShape* shape = new btBoxShape(
btVector3(1, 1, 1));
_allShape.push_back(shape);
}
/**
* @brief 创建刚体
* @param[in] shape_id 形状id
* @param[in] trans 变换
* @param[in] mass 质量
* @retval 失败返回nullptr
*/
RigidBody* CreateRigidBody(size_t shape_id, Transform* trans, Float mass)
{
if (shape_id >= _allShape.size())
{
log_err0("shape id越界!");
return nullptr;
}
RigidBody* ret = new RigidBody;
RigidBodyImp* body = ret->GetImp();
//形状
body->_idShape = shape_id;
btCollisionShape* shape = _allShape[shape_id];
//运动状态
btTransform bt_trans;
bt_trans.setIdentity();
Position3 pos = trans->GetTranslation();
bt_trans.setOrigin(toBtVector3(pos));
body->_motion = new btDefaultMotionState(bt_trans);
//质量和惯性
btScalar bt_mass{ mass };
btVector3 local_inertia(0, 0, 0);
if (bt_mass)
shape->calculateLocalInertia(bt_mass, local_inertia);
//创建刚体
body->_rigidBody = new btRigidBody(bt_mass, body->_motion, shape);
//加入世界
_world->addRigidBody(body->_rigidBody);
return ret;
}
//! 创建默认刚体
RigidBody* CreateRigidBodyDefault(Transform* trans)
{
return CreateRigidBody(0, trans, 1);
}
//! 创建形状 box
size_t CreateShapeBox(const Position3& box)
{
size_t id = _allShape.size();
btCollisionShape* shape = new btBoxShape(toBtVector3(box));
_allShape.push_back(shape);
return id;
}
void Update()
{
_world->stepSimulation(g_time->GetDelta());
//更新位置
/*for (int j = _world->getNumCollisionObjects() - 1; j >= 0; j--)
{
btCollisionObject* obj = _world->getCollisionObjectArray()[j];
btRigidBody* body = btRigidBody::upcast(obj);
btTransform trans;
if (body && body->getMotionState())
{
body->getMotionState()->getWorldTransform(trans);
}
else
{
trans = obj->getWorldTransform();
}
trans.getOpenGLMatrix()
printf("world pos object %d = %f,%f,%f\n", j, float(trans.getOrigin().getX()), float(trans.getOrigin().getY()), float(trans.getOrigin().getZ()));
}*/
}
void UpdateRigidBody(RigidBodyImp* body, Transform* trans)
{
btTransform bt_trans;
btRigidBody* bt_body = body->_rigidBody;
if (bt_body->getMotionState())
{
bt_body->getMotionState()->getWorldTransform(bt_trans);
}
else
{
bt_trans = bt_body->getWorldTransform();
}
const btVector3& pos = bt_trans.getOrigin();
trans->SetTranslation({pos.getX(), pos.getY(), pos.getZ()});
}
~Physics()
{
//反向删除
for (int i = _world->getNumCollisionObjects() - 1; i >= 0; --i)
{
btCollisionObject* obj = _world->getCollisionObjectArray()[i];
btRigidBody* body = btRigidBody::upcast(obj);
if (body && body->getMotionState())
{
delete body->getMotionState();
}
_world->removeCollisionObject(obj);
delete obj;
}
for (auto& iter : _allShape)
{
delete iter;
}
delete _world;
delete _solver;
delete _broadphase;
delete _collDispatcher;
delete _collConfig;
}
};
extern Physics* g_physics;
}