【Bullet随笔】01_HelloBullet

1. 编译bullet

修改配置:

2. 初始化物理世界

2.1 基本概念

1. btDefaultCollisionConfiguration

  • 用途:这是 Bullet 物理引擎中用于配置碰撞检测系统的默认设置类。它负责初始化和配置碰撞检测所需的各种算法和数据结构。
  • 功能:它提供了碰撞算法的默认实现,可以根据不同类型的碰撞对象(如凸体、网格)选择合适的算法。它还管理着用于碰撞检测过程中的内存分配。

2. btCollisionDispatcher

  • 用途:这是一个碰撞分派器,用于管理和分配物体间的碰撞检测任务。
  • 功能:当两个物体可能发生碰撞时,碰撞分派器确定是否需要进行碰撞检测,以及使用哪种碰撞检测算法。它依据物体的形状和碰撞配置来决定如何处理这些潜在的碰撞(依据包围盒)。

3. btBroadphaseInterface

  • 用途:这是一个用于初步筛选碰撞对的接口,用于快速剔除那些不可能相互碰撞的物体。
  • 功能:通过空间分割和快速检测方法(如AABB测试),该接口能够高效地缩小需要进行详细碰撞检测的物体对的数量。这极大地提高了整体的碰撞检测效率。

4. btSequentialImpulseConstraintSolver

  • 用途:这是一个求解器,用于处理刚体间的约束和碰撞响应。
  • 功能:它使用迭代方法来解决刚体之间的约束,如铰链、滑轮或接触约束。这个求解器计算出所需的力和冲量,以保持物体间的约束条件并适当地响应碰撞。

5. btCollisionWorld

  • 用途:这是一个包含所有参与碰撞检测物体的容器。
  • 功能:它负责组织和执行碰撞检测,但不处理物体的动力学(如力和运动)。这使得它适用于那些只需进行碰撞检测而无需物理模拟的场景。

6. btDiscreteDynamicsWorld

  • 用途:这是 Bullet 中最常用的动力学世界类型,它既处理刚体的碰撞也处理它们的动力学。
  • 功能:除了执行碰撞检测之外,这个世界还管理物体的运动,处理力的作用、质量、摩擦等物理属性。这使得它成为模拟真实世界物理行为(如在游戏和模拟中)的理想选择。

2.2 初始化碰撞世界

// 碰撞配置
btDefaultCollisionConfiguration* pCollisionConfig = new btDefaultCollisionConfiguration();

// 分派器
btCollisionDispatcher* pDispatcher = new btCollisionDispatcher(pCollisionConfig);

// 粗侧接口
btBroadphaseInterface* pBroadphase = new btDbvtBroadphase();

// 注册GImpact算法
btGImpactCollisionAlgorithm::registerAlgorithm(pDispatcher);

// 初始化碰撞世界
btCollisionWorld* pCollisionWorld = new btCollisionWorld(pDispatcher, pBroadphase, pCollisionConfig);

2.3 初始化动力学世界

// 碰撞配置
btDefaultCollisionConfiguration* pCollisionConfig = new btDefaultCollisionConfiguration();

// 分派器
btCollisionDispatcher* pDispatcher = new btCollisionDispatcher(pCollisionConfig);

// 设置世界的空间大小,限定刚体运动的空间范围
btVector3 worldAabbMin(-10000, -10000, -10000);
btVector3 worldAabbMax(10000, 10000, 10000);
// 设置最大刚体数
int maxProxies = 1024;
// 粗侧接口
btBroadphaseInterface* pBroadphase = new btAxisSweep3(worldAabbMin, worldAabbMax, maxProxies);

// 求解器
btSequentialImpulseConstraintSolver* solver = new btSequentialImpulseConstraintSolver();

// 注册GImpact算法
btGImpactCollisionAlgorithm::registerAlgorithm(pDispatcher);

// 初始化碰撞世界
btCollisionWorld* pCollisionWorld = new btCollisionWorld(pDispatcher, pBroadphase, pCollisionConfig);

3. 碰撞形体

3.1 btCollisionShape

1. 用途

  • btCollisionShape 是 Bullet 中所有碰撞形状的基类。它定义了物体在物理世界中的几何形状,这是进行碰撞检测的基础。

2. 特点

  • 形状多样:支持多种类型的形状,包括球体(btSphereShape)、立方体(btBoxShape)、圆柱体(btCylinderShape)、锥体(btConeShape)和更复杂的网格形状(btConvexHullShapebtBvhTriangleMeshShape等)。
  • 可组合:可以通过 btCompoundShape 将多个简单形状组合成一个复杂的形状,以适应更复杂的物体。
  • 用途广泛:被用于定义静态和动态物体的几何形状,以进行精确的碰撞检测和物理模拟。

3.2 创建立方体Mesh

btTriangleMesh* CreateBoxMesh(double halfExtents)
{
	btTriangleMesh* pBoxMesh = new btTriangleMesh();

	//       7----------------6
	//      /|                |
	//     / 4----------------5
	//    / /                /
	//   3 /                / <- 2 (hidden)
	//   |/                /
	//   0----------------1

	// right x | up y | front z 

	btVector3 p0 = btVector3(-halfExtents, -halfExtents,  halfExtents);
	btVector3 p1 = btVector3( halfExtents, -halfExtents,  halfExtents);
	btVector3 p2 = btVector3( halfExtents,  halfExtents,  halfExtents);
	btVector3 p3 = btVector3(-halfExtents,  halfExtents,  halfExtents);

	btVector3 p4 = btVector3(-halfExtents, -halfExtents, -halfExtents);
	btVector3 p5 = btVector3( halfExtents, -halfExtents, -halfExtents);
	btVector3 p6 = btVector3( halfExtents,  halfExtents, -halfExtents);
	btVector3 p7 = btVector3(-halfExtents,  halfExtents, -halfExtents);

	// front
	pBoxMesh->addTriangle(p0, p1, p2);
	pBoxMesh->addTriangle(p0, p2, p3);

	// back
	pBoxMesh->addTriangle(p4, p5, p6);
	pBoxMesh->addTriangle(p4, p6, p7);

	// right
	pBoxMesh->addTriangle(p1, p5, p6);
	pBoxMesh->addTriangle(p1, p6, p2);

	// left
	pBoxMesh->addTriangle(p0, p4, p7);
	pBoxMesh->addTriangle(p0, p7, p3);

	// top
	pBoxMesh->addTriangle(p3, p2, p6);
	pBoxMesh->addTriangle(p3, p6, p7);

	// bottom
	pBoxMesh->addTriangle(p0, p1, p5);
	pBoxMesh->addTriangle(p0, p5, p4);

	return pBoxMesh;
}

3.3 创建碰撞形体

btTriangleMesh* pBoxMesh = CreateBoxMesh(1.0);

// 形体 01
btGImpactMeshShape* gImpactShape01 = new btGImpactMeshShape(pBoxMesh);
gImpactShape01->updateBound();

// 形体 02
btGImpactMeshShape* gImpactShape02 = new btGImpactMeshShape(pBoxMesh);
gImpactShape02->updateBound();

4. 碰撞对象

4.1 btCollisionObject (碰撞对象)

4.1.1 基本概念

1. 定义与用途

  • btCollisionObject 是一个更通用的类,用于表示任何可以参与碰撞检测的物体。它是 btRigidBody 和其他碰撞对象类的基类。

2. 主要特征

  • 碰撞形状关联:同样与 btCollisionShape 关联,定义物体的碰撞边界。
  • 灵活性:可以表示不仅仅是动态物体,也包括静态物体、触发器、感应区等。
  • 状态和属性:存储有关物体的碰撞相关信息,如是否参与物理反应、摩擦系数、弹性系数等。

4.1.2 初始化

// 创建姿态
btTransform startTransform01;
startTransform01.setIdentity();
startTransform01.setOrigin(btVector3(0., 0., 0.));

btTransform startTransform02;
startTransform02.setIdentity();
startTransform02.setOrigin(btVector3(1., 0., 0.));

// 创建碰撞对象
btCollisionObject* btMeshObject01 = new btCollisionObject();
btMeshObject01->setCollisionShape(gImpactShape01);
btMeshObject01->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT);
btMeshObject01->setWorldTransform(startTransform01);

btCollisionObject* btMeshObject02 = new btCollisionObject();
btMeshObject02->setCollisionShape(gImpactShape02);
btMeshObject02->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT);
btMeshObject02->setWorldTransform(startTransform02);

// 将碰撞对象加入世界
pCollisionWorld->addCollisionObject(btMeshObject01);
pCollisionWorld->addCollisionObject(btMeshObject02);

4.2 btRigidBody (刚体)

4.2.1 基本概念

1. 定义与用途

  • btRigidBody 是表示动态物体的类,用于模拟具有质量和力学属性的物体。它是实现物理模拟中最常见的对象类型,如移动的车辆、掉落的物体等。

2. 主要特征

  • 动力学属性:包括质量、惯性、速度(线性和角速度)等,这些属性影响物体的运动方式。
  • 碰撞形状:与一个或多个 btCollisionShape 对象关联,这些形状定义了物体的碰撞边界。
  • 运动和交互:可以响应力和扭矩,与其他物体发生碰撞,以及受到如重力等外部影响。
  • 状态控制:可以设置为动态(可移动)或静态(不动的,如墙壁或地面)。

4.2.2 初始化

// 创建姿态
btTransform startTransform01;
startTransform01.setIdentity();
startTransform01.setOrigin(btVector3(0., 0., 0.));

btTransform startTransform02;
startTransform02.setIdentity();
startTransform02.setOrigin(btVector3(1., 0., 0.));

// 创建刚体
btScalar mass(1.f);
bool isDynamic = (mass != 0.f);

btVector3 localInertia(0, 0, 0);
if (isDynamic) gImpactShape01->calculateLocalInertia(mass, localInertia);
btDefaultMotionState* pMotionState01 = new btDefaultMotionState(startTransform01);
btRigidBody::btRigidBodyConstructionInfo rbInfo01 = btRigidBody::btRigidBodyConstructionInfo(mass, myMotionState, colShape, localInertia);
btRigidBody* pRigidBody01 = new btRigidBody(rbInfo01);

btVector3 localInertia(0, 0, 0);
if (isDynamic) gImpactShape02->calculateLocalInertia(mass, localInertia);
btDefaultMotionState* pMotionState02 = new btDefaultMotionState(startTransform02);
btRigidBody::btRigidBodyConstructionInfo rbInfo02 = btRigidBody::btRigidBodyConstructionInfo(mass, myMotionState, colShape, localInertia);
btRigidBody* pRigidBody02 = new btRigidBody(rbInfo02);

// 将碰撞对象加入世界
pCollisionWorld->addCollisionObject(pRigidBody01);
pCollisionWorld->addCollisionObject(pRigidBody02);

5. 碰撞检测

5.1 关键步骤

1. 精测阶段(Broadphase Detection)

  • 目的:快速识别可能发生碰撞的物体对,以减少需要进行详细碰撞检测的物体数量。
  • 方法:通常使用空间分割技术,如轴对齐包围盒(AABB)来快速筛选。在此阶段,只确定物体是否足够接近以致可能发生碰撞。

2. 粗侧阶段(Narrowphase Detection)

  • 目的:在粗侧阶段确定的潜在碰撞对中进行详细的碰撞检测。
  • 方法:计算精确的碰撞点、碰撞法线和穿透深度。这一步使用更精确的几何计算来确定物体是否真正相交,并在哪里相交。

3. 碰撞分派(Collision Dispatch)

  • 目的:处理碰撞对,并决定对于每对碰撞物体使用哪种碰撞检测算法。
  • 方法:根据物体的类型(如凸体、凹体、网格等)和碰撞形状,选择适当的碰撞算法。

4. 碰撞解算(Collision Resolution)

  • 目的:计算碰撞的物理响应,如力、冲量的变化。
  • 方法:这通常包括计算应用在物体上的反作用力和扭矩,以防止物体相互穿透,并模拟逼真的物理交互。

5. 集成到物理世界(Integration into the Physics World)

  • 目的:将碰撞检测的结果应用到物理世界的状态更新中。
  • 方法:根据碰撞解算的结果更新物体的位置、速度等状态。这可能包括处理约束和模拟物体的动力学行为。

6. 约束解算(Constraint Solving)

  • 目的:如果有的话,解决物体间的约束条件。
  • 方法:处理诸如铰链、滑轮、固定连接等约束,确保这些约束在物理世界中得到适当的维护。

5.2 代码示例

1. 碰撞世界

pCollisionWorld->performDiscreteCollisionDetection();

2. 动态世界

btScalar deltaTime = 1.f / 60.f;
int maxSubSteps = 10;
dynamicsWorld->stepSimulation(deltaTime, maxSubSteps);

5.3 碰撞世界与动态世界碰撞检测的区别

1. btCollisionWorld

  • btCollisionWorld 是 Bullet 物理引擎中处理碰撞检测的基础类。
  • 它提供了一个通用的环境,用于检测和记录物体之间的碰撞。
  • performDiscreteCollisionDetection() 方法在这个环境中执行碰撞检测,但不处理物体的运动或者动力学响应。它仅仅检测物体在特定时刻的碰撞状态。

2. btDiscreteDynamicsWorld

  • btDiscreteDynamicsWorldbtCollisionWorld 的一个子类,它不仅处理碰撞检测,还处理物理模拟中的动力学方面。
  • 这包括物体的运动、力的应用、刚体之间的互动等。
  • btDiscreteDynamicsWorld 的上下文中,performDiscreteCollisionDetection() 方法不仅执行碰撞检测,还可能涉及碰撞的结果如何影响物体的动力学。例如,当两个物体碰撞时,它们可能会根据物理定律改变速度或方向。

6. 内存管理

#define SAFE_DELETE_PTR(ptr) if(ptr){delete ptr; ptr = nullptr;};

6.1 释放碰撞形体

碰撞形体需要在最后手动释放。

1. 保存形体的指针

// 保存shape
std::vector<btCollisionShape*> shapesCache;
shapesCache.emplace_back(gImpactShape01);
shapesCache.emplace_back(gImpactShape02);

2. 在结束时进行释放

// 释放 Shape
for (auto pShape : shapesCache)
{
	SAFE_DELETE_PTR(pShape);
}

6.2 释放碰撞对象

// 释放 World 中的 Object
// 从后往前析构,避免未知错误,例如越界或者遗漏一些元素。
for (int idx = pCollisionWorld->getNumCollisionObjects() - 1; idx >= 0; idx--)
{
	btCollisionObject* obj = pCollisionWorld->getCollisionObjectArray()[idx];
	
	// 若为刚体,还需要释放内部的 btMotionState
	btRigidBody* body = btRigidBody::upcast(obj);
	if (body && body->getMotionState())
	{
		btMotionState* tempMotionState = body->getMotionState();
		SAFE_DELETE_PTR(tempMotionState);
	}

	pCollisionWorld->removeCollisionObject(obj);
	SAFE_DELETE_PTR(obj);
}

6.3 释放世界环境

碰撞世界必须首先进行释放,否则会报错。

SAFE_DELETE_PTR(pCollisionWorld);
SAFE_DELETE_PTR(pCollisionConfig);
SAFE_DELETE_PTR(pDispatcher);
SAFE_DELETE_PTR(pBroadphase);
  • 16
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值