Integrate Simulation and Visualization
The most common type of ODE simulation has the following characteristics:
- it is real time (simulation time and wall-clock time are synchronized)
- it is visualized using a graphics device.
This page describes how to properly integrate the graphics and the sim parts.
The simulation and visualization are iterative processes. For an iteration, the simulation is used to update the state of the world, and then this state is depicted in the visualization stage. First order of business is to measure the time that elapsed while your main loop performed the last iteration.
A naive approach would be to use this measured elapsed time value in ODE's Step() function call. This has two drawbacks: for slow CPUs or slow graphics cards, the elapsed time may be so big that the simulation is performed with timesteps that are too large, giving bad results. Additionally, the measured timesteps are likely to vary from run to run, causing a non deterministic simulation: each time you run the simulation, the outcome will be different.
To get a simulation that is:
- repeatable between runs
- real time
- not influenced by the speed of the visualization stage
The following approach is to be taken:
- Choose a fixed timestep to use to step through ODE's simulation, e.g. 1 ms.
- See how many sim timesteps there are in your measured elapsed time dt. You can do this by dividing dt by the simstep, rounding up. E.g. if you measured an elapsed time of 14.5 ms you would do 15 simulation steps, followed by the visualization.
- To avoid a situation where elapsed time keeps growing each frame because it needs to make more and more simulation steps, an upper limit for dt needs to be taken so that slow systems can still run the application, albeit not real time.
- Note that instead of rounding up the division result, you could opt for carrying the remainder of the simulation time to the next frame.
In code, it will look like the main loop in ODE's test application test_basket.cpp which is something like this:
double simstep = 0.001; // 1ms simulation steps double dt = dsElapsedTime(); int nrofsteps = (int) ceilf(dt/simstep); // PERFORM SIMULATION for (int i=0; i<nrofsteps && !pause; i++) { dSpaceCollide (space,0,&nearCallback); dWorldQuickStep (world, simstep); dJointGroupEmpty (contactgroup); } // PERFORM VISUALIZATION ...