【Bullet随笔】02_Bullet接触点

1. 碰撞检测概念

1. btCollisionDispatcher (碰撞分发器)

  • btCollisionDispatcher 的角色是识别哪些物体对可能会发生碰撞。它会遍历所有物体对,并使用各种算法(如 AABB 相交测试)来快速排除那些不可能相碰的对象。
  • btCollisionDispatcher 确定两个对象可能发生碰撞时,它会为这对对象创建一个 btPersistentManifold 实例。

2. btPersistentManifold (渗透流形)

  • btPersistentManifold 是一个存储关于两个碰撞物体间接触信息的容器。它不仅记录了是否发生碰撞,还记录了碰撞的具体细节,如接触点、正常和接触深度等。
  • 每个 btPersistentManifold 对象代表一对可能相互接触的物体。这些信息被用于碰撞响应计算,比如计算反作用力、摩擦力等。

3. btManifoldPoint (流形点)

  • btManifoldPointbtPersistentManifold 中的一个元素,代表单个接触点的数据。每个 btManifoldPoint 包含了接触点的位置、正常、接触深度以及其他有关该接触点的信息。
  • 在两个物体的碰撞检测过程中,可能会产生多个 btManifoldPoint ,每个都表示一个不同的接触点。

小结

  • btCollisionDispatcher 在 Bullet 物理引擎中负责识别可能的碰撞对;
  • btPersistentManifold 存储关于这些碰撞对的详细信息;
  • btManifoldPoint 则是 btPersistentManifold 中的元素,代表单一接触点的具体数据。

这三者共同工作,以精确地处理和响应物理世界中的碰撞事件。

2. 接触点 (Contact Point)

2.1 接触点 (Contact Point) 生成过程和规则

1. 碰撞检测 (Collision Detection)

  • 首先,物理引擎会执行碰撞检测步骤,以确定哪些物体之间可能发生了碰撞。这通常涉及对物体的包围盒(bounding boxes)或其他简化形状(如球体、胶囊体)进行快速检测。

2. 详细的几何计算 (Detailed Geometric Calculation)

  • 一旦判定两个物体可能发生碰撞,物理引擎会进行更详细的几何计算,以精确确定接触点。这包括计算物体的确切交叉区域,如接触点的位置、接触面的法线方向、接触深度等。

3. 接触点位置的确定 (Contact Point Position)

  • 接触点的具体位置通常是在两个物体表面上接触点的平均位置或对应点。这些位置是基于物体的几何形状和相对运动计算出来的。

4. 物理属性的评估 (Physical Properties Assessment)

  • 物理引擎还会考虑物体的物理属性,如弹性、摩擦系数等,来决定接触点的具体特性和碰撞响应。

5. 持续性和稳定性的处理 (Persistence and Stability Handling)

  • 在连续的物理模拟中,为了保持碰撞处理的稳定性和连续性,接触点可能会被持续跟踪和更新,即使物体的相对位置发生微小变化。

6. 优化和性能考虑 (Optimization and Performance Considerations)

  • 出于性能优化的考虑,物理引擎可能会限制每对碰撞物体所生成的接触点数量,以及在必要时合并或忽略一些接触点。

7. 特定物理引擎的算法 (Specific Physics Engine Algorithms)

  • 不同的物理引擎可能使用不同的算法和技术来生成和处理接触点。这些算法的选择和实现会影响接触点的生成方式和特性。

2.2 接触点 (Contact Point) 是一对点

1. btManifoldPoint 在 Bullet 物理引擎中通常代表两个碰撞物体之间的接触点,它实际上包含了代表一对接触点的信息。这对接触点分别位于两个碰撞物体的表面上,它们是物体间碰撞交互的直接接触位置。

2. 每个接触点通常表示两个碰撞物体表面上的相对应的位置。即使这两个点在物理空间中非常接近或看似重叠,它们在各自物体上的位置可能是不同的。这种表示法允许物理引擎分别处理每个物体表面上的接触效应,如摩擦、反作用力等:

  • 向量的方向决定力的方向,即接触点位置用于确定力的应用点和方向;
  • 向量的模决定力的大小,即接触深度(或距离)用于决定是否需要应用碰撞响应以及响应的强度。

3. 许多物理引擎使用特定的算法来检测和解析碰撞,这些算法可能会自然地为每个物体生成一个接触点。这种做法有助于算法的通用性和精确性,确保它们可以在不同情况下有效地工作。

2.3 接触点 (Contact Point) 的方向

接触点(Contact Point)的方向 :通常是指确定接触点的法线方向。接触点的法线方向是指从一个物体表面指向另一个物体表面的直线,通常垂直于接触面。这个方向对于计算碰撞响应(如力的大小和方向)非常重要。以下是如何确定接触点方向的一般步骤:

1. 碰撞检测算法

  • 当两个物体碰撞时,物理引擎使用碰撞检测算法来确定接触点。这些算法通常计算出接触点的位置以及碰撞发生时两个物体的相对位置。

2. 计算接触面法线

  • 接触面法线是指垂直于接触面的方向。在两个凸形物体碰撞的情况下,法线通常指向从一个物体(碰撞发生点)到另一个物体的方向。
  • 对于非凸形物体或更复杂的形状,法线的计算可能更为复杂,需要基于物体的几何细节和相对位置。

3. 使用物理引擎提供的数据

  • 大多数物理引擎会在碰撞检测过程中提供接触点的法线信息。例如,在 Bullet 物理引擎中, btManifoldPoint 类提供了获取接触点法线的方法。

4. 处理接触点数据

  • 在接触点数据结构中,除了接触点位置外,通常还会包括法线方向信息。这个信息用于计算碰撞力,特别是决定力的方向。

5. 法线方向的应用

  • 在计算碰撞响应时,如计算冲量或力的作用点,接触点法线方向是关键。它确保了力的方向正确地沿着两个物体的接触面垂直分布。

2.4 接触点 (Contact Point) 方法

方法含义
getDistance()该方法返回接触点的接触深度。在物理模拟中,这通常表示两个碰撞物体之间的重叠量。如果值为负,则表示物体之间有重叠(即发生了碰撞);如果值为正,则表示物体之间的距离。这个值对于判断物体是否碰撞以及计算碰撞响应非常重要。
getLifeTime()该方法返回接触点存在的时间帧数。这可以用于确定接触点的“年龄”,即它已经在物体间存在了多长时间。在物理模拟中,这可以用来处理接触点的持续性,比如用于摩擦或稳定性计算。
getPositionWorldOnA()getPositionWorldOnB()这两个方法分别返回接触点在世界坐标系中的位置,相对于碰撞中的两个物体(A和B)。 getPositionWorldOnA() 返回接触点在物体A上的位置,而 getPositionWorldOnB() 返回接触点在物体B上的位置。

2.5 接触点 (Contact) 与交点 (Intersection) 的区别

1. 接触点 (Contact Point)

  • 接触点通常指的是两个物体表面在碰撞中相接触的点。在物理模拟中,接触点不仅标识了物体之间的接触位置,还包含了额外的信息,如接触点的正常方向、接触深度(或距离)、接触点在每个物体上的确切位置等。

  • 接触点对于计算碰撞响应至关重要,如决定力的施加点、摩擦力的计算等。在复杂的物理模拟中,可能会有多个接触点,每个都有其独特的物理属性和影响。

2. 交点 (Intersection Point)

  • 碰撞的交点通常指的是两个物体几何形状在空间中相交的点。这更多关注于几何学上的交点,而不是物理学上的接触细节。

  • 在简单的碰撞检测中,这些交点用于确定两个物体是否物理上重叠或接触。然而,这些点可能不包含足够的信息来处理复杂的物理响应,如力的大小和方向。

小结

总结来说,接触点更多地关注于物理碰撞的细节,包括碰撞的力学属性和响应,而交点更多关注于几何相交的事实。在实际应用中,尤其是在复杂的物理模拟中,接触点的信息比单纯的交点信息更为丰富和有用。

3. 判断是否发生碰撞

bool IsCollision(btCollisionWorld* pCollisionWorld)
{
	// 1. 粗测阶段:流形
	unsigned int numManifolds = pCollisionWorld->getDispatcher()->getNumManifolds();
	for (unsigned int idx = 0; idx < numManifolds; idx++)
	{
		btPersistentManifold* contactManifold = pCollisionWorld->getDispatcher()->getManifoldByIndexInternal(idx);
		
		// 2. 精测阶段:接触点
		unsigned int numContacts = contactManifold->getNumContacts();
		for(unsigned int jdx = 0; jdx < numContacts; jdx++)
		{
			btManifoldPoint& pt = contactManifold->getContactPoint(jdx);
			if (pt.getDistance() <= 0.f)
			{
				return true;
			}
		}
	}
	return false;
}
  • 粗测阶段生成流形,精测阶段生成接触点;
  • 若粗测阶段未生成流形,则说明两物体没有包围盒发生碰撞;
  • 在精测阶段,若接触点的距离大于零,说明两物体虽包围盒发生碰撞,但实际的几何形体未发生碰撞,其接触点的距离为两物体的最短距离。
  • 在精测阶段,若接触点的距离小于零,说明两物体包围盒发生碰撞,同时实际的几何形体也发生碰撞,其接触点的距离为两物体互相渗透的深度。
  • 17
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
jBullet是一个Java实现的开源物理引擎,可以用于模拟2D和3D物理场景。以下是一个简单的jBullet示例,演示如何创建一个简单的物理场景并模拟物体的运动。 首先,我们需要导入jBullet库: ```java import com.bulletphysics.collision.shapes.*; import com.bulletphysics.dynamics.*; import com.bulletphysics.linearmath.*; import javax.vecmath.Vector3f; ``` 然后,我们可以创建一个物理场景: ```java DynamicsWorld world = new DiscreteDynamicsWorld(new CollisionDispatcher(), new DbvtBroadphase(), new SequentialImpulseConstraintSolver(), new DefaultCollisionConfiguration()); ``` 这里我们使用了一个离散的动力学世界,它包含了一个碰撞检测器、一个宽相检测器、一个顺序脉冲约束求解器和一个默认的碰撞配置。 接下来,我们可以创建一个平面作为地面: ```java StaticPlaneShape groundShape = new StaticPlaneShape(new Vector3f(0, 1, 0), 0); DefaultMotionState groundMotionState = new DefaultMotionState(new Transform(new Matrix4f(new Quat4f(0, 0, 0, 1), new Vector3f(0, -1, 0), 1.0f)))); RigidBodyConstructionInfo groundRigidBodyCI = new RigidBodyConstructionInfo(0, groundMotionState, groundShape, new Vector3f(0, 0, 0)); RigidBody groundRigidBody = new RigidBody(groundRigidBodyCI); world.addRigidBody(groundRigidBody); ``` 这里我们创建了一个静态平面,沿着y轴为1,位于y轴为0处。我们还创建了一个默认的运动状态,并使用它来创建一个刚体。最后,我们将刚体添加到物理世界中。 现在,我们可以创建一个球体,并给它一个随机的初速度: ```java float ballRadius = 1.0f; SphereShape ballShape = new SphereShape(ballRadius); Vector3f ballInertia = new Vector3f(0, 0, 0); ballShape.calculateLocalInertia(1, ballInertia); DefaultMotionState ballMotionState = new DefaultMotionState(new Transform(new Matrix4f(new Quat4f(0, 0, 0, 1), new Vector3f((float) (Math.random() * 10), 20, (float) (Math.random() * 10)), 1.0f)))); RigidBodyConstructionInfo ballRigidBodyCI = new RigidBodyConstructionInfo(1, ballMotionState, ballShape, ballInertia); RigidBody ballRigidBody = new RigidBody(ballRigidBodyCI); ballRigidBody.setLinearVelocity(new Vector3f((float) (Math.random() * 10), -10, (float) (Math.random() * 10))); world.addRigidBody(ballRigidBody); ``` 这里我们创建了一个球体,并使用calculateLocalInertia方法计算了它的惯性。我们还创建了一个随机的运动状态,并使用它来创建一个刚体。我们将刚体添加到物理世界中,并为球体设置一个随机的初速度,以便它开始运动。 最后,我们可以模拟物理场景并更新球体的位置: ```java for (int i = 0; i < 100; i++) { world.stepSimulation(1 / 60f, 10); Vector3f ballPos = new Vector3f(); ballRigidBody.getMotionState().getWorldTransform(new Transform()).getTranslation(ballPos); System.out.println("Ball position: " + ballPos.x + ", " + ballPos.y + ", " + ballPos.z); } ``` 这里我们循环100次,每次调用stepSimulation方法模拟物理场景,并使用getWorldTransform方法获取球体的位置并输出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值