I use Box2D with WebGL. Box2D demands a constant frame rate (time steps for it's "world" updates).
function update(time) {//update of box2d world
world.Step(
1/60 // 1 / frame-rate
, 3 //velocity iterations
, 8 //position iterations
);
But I've read that requestAnimFrame defined as below is the right way to go.
requestAnimFrame = (function() {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(/* function FrameRequestCallback */ callback, /* DOMElement Element */ element) {
window.setTimeout(callback, 1000/60);
};
})();
requestAnimFrame doesn't give me a constant frame rate and so my Box2D's variables are going unsynchronized.
Is there a fix to this?
[EDIT]
John's (Cutch) solution when implemented looks like this:
function interpolate(dt) {
var t = dt/time_step;
body_coordinates = (1-t) * body_coordinates + t * next_body_coordinates;
}
var physicsDt = 0;
function tick() {
var time_now = new Date().getTime();
var dt = time_now - last_time; //Note that last_time is initialized priorly
last_time = time_now;
physicsDt += dt;
clear_the_screen();
requestAnimFrame(tick);
drawEverything();
if(physicsDt >= time_step) {
update();
physicsDt -= time_step;
}
interpolate(dt);
}
Note that my physics update function takes care that the next_attribue
s are set.
And also, a physics update
is called before this, to keep the physics world ahead by 1 frame.
The result
The animation is fairly smooth, except for those times when I can see some really bad jumps and random appearing micro-movements.
I thought the following issues were not addressed in the solution :
----> 1) dt
may become larger than time_step
: This would make dt/time_step
greater than 1 which would ruin the interpolation equations.
When dt
remains larger than time_step
consistently, problems would increase.
Is it possible to overcome the problem of the time gap becoming larger than time_step
?
I mean, even if we keep the world one frame ahead of the rendering, if time gaps consistently stay greater than time_step
, it wouldn't take long pass that "ahead" frame.
----> 2) Imagine dt
being lesser than time_step
by 1 ms. Then, the world is not updated that one time. Now interpolation is done and the approximate position is found(1 ms behind where it should have been).
Lets say the next time no difference is seen between dt
and time_step
.
Now, no interpolation is done considering that dt
and time_step
are equal. So, the next that is drawn is the "ahead" frame in the world, right?(using those equations, with t = 1
)
But accurately, the rendered world should be that 1ms behind which it was before.
I mean, that 1ms by which it was behind the world frame should not vanish.
But with t = 1
, draws the physics world frame and forgets that 1ms.
Am I wrong about the code or the above 2 points?
I request you to clarify these issues.
[EDIT]
I asked the author of this webpage, for a way to efficiently draw many shapes, in the comments there.
I learnt to do it this way :
I'm saving bufferData
calls by keeping separate buffers for each shape and calling createBuffer
, bindBuffer
, bufferData
only once during init.
Everytime I refresh the screen, I have to iterate over all the shapes and
I have to call enableVertexAttribArray
and vertexAttribPointer
after binding the required shape's buffer(using bindBuffer
).
My shapes don't change with time. There are just a variety of them (like polygons, circles, triangles) that stay from beginning to end.
You must decouple your physics simulation stepping timing from your render vsync timing. The easiest solution is to do this:
frameCallback(dt) {
physicsDt += dt;
if (physicsDt > 16) {
stepPhysics();
physicsDt -= 16;
}
renderWorld();
requestAnimFrame(frameCallback);
}
The biggest issue here is that sometimes you'll be rendering with an outdated physics world, for example, if physicsDt was 15 no simulation update will occur but your objects would have moved almost an entire frame by that point in time. You can work around this by keeping the physics 1 frame ahead of the rendering and linearly interpolating object positions in the renderer. Something like:
var t = dt/16.0;
framePosition = (1-t) * previousFramePositions + (t) * nextFramePositions;
That way your objects move smoothly even if you're rendering is out of sync with your physics simulation. Let me know if you have any questions.
John
requestAnimFrame
isn't meant to guarantee a constant frame rate – it's designed so that the browser only does the calculations for frames it actually draws.
If you want/have to calculate frames that aren't drawn, then it isn't the way to go.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With