Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Bullet引擎的模拟循环

这里以bullet2.89版本为基础进行讲解。

btDiscreteDynamicsWorld类

btDiscreteDynamicsWorld负责整个物理世界的模拟流程。这个类包含物理世界的刚体数组、模拟岛和约束数组等。

// 在btDiscreteDynamicsWorld.h中
btDiscreteDynamicsWorld : public btDynamicsWorld
{
protected:
    // ...
	btConstraintSolver* m_constraintSolver; // 约束求解器
	btSimulationIslandManager* m_islandManager; // 模拟岛管理器
	btAlignedObjectArray<btTypedConstraint*> m_constraints;  // 约束数组
	btAlignedObjectArray<btRigidBody*> m_nonStaticRigidBodies;  //刚体数组
	btVector3 m_gravity;
    // ...
}

StepSimulation函数

bullet的StepSimulation函数是

// timeStep: 本帧真实流逝时间(来自游戏主循环)。
// maxSubSteps: 单帧内允许执行的“最大物理子步数”.
// fixedTimeStep: 单次物理 step 的固定 dt
int btDiscreteDynamicsWorld::stepSimulation(btScalar timeStep, int maxSubSteps, btScalar fixedTimeStep)

在这个函数中,存在两种时间推进模式,两种的模式的启用条件是:maxSubSteps的数值。

  • 固定时间步进(Fixed Timestep)。启用条件:maxSubSteps >0,物理使用固定步长(如1/60s)。数值稳定,适合游戏和实时仿真。
  • 可变时间步长(Variable Timestep)。启用条件maxSubSteps ==0,使用可变的时间步模式。每帧只跑一次物理。不推荐使用。
int btDiscreteDynamicsWorld::stepSimulation(btScalar timeStep, int maxSubSteps, btScalar fixedTimeStep)
{
	startProfiling(timeStep);
	
	int numSimulationSubSteps = 0; // 本帧应执行的物理 step 次数

	if (maxSubSteps)
	{	
		//固定时间步
		//fixed timestep with interpolation
		m_fixedTimeStep = fixedTimeStep;
		//m_localTime:尚未被物理消耗的时间
		m_localTime += timeStep;
		if (m_localTime >= fixedTimeStep)
		{
			numSimulationSubSteps = int(m_localTime / fixedTimeStep);
			m_localTime -= numSimulationSubSteps * fixedTimeStep;
		}
	}
	else
	{
		//可变时间步模式
		//variable timestep
		fixedTimeStep = timeStep;
		m_localTime = m_latencyMotionStateInterpolation ? 0 : timeStep;
		m_fixedTimeStep = 0;
		if (btFuzzyZero(timeStep))
		{
			numSimulationSubSteps = 0;
			maxSubSteps = 0;
		}
		else
		{
			numSimulationSubSteps = 1;
			maxSubSteps = 1;
		}
	}
	
	//process some debugging flags
	if (getDebugDrawer())
	{
		btIDebugDraw* debugDrawer = getDebugDrawer();
		gDisableDeactivation = (debugDrawer->getDebugMode() & btIDebugDraw::DBG_NoDeactivation) != 0;
	}
	if (numSimulationSubSteps)
	{
		//clamp the number of substeps, to prevent simulation grinding spiralling down to a halt
		int clampedSimulationSteps = (numSimulationSubSteps > maxSubSteps) ? maxSubSteps : numSimulationSubSteps;
		//保存上一帧状态
		saveKinematicState(fixedTimeStep * clampedSimulationSteps);
		//应用重力
		applyGravity();

		for (int i = 0; i < clampedSimulationSteps; i++)
		{
			//物理单步模拟
			internalSingleStepSimulation(fixedTimeStep);
			synchronizeMotionStates();
		}
	}
	else
	{
		synchronizeMotionStates();
	}
	// 清理力
	clearForces();

#ifndef BT_NO_PROFILE
	CProfileManager::Increment_Frame_Counter();
#endif  //BT_NO_PROFILE

	return numSimulationSubSteps;
}

internalSingleStepSimulation

void btDiscreteDynamicsWorld::internalSingleStepSimulation(btScalar timeStep)
{
	BT_PROFILE("internalSingleStepSimulation");

	if (0 != m_internalPreTickCallback)
	{
		(*m_internalPreTickCallback)(this, timeStep);
	}

	///apply gravity, predict motion
	// 1. 预测物无约束的运动
	predictUnconstraintMotion(timeStep);

	btDispatcherInfo& dispatchInfo = getDispatchInfo();

	dispatchInfo.m_timeStep = timeStep;
	dispatchInfo.m_stepCount = 0;
	dispatchInfo.m_debugDraw = getDebugDrawer();

	createPredictiveContacts(timeStep);

	///perform collision detection
	// 2. 碰撞检测
	performDiscreteCollisionDetection();
	// 3. 计算模拟岛
	calculateSimulationIslands();

	getSolverInfo().m_timeStep = timeStep;

	///solve contact and other joint constraints
	// 4. 约束求解
	solveConstraints(getSolverInfo());

	///CallbackTriggers();

	///integrate transforms
	// 5. 积分变换
	integrateTransforms(timeStep);

	///update vehicle simulation
	// 6. 更新自定义行为
	updateActions(timeStep);

	// 7. 更新激活状态
	updateActivationState(timeStep);

	// 8. 系统回调
	if (0 != m_internalTickCallback)
	{
		(*m_internalTickCallback)(this, timeStep);
	}
}