1.bullet简介:

bullet可以做刚体模拟,软体模拟以及变形刚体处理,他是一个开源库。

2.bullet的继承关系以及调用方式:

这里只列举一些常用的。

2.1堆栈分配:

2.2派发器:

2.3碰撞检测及空间管理:

2.4约束处理:

2.5物理世界:

2.6各种约束:

2.7MCLP约束处理:

2.8联动模拟:

2.9调用关系:

3.刚体模拟:

bullet组成一个物理世界需要以下几个对象(首先介绍最通用的版本是普通刚体模拟)

btCollisionConfiguration;用于堆栈分配器大小,碰撞算法和复合模型大小。

btCollisionDispatcher:支持处理凸凸和凸凹碰撞对的算法。 冲击时间,最近点和穿透深度。

btDbvtBroadphase:使用两个动态的AABB包围体层次结构/树(参见btDbvt)实现一个宽碰撞检测阶段。 一棵树用于静态/非移动对象,另一棵树用于动态对象。 对象可以从一棵树移动到另一棵树。 这是一个非常快的宽阶段,特别是对于很多物体都在移动的动态世界。 它的插入/添加和删除对象通常比扫描和修剪宽相位btAxisSweep3和bt32BitAxisSweep3要快。  btAxisSweep3和bt32BitAxisSweep3是另一种宽碰撞检测方式。

btSequentialImpulseConstraintSolver:迭代的脉冲序列解决约束问题的方案。

btDiscreteDynamicsWorld:动态碰撞世界,是组合以上元素的统一体。

btRigidBody:刚体本身,每个对象需要有碰撞都需要他。

btDiscreteDynamicsWorld负责整合堆栈分配器,碰撞派发器,碰撞检测和约束处理。

碰撞检测:

其中碰撞检测就包括宽碰撞和窄碰撞,如果用的是btDbvtBroadphase则是在btDbvt::rayTestInternal根据深度不断碰撞检测点的aabb是否有碰撞,有碰撞到就进入policy.Process(node);最终在btCollisionWorld::rayTestSingleInternal根据选择的窄碰撞方式来进行宅碰撞,比如选择Gjk的方式。到btGjkPairDetector::getClosestPointsNonVirtual进行宅碰撞检测。最终得到最近的点。再返回碰撞点信息。

4.约束处理:

4.1btSequentialImpulseConstraintSolver:

再btSequentialImpulseConstraintSolver中是单线程的处理约束,约束的条件是需要把相关的刚体通过世界动态管理器btDiscreteDynamicsWorld的addRigidBody来加入到世界中,然后每帧调用btDiscreteDynamicsWorld的stepSimulation来让他执行约束处理。在btDiscreteDynamicsWorld中分了两部,第一步是处理约束数据internalSingleStepSimulation,第二步是同步数据到transparent中。

4.2predictUnconstraintMotion:

internalSingleStepSimulation中predictUnconstraintMotion首先预测没约束的世界,主要是一些弹簧处理。

4.3createPredictiveContacts:

就会进行宽碰撞和窄碰撞检测convexSweepTest。

4.4performDiscreteCollisionDetection:

主要更新aabb以及排序。

4.5calculateSimulationIslands:

做的让每个需要联动的对象联合在一起。

4.6solveConstraints:

里面主要执行processConstraints进入btSequentialImpulseConstraintSolver这里的solveGroup,设置互相刚体的约束起始数据以及迭代处理约束并且最终赋值约束到外面。solveGroupCacheFriendlySetup,solveGroupCacheFriendlyIterations,solveGroupCacheFriendlyFinish。

采用雅可比迭代法。

4.7integrateTransforms:

是最终迭代力到刚体上。

5.软体模拟:

软体模拟是在自身还会有一定的反复碰撞或者叫做联动的效果,也就是会影响到顶点的变化。他构建的方式跟刚体类似,但是有一些部分不太一样,构建世界时用的对战生成器是用的。

5.1btSoftBodyRigidBodyCollisionConfiguration

主要是因为他跟刚体不一样,他还有软体自己的解决方案。

另外一个就是构建的世界的离线世界对象用的是btSoftRigidDynamicsWorld。

5.2btSoftBodySolver:

另外要说的一个是btSoftBodySolver,这个是软体的处理方式,后面会讲到。

还有一点不一样的就是加入刚体处理这里用的是addSoftBody,加入的刚体自然要是btSoftBody。

我们关注在btSoftRigidDynamicsWorld::internalSingleStepSimulation:

他首先会执行btDiscreteDynamicsWorld::internalSingleStepSimulation(timeStep);也就是让刚体离散世界的循环模拟一样执行。但是internalSingleStepSimulation里面的几个方法执行得不一样。

5.3predictUnconstraintMotion:

他除了还是预处理无约束的力的变化外,还会执行m_softBodySolver->predictMotion(float(timeStep));用到了btSoftBodySolver,而这里用的是btDefaultSoftBodySolver的predictMotion。对所有软体btSoftBody执行内部的predictMotion,主要是做顶点更新以及动态aabb树的构建。

其他关于宽碰撞窄碰撞,更新aabb和排序,相关对象联合,约束处理都会用回btDiscreteDynamicsWorld的。

5.4solveSoftBodiesConstraints:

然后执行btSoftRigidDynamicsWorld::solveSoftBodiesConstraints也就是软体约束。

在btSoftBody::solveClusters里面会准备好约束信息启用prepareClusters,每个body执行solveClusters,对里面的联合约束处理,比如AJoint是角速度联合,LJoint是线性直线运动联合,CJoint互相的约束联合。cleanupClusters清除簇。

5.5defaultCollisionHandler:

对每个软体执行defaultCollisionHandler,主要执行collideTV,也就是执行宽碰撞和窄碰撞。

5.6m_softBodySolver->updateSoftBodies

通过btDefaultSoftBodySolver的updateSoftBodies对每个软体执行integrateMotion,最终更新法线信息updateNormals。

完成整个软体的循环。

6.多线程离散世界处理:

总的来说多线程版本的,其实就是用一个互斥锁来执行旁边范围的对象的btDiscreteDynamicsWorld方法。因为互斥锁所以运行效率也是看线程运行效率,因为他是会锁死线程的,并且按顺序。理论上因为加了多线程,肯定比单线程快,但也会有可能等待的情况。

6.1bDiscreteDynamicsWorldMt

这里会锁线程执行solveGroup,predictUnconstraintMotion,createPredictiveContacts,integrateTransforms。

6.2btDefaultCollisionConfiguration

用的是默认的堆栈管理器,addRigidBody用的是btDiscreteDynamicsWorld中的。

6.3internalSingleStepSimulation

因为会执行btDiscreteDynamicsWorld::internalSingleStepSimulation。而btDiscreteDynamicsWorldMt重写了一些方法,

1.predictUnconstraintMotion

2.createPredictiveContacts

3.solveConstraints

4.integrateTransforms

以上四个方法。

6.3.1predictUnconstraintMotion

是执行了btParallelFor(0, m_nonStaticRigidBodies.size(), grainSize, update);

而btParallelFor的方法是gBtTaskScheduler->parallelFor(iBegin, iEnd, grainSize, body);

也就是执行btTaskSchedulerDefault的parallelFor。

里面是用互斥锁把线程锁起来然后执行iBegin到iEnd区间按照间隔grainSize。加入多线程队列执行。通过ParallelForJob的executeJob,执行body的forLoop。在btDiscreteDynamicsWorldMt::predictUnconstraintMotion中就是update,这个update是UpdaterUnconstrainedMotion,执行到UpdaterUnconstrainedMotion的forLoop。

这时线程会排队,因为是互斥锁,到了才会执行。

这里就是执行body的力的方法了。

6.3.2createPredictiveContacts

这里其实都是一样的,通过btParallelFor来执行互斥锁,执行UpdaterCreatePredictiveContacts的forLoop,最终执行回btDiscreteDynamicsWorld的createPredictiveContactsInternal。

6.3.3solveConstraints

这里就不太一样了,首先他的btConstraintSolver是btConstraintSolverPoolMt。prepareSolve还是用btConstraintSolver的,其实也没执行任何东西。然后把m_islandManager强制转为btSimulationIslandManagerMt,执行buildAndProcessIslands。他的btConstraintSolverPoolMt::solveGroup执行互斥锁后执行btSequentialImpulseConstraintSolver::solveGroup处理相互关系。

最后到solveConstraints执行btConstraintSolverPoolMt的allSolved,其实也没执行任何东西。

6.3.4integrateTransforms

这里还是用btParallelFor来执行间隔距离的UpdaterIntegrateTransforms的forLoop。其实还是btDiscreteDynamicsWorld的integrateTransformsInternal。

7.多刚体同时模拟:

带Muti的类都是针对原始物理系统的一个优化,相当于给到多个同样的对象,然后一次性处理,减少多次重复add进world的过程以及循环判断的过程。因为类型都一样可以一起处理。然后他是说可以急速计算关节梯多自由度算法的。

主要用到btMultiBodyDynamicsWorld,他可以保存多个一致的RigidBody,Constraint。stepSimulation中的内部执行internalSingleStepSimulation还是用btDiscreteDynamicsWorld的。但是predictUnconstraintMotion,calculateSimulationIslands,solveConstraints,integrateTransforms,updateActivationState都用btMultiBodyDynamicsWorld的。

btMultiBody是一个多个body的容器以及处理方式,他里面的m_links是一个btMultibodyLink的数组,他保存的是一些用于运算的数据,但是他不会new出rigidbody的方式去运算。然后通过btMultiBodyDynamicsWorld::addMultiBody把这个btMultiBody加入到场景中运算。

然后在btMultiBodyDynamicsWorld中运行internalSingleStepSimulation时,比如predictMultiBodyTransforms,不单止会运行带rigidbody的btDiscreteDynamicsWorld的predictMultiBodyTransforms,还会运行带btMultiBody的btMultiBodyDynamicsWorld。

其中btMultiBodyDynamicsWorld里的约束solveConstraints比较特别的处理,对所有multiBody做约束判断。

8.变形体模拟:

btDeformabeBody

这个是用于可变形的精确约束的,比如两个布料,他们之间的约束就可以用这个方式来执行,但是他的性能非常低,主要低效在于两块,第一个是btDeformableMultiBodyDynamicsWorld::internalSingleStepSimulation中的performDiscreteCollisionDetection,他会执行dispatcher->dispatchAllCollisionPairs

,最终执行到btOverlappingPairCache下的btHashedOverlappingPairCache::processAllOverlappingPairs,callback->processOverlap(*pair)会比较耗时。

另外一个地方在约束处理solveConstraints中。

结构是用btSoftBodyRigidBodyCollisionConfiguration的config,btCollisionDispatcher的dispatcher,btDbvtBroadphase的宽碰撞检测,btDeformableMultiBodyConstraintSolver的窄碰撞检测,btDeformableMultiBodyDynamicsWorld这个世界管理器来组织的。

在衣服上,他加了两个力,一个是本身的质量的弹力,另一个重力。

9.各种约束方式处理:

9.1btPoint2PointConstraint

Jacobi 方法先遍历所有弹簧,把每个点受到多个弹簧影响的位置更新量累加起来取平均值,再用平均值更新弹簧的位置。Jacobi 方法没有偏向性,不存在 bias 问题。容易并行计算。

9.2btHingeConstraint

他是一个点旋转的约束,他只能绕着一个点旋转,不能移开这个点,他也能约束他的旋转角度。

他设置的pivotInA就是约束的点。

9.3btSliderConstraint

btSliderConstraint是基于轴的约束,他只能在指定的轴上移动,不能离开这个轴。他跟btHingeConstraint的差别是,btHingeConstraint会控制基于一个点的旋转角度,而btSliderConstraint是直接获取轴然后限制在轴上运动。

9.4btGeneric6DofConstraint

VoronoiFractureDemo里面展示了一个刚开始很牢固然后碰到物体之后就开始部分松散的效果。

组成整个牢固效果的是通过VoronoiFractureDemo约束来实现的,他的实现方式是再限制约束的时候执行btGeneric6DofConstraint的getInfo2,他里面关键是两个,一个是setAngularLimits,一个是setLinearLimits。

setAngularLimits是角度的限制,通过对每两个对象执行约束。setLinearLimits同样也是通过get_limit_motor_info2来限制的线性运动。

当碰撞到其他刚体后,在每个刚体判断convertContact的时候会判断是否达到可以断裂的力,如果到了则添加链接池子的数量,池子越多断裂越多,然后因为池子的数量变化,执行让两个物体分开。其中通过btSolverConstraint给到两个body力让他们分开。

9.5btGeneric6DofSpring2Constraint

这是一个通过雅可比迭代约束的方式限制两个对象的,并且通过enableSpring可以让对象有弹簧力。

btGeneric6DofSpring2Constraint里的setLimit,enableSpring,setStiffness等都是按顺序设置的,前三个索引是设置xyz,后三个是设置旋转的xyz。

getInfo1还是设置初始的约束数值,m_numConstraintRows数量越大,在btSequentialImpulseConstraintSolver::convertJoint对约束的迭代越多。

getInfo2也是对线性速度以及角速度约束的。setAngularLimits,setLinearLimits。

通过跟轴的叉乘输出到m_J1angularAxis和m_J2angularAxis中。

如果设置了m_enableSpring则会通过胡克定义设置弹力。最后放在m_constraintError。

9.6btConeTwistConstraint

可以用来模拟布娃娃的关节(上臂,腿等)

9.7各种约束在btSequentialImpulseConstraintSolver的处理

主要在convertJoints中需要做两个信息的获取。getInfo1和getInfo2.

getInfo1是获取初始信息,相当于角度限制,位移限制的数值获取。会在convertJoints中做整体限制。

getInfo2是在每一段约束中单端执行的convertJoint。执行每个btTypedConstraint类型的getInfo2获取数据,然后info2的数值跟currentConstraintRow关联的起来,他是一个btSolverConstraint类型。

在writeBackContacts中将力的变化放到m_appliedImpulse等,就完成约束处理。

10.几何体:

10.1几何体基础

首先btCollisionShape是一个碰撞几何体,所有要有碰撞的几何体都需要继承他。比如btBoxShape。btCapsuleShape等

10.2凸边形几何体:

btConvexShape是凸边形几何体,也就是可以让开发者定义凸变形顶点索引等的几何体结构。

10.3任意几何体:

btTriangleMesh可以组成任意几何体。

10.4组合几何体

要形成一个组合模式的话需要用到btCoumpoundShape,组合模式的概念是他可以结合多个碰撞几何体形成一个整体,addChildShape就是加入一个几何体到组合几何体中。

11.反向动力学:

11.1InverseDynamics模式:

这里用到createInvertedPendulumMultiBody创建btMultiBody,btMultiBody里面有相关反向动力学相关的计算。InvertedPendulumPDControl中的createInvertedPendulumMultiBody创建了两个链接的节点,setupRevolute或者setupFixed可以固定节点或者可以浮动节点,setupRevolute还用以可以旋转的轴以及角度限制的控制。world->addMultiBody(pMultiBody);加入到world中,然后btMultiBodyLinkCollider加入pMultiBody,然后world->addCollisionObject加入到world中。

然后到InverseDynamicsExample中

btInverseDynamics::btMultiBodyTreeCreator id_creator;

btInverseDynamics::CreateMultiBodyTree(id_creator);。这里的目的是建立反向动力学的父级以及子级关系,先建立一个MultiBodyTree,针对num_bodies个body,addBody把相关的父节点,链接类型等写入MultiBodyTree中。

然后再InverseDynamicsExample::stepSimulation中更新pd_control(dof)的值并设置到nu(dof)中,然后通过m_inverseModel->calculateInverseDynamics来计算反向动力学的结果(m_inverseModel是前面装载了父节点的MultiBodyTree)。调用到MultiBodyTree::MultiBodyImpl::calculateInverseDynamics。最终目的是计算出joint_forces值。然后回到InverseDynamicsExample的stepSimulation,对所有相关btMultiBody执行m_multiBody->addJointTorque(dof, joint_force6(dof + 6));加入到btMultiBody的m_links[i]中。通过btMultiBody::computeAccelerationsArticulatedBodyAlgorithmMultiDof来计算出最终这个节点的运动结果。

11.2InverseKinematics模式:

在InverseKinematicsExample中initPhysics中的BuildKukaIIWAShape建立了一个树结构,通过InsertRoot,InsertLeftChild,InsertRightSibling等函数加入到树结构中,并设置Node的长度,链接方式以及限制角度 new Node(p1, unitx, 0.08, JOINT, RADIAN(-180.), RADIAN(180.), RADIAN(30.));

然后new Jacobian加入树结构来初始化雅可比方式,在stepSimulation中用UpdateTargets来模拟运动,ComputeJacobian计算雅可比结果,他是从父节点一个一个节点拿出来计算结果存到末端执行位置然后末端执行位置再影响到目标执行位置。

然后雅可比的算法上有几种:雅可比转置法,阻尼最小二乘法,德尔塔算法,纯伪逆方法,选择性阻尼最小二乘法。最终算的结果放到jacob的dTheta中。通过不同的方式计算结果。

然后用jacob->UpdateThetas();让dTheta的值放入到Node中,然后Tree的Compute会执行ComputeTree,从根节点到子节点,每个节点执行位移和旋转。在Node的ComputeS中theta用于位移,ComputeW中的theta用于旋转。这两个值就是之前用在计算节点变化的ComputeJacobian中。

然后UpdatedSClampValue来插值放到dSclamp中。

renderScene中把效果渲染出来。MyDrawTree是画出反向动力学所有节点得结构得。

11.3InverseKinematics和InverseDynamics的比较:

InverseKinematics是分成几步去做的,分别是计算雅克比,计算每个节点运动,更新每个节点运动,他们每一步都是单独遍历更新的。他没有跟随rigidbody,也就是他制作反向动力学,不会有碰撞相关的计算

InverseDynamics,这里是用MultiBody做的rigibody,也就是他还是会有碰撞相关的计算,而且他是用一个循环把更新碰撞相关的全做了。理论上他的反向动力学计算会快一点,但是如果有碰撞他可能会慢一些。

12.MLCP线性互补:

btMLCPSolver是通过MLCP解决的一个约束方案,他本质是LCP,也就是线性互补问题。他是需要a和b的符号是相反的,也就是a是正的b就是负数。而MLCP是混合线性互补问题,也就是混合所有问题一次解决,也就不一定是符号相反的了。

参考:

The Mixed Linear Complementarity Problem - Chris Hecker's Website

物理引擎如何正确的求解多个刚体间的约束? - 知乎

物理引擎之约束求解(一)——线性互补问题 - 知乎

在bullet的例子中有用到MLCP的是在Hinge2Vehicle中,当按下f6后他会切换约束方式btSequentialImpulseConstraintSolver为btDantzigSolver。

首先在 btMLCPSolver::solveGroupCacheFriendlySetup设置约束时会把所有相关的约束加入到m_allConstraintPtrArray数组中,然后createMLCPFast(infoGlobal);这里执行快速创建MLCP,把算到的力加入到m_b中。

然后在迭代约束时btMLCPSolver::solveGroupCacheFriendlyIterations执行result = solveMLCP(infoGlobal);,然后执行m_solver->solveMLCP。在里面循环赋值多个a和b的力来计算

然后在btDantzigLCP中的btSolveDantzigLCP循环计算力的影响。

最终在btMLCPSolver::solveGroupCacheFriendlyIterations给回到solverBodyA和solverBodyB的力上面。

像MLCP的解法有btLemkeSolver,btDantzigSolver。

bullet物理系统功能及实现简介相关推荐

  1. Unity 物理系统 -- 碰撞体简介(碰撞、触发条件)

    Unity 物理系统 -- 碰撞体简介(碰撞.触发条件) 几个常用的碰撞体: Box Collider:盒碰撞体,盒碰撞体是一个立方体外形的基本碰撞体,该碰撞体可以调整为不同大小的长方体,可用作门.墙 ...

  2. 给osg配置bullet物理引擎

    配置bullet物理引擎,花了好长时间,因为没有详细的教程,现在做个笔记. 首先,对于下载下来的一大堆文件,包括好多demo,example,src,等等看的我们眼花缭乱,其实我们可以先不要管他,因为 ...

  3. bullet 物理引擎资料

    bullet 官方网站 https://pybullet.org gamekit-developers 开源的游戏引擎,由 bullet 创始人发起. https://github.com/gamek ...

  4. Bullet 物理引擎 简析[1]

    原创帖子, 转载请注明出处,作者信息.   这个是自己分析bullet的代码过程中的笔记,比较简陋, 希望抛砖引玉, 欢迎板砖 作者: 马良 (www.iphonephysics.com ) (此bl ...

  5. bullet物理引擎与OpenGL结合 导入3D模型进行碰撞检测 以及画三角网格的坑

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/11681069.html 一.初始化世界以及模型 /// 冲突配置包含内存的默认设置,冲突设置. ...

  6. Bullet 物理引擎 详细分析 Dbvt (4)

    光线与AABB 相交检测: 这是一个非常经典的问题, <<real time collision detection>> 5.33章节有非常详尽的讨论. 下面是光线的方程 t是 ...

  7. 使用 bullet 物理引擎多线程求解器

    注意,很多时候多线程的性能比单线程的更烂. windows10 本机测试 bullet 版本 master 2021/6 单线程:10-13FPS PPL:7-13FPS OpenMP:1-4FPS ...

  8. 【AwayPhysics学习笔记】:Away3D物理引擎的简介与使用

    首先我们要了解的是AwayPhysics这个物理引擎并不是重头开始写的新物理引擎,而是使用Flascc技术把一个已经很成熟的Bullet物理引擎引入到了Flash中,同时为了让as3可以使用这个C++ ...

  9. bullet 库的概述

    Library Overview 库的概述 Introduction 简介 物理引擎的主要任务是执行碰撞检测.解决碰撞和其他约束,并为所有对象提供更新的世界变换.本章将概述刚体动力学管道以及所有组件共 ...

最新文章

  1. ASP.NET MVC 防止 CSRF 的方法
  2. shell中的命令替换和变量替换
  3. mysql 平均响应时间_Percona-Server/MySQL响应时间统计
  4. C#图解教程 第十二章 数组
  5. win10查看上次开机时间
  6. 开发 OpenAM Java 客户端
  7. 深圳警方出手!“钱爸爸”涉嫌集资诈骗 已累计冻结2.13亿元
  8. 你在寻觅冬季唯美的海报设计素材么?
  9. psm倾向得分匹配法举例_倾向得分匹配法的详细解读
  10. unix服务器修改系统时间,Linux或Unix修改系统时间的方法
  11. 通过使用 NTLite 工具实现精简Windows系统
  12. android手机更改手机密码,重要提醒:手机这个密码一定要改!
  13. div嵌套的div水平垂直居中
  14. win10系统bat脚本自启动程序、修改壁纸、更换主题区分主副屏壁纸
  15. 专利之争:诺基亚与苹果互指对方侵权(每日关注2009.12.31)
  16. PS如何修改图片上的文字
  17. 技术博客哪家强:CSDN、博客园、简书、开源中国OSChina等博客的详细分析比较
  18. mongodb基础入
  19. 计算机组成原理中dma是,《计算机组成原理》课程中“DMA方式”知识点的教学设计...
  20. 微软校招来喽 | 内推名额等待优秀的你

热门文章

  1. [C++][QT]俄罗斯方块
  2. 数论概论 第二章 勾股数组
  3. 在Linux下使用“360随身WiFi 2”
  4. JSP住宅小区物业管理系统(源代码+开题报告+论文+答辩PPT)科大云炬
  5. JavaScript之for...in和for...fo区别
  6. linux登录grub是什么,linux 如何单用户登录和设置grub密码Linux -电脑资料
  7. Unix和Linux有什么区别?
  8. PHPStorm使用PHP7新特性出现红色波浪错误
  9. 关于Gerrit管理使用git push出现 prohibited by Gerrit: ref update access denied
  10. 恶意软件如何被用来创建虚假的过期证书警报