5

我将 Box2D 与 WebGL 一起使用。Box2D 需要恒定的帧速率(“世界”更新的时间步长)。

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

但我已经读过定义如下的 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);
     };
})();

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

有解决办法吗?

[编辑]

实施时约翰(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);
}

请注意,我的物理更新函数负责next_attribue设置 s。而且,update在此之前调用了一个物理,以使物理世界领先一帧。

结果

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

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

----> 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。

我对代码或以上两点有误吗?

我请求你澄清这些问题。

[编辑]

我在那里的评论中询问了这个网页的作者,寻找一种有效地绘制许多形状的方法。

我学会了这样做:我 bufferData通过为每个形状保存单独的缓冲区来保存调用,并且createBuffer在初始化期间只调用一次bindBufferbufferData

每次刷新屏幕时,我都必须遍历所有形状,并且必须在绑定所需形状的缓冲区(使用)之后调用enableVertexAttribArray和。vertexAttribPointerbindBuffer

我的形状不会随着时间而改变。它们中只有很多种(如多边形、圆形、三角形)从头到尾都保持不变。

4

2 回答 2

6

您必须将物理模拟步进时序与渲染垂直同步时序分离。最简单的解决方案是这样做:

frameCallback(dt) {
  physicsDt += dt;
  if (physicsDt > 16) {
    stepPhysics();
    physicsDt -= 16;
  }
  renderWorld();
  requestAnimFrame(frameCallback);
}

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

var t = dt/16.0;
framePosition = (1-t) * previousFramePositions + (t) * nextFramePositions;

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

约翰

于 2012-10-23T19:07:28.793 回答
1

requestAnimFrame并不是要保证恒定的帧速率——它的设计目的是让浏览器只计算它实际绘制的帧。

如果您想/必须计算未绘制的帧,那么这不是要走的路。

于 2012-10-23T18:48:12.087 回答