requestAnimFrame无法提供恒定的帧速率,但我的物理引擎需要它

bat*_*man 5 javascript box2d webgl requestanimationframe

我使用Box2D和WebGL.Box2D需要一个恒定的帧速率(它的"世界"更新的时间步长).

function update(time) {//update of box2d world
     world.Step(
           1/60   // 1 / frame-rate
        ,  3      //velocity iterations
        ,  8       //position iterations
     );
Run Code Online (Sandbox Code Playgroud)

但我已经读过如下定义的requestAnimFrame是正确的方法.

     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);
     };
})();
Run Code Online (Sandbox Code Playgroud)

requestAnimFrame没有给我一个恒定的帧速率,所以我的Box2D的变量是不同步的.

有没有解决这个问题?

[编辑]

实施时John的(Cutch)解决方案如下所示:

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);
}
Run Code Online (Sandbox Code Playgroud)

请注意,我的物理更新功能会注意next_attribues已设置.而且,update在此之前调用物理学,以使物理世界保持领先1帧.

结果

动画相当流畅,除了那些我可以看到一些非常糟糕的跳跃和随机出现的微动作的时候.

我认为解决方案中没有解决以下问题:

----> 1) dt可能会大于time_step:这将dt/time_step大于1,这将破坏插值方程.

dt保持大于time_step一致时,问题会增加.是否有可能克服时间差距变大的问题time_step

我的意思是,即使我们将世界保持在渲染之前一帧,如果时间间隔始终保持大于time_step,那么"前方"帧也不会需要很长时间.

----> 2) 想象一下dt小于time_step1毫秒.然后,世界不会更新一次.现在进行插值并找到近似位置(应该在它后面1毫秒).

让我们说下一次没有看到dt和之间的差异time_step.

现在,考虑到dt并且time_step相等,没有进行插值.那么,接下来绘制的是世界上的"前方"框架,对吧?(使用这些方程式t = 1)

但准确地说,渲染的世界应该是之前1毫秒.我的意思是,它在世界框架后面的1ms不应该消失.但是t = 1,绘制物理世界框架并忘记1ms.

我错了代码还是以上2分?

我请你澄清这些问题.

[编辑]

我问笔者这个网页,换一种方式来有效地绘制许多形状,在评论那里.

我学会了做这样说:我保留 bufferData通过保持独立的缓冲区为每个形状和呼叫通话createBuffer,bindBuffer,bufferData只有一次初始化过程中.

每次刷新屏幕时,我都必须迭代所有形状,然后我必须调用enableVertexAttribArrayvertexAttribPointer绑定所需形状的缓冲区(使用bindBuffer).

我的形状不随时间变化.它们中的各种(如多边形,圆形,三角形)始终保持不变.

Cut*_*tch 6

您必须将物理模拟步进时序与渲染vsync时序分离.最简单的解决方案是:

frameCallback(dt) {
  physicsDt += dt;
  if (physicsDt > 16) {
    stepPhysics();
    physicsDt -= 16;
  }
  renderWorld();
  requestAnimFrame(frameCallback);
}
Run Code Online (Sandbox Code Playgroud)

这里最大的问题是,有时你将使用过时的物理世界进行渲染,例如,如果physicsDt为15,则不会发生模拟更新,但是你的对象在那个时间点几乎会移动整个帧.您可以通过将物理1帧保持在渲染之前并在渲染器中线性插入对象位置来解决此问题.就像是:

var t = dt/16.0;
framePosition = (1-t) * previousFramePositions + (t) * nextFramePositions;
Run Code Online (Sandbox Code Playgroud)

这样,即使渲染与物理模拟不同步,您的对象也会平滑移动.如果您有任何疑问,请告诉我.

约翰