Thanks for your answer! So ok, it is not possible to just say that to let it run as fast as possible. Can I ask bullet somehow how many of the maxsubsteps it actually calculated and how many were not lost? Otherwise I will just tune it for my platforms to get my simulations done there as fast as possible. Hopefully I cam shorten down weeks down to days or so. Do you know if the Bullet on GPU is already ready to be used in complex simulations or not? Because that might speed up everything as well.
Edit: Found a way! I just calculate how much time is left for physics in a canonical loop as described in the Bullet physics wiki
http://www.bulletphysics.org/mediawiki- ... _Game_Loop. My canonical loop even has an inner loop that triggers when I say I want a headless simulation. Then the inner loop only updates the physics and my model of the simulation and the input, but never goes to the graphics rendering. Only when I turn the headless simulation off via input, it exits that inner loop. SIMULATION_SPEED_09 in the code below is the graphical mode running as fast as possible, SIMULATION_SPEED_10 is the headless mode running as fast as possible. When this method exits, the Graphics rendering takes place. That is why I also measure the time the program is outside this method.
Code: Select all
bool SimulationManager::frameRenderingQueued(const Ogre::FrameEvent& evt) {
// structure according to the canonical game loop
// http://www.bulletphysics.org/mediawiki-1.5.8/index.php/Canonical_Game_Loop
// shutdown the application if the application has initiated shutdown
if (mWindow->isClosed()
|| mStateHandler.getCurrentState() == StateHandler::SHUTDOWN) {
return false;
}
//#############
// Physics handling part
//#############
/* This, like the rendering, ticks every time around.
Bullet does the interpolation for us. */
do {
// update timers
mPrevious = mNow;
mNow = boost::posix_time::microsec_clock::local_time();
mModelStart = boost::posix_time::microsec_clock::local_time();
mLastGraphicsTick = mModelStart - mGraphicsStart;
if (mSimulationSpeed == PhysicsConfiguration::SIMULATION_SPEED_09
|| mSimulationSpeed
== PhysicsConfiguration::SIMULATION_SPEED_10) {
mPhysicsTick = boost::posix_time::millisec(
ApplicationConfiguration::APPLICATION_TICK)
- mLastGraphicsTick - mLastInputTick;
mPhysicsStepStart = boost::posix_time::microsec_clock::local_time();
while (mPhysicsTick > mPhysicsStepEnd - mPhysicsStepStart) {
// step the physics forward
mUniverse.setSimulationSpeed(mSimulationSpeed);
mUniverse.stepPhysics(
PhysicsConfiguration::SIMULATOR_PHYSICS_FIXED_STEP_SIZE);
// update the model
mUniverse.update(
PhysicsConfiguration::SIMULATOR_PHYSICS_FIXED_STEP_SIZE);
mPhysicsStepEnd =
boost::posix_time::microsec_clock::local_time();
}
} else {
// step the physics forward
mUniverse.setSimulationSpeed(mSimulationSpeed);
mUniverse.stepPhysics(
(mNow - mPrevious).total_milliseconds() / 1000.0f);
// update the universe
mUniverse.update((mNow - mPrevious).total_milliseconds() / 1000.0f);
}
mInputStart = mNow = boost::posix_time::microsec_clock::local_time();
mLastModelTick = mInputStart - mModelStart;
//#############
// Input part
//#############
// Game Clock part of the loop
/* This ticks once every APPLICATION_TICK milliseconds on average */
mApplicationDt = mNow - mApplicationClock;
while (mApplicationDt
>= boost::posix_time::millisec(
ApplicationConfiguration::APPLICATION_TICK)) {
mApplicationDt -= boost::posix_time::millisec(
ApplicationConfiguration::APPLICATION_TICK);
mApplicationClock += boost::posix_time::millisec(
ApplicationConfiguration::APPLICATION_TICK);
// Inject input into handlers
mInputHandler.injectInput();
// update the information in the panels on screen
updatePanels(ApplicationConfiguration::APPLICATION_TICK / 1000.0f);
}
mGraphicsStart = boost::posix_time::microsec_clock::local_time();
mLastInputTick = mGraphicsStart - mInputStart;
} while (mStateHandler.getCurrentState()
== StateHandler::HEADLESS_SIMULATION);
//#############
// Graphics part
//#############
// reposition the camera
...
// update view
...
// draw the debug output if enabled
...
return true;
}
I then step the bullet physics world like this:
Code: Select all
void PhysicsController::stepBulletPhysics(const double timeStep) {
//step the simulation
if (mDynamicsWorld && (!mPhysicsPaused || mPhysicsStepped)) {
//calculate the number of substeps the simulator needs to take
int subSteps =
PhysicsConfiguration::SIMULATOR_SECURITY_MARGIN
+ ceil(
pow(2,
PhysicsConfiguration::SIMULATION_SPEEDS[mSimulationSpeed])
* timeStep
/ PhysicsConfiguration::SIMULATOR_PHYSICS_FIXED_STEP_SIZE);
if (timeStep) {
mDynamicsWorld->stepSimulation(
pow(2,
PhysicsConfiguration::SIMULATION_SPEEDS[mSimulationSpeed])
* timeStep, subSteps,
PhysicsConfiguration::SIMULATOR_PHYSICS_FIXED_STEP_SIZE);
}
//if step trigger is pressed, we pause the simulation and it steps forward every time we press the step trigger
if (mPhysicsStepped) {
mPhysicsStepped = false;
mPhysicsPaused = true;
}
}
}
The constants in my code are those:
Code: Select all
/**
* Step size of the bullet physics simulator (solverAccuracy). Accuracy versus speed.
*/
static const double SIMULATOR_PHYSICS_FIXED_STEP_SIZE = 1.0f / 60.0f;
static const int SIMULATOR_SECURITY_MARGIN = 5;
const int PhysicsConfiguration::SIMULATION_SPEEDS[] = {
/*SIMULATION_SPEED_01*/
-2,
/*SIMULATION_SPEED_02*/
-1,
/*SIMULATION_SPEED_03*/
0,
/*SIMULATION_SPEED_04*/
1,
/*SIMULATION_SPEED_05*/
3,
/*SIMULATION_SPEED_06*/
5,
/*SIMULATION_SPEED_07*/
6,
/*SIMULATION_SPEED_08*/
7,
/*SIMULATION_SPEED_09*/
0, // run as fast as possible with graphics
/*SIMULATION_SPEED_10*/
0 //run as fast as possible headless
};
I hope this helps somebody that has the same problem. If something is unclear, just ask.