1. Babylonjs 的逻辑帧和渲染帧

548 阅读3分钟

游戏中的帧的概念

我们知道游戏是一帧一帧的画面组成的连续动画。 每一帧都要运行一些逻辑,来形成最后的画面。一般的3D引擎中,都有一个固定的频率去跑每一帧的逻辑。这个固定的帧率,简单的实现,可以就是

setInterval(()=>{
    // do some logic
    customLogic();
    // call engine render
    engine.render();
}, 16.6)

上面代码中的customLogic就是自己的逻辑,比如调整一个小人的位置,又或者执行键盘事件等等。
等所有的逻辑走完了之后,引擎根据内部的数据,渲染新的画面。
如此往复,游戏就跑起来了。

Babylon.js 中帧的概念

我们知道网页js中,如果想要驱动一个动画逻辑,我们一般不使用setInterval, 此处的道理不额外多言,可自行问一下AI。
那么驱动一个定时执行的动画逻辑,要用什么api呢:

requestAnimationFrame

这个东西的效果,大体上和

setInterval(()=>{}, 16.6);

差不多,是以60帧的频率运行的。

我没看Babylon.js的源码,但大概率是用了这个requestAnimationFrame。这东西可以以当前的硬件真正所支持的频率进行运行。由于目前,大部分设备的默认就是60帧,所以这东西就是60帧了。

Babylon.js 的 Engine

初始化环境的时候,必须要new 一个Engine出来,这很合理,没什么可说。 那么怎么跑起来上面一节中提到的循环呢, 官方给的例子是这样来做的:

engine.runRenderLoop(()=>{
    console.log('此日志会16.6ms打印一次,不信你可以做实验');
});

调用了这一句之后,engine内部的各个生命周期函数,会在我们的闭包函数前后,相应的调用。

engine 身上的生命周期函数还挺多的,可以逐一的去试试。

Babylon.js 中的 Scene

在上面 runRenderLoop 中传入的闭包函数中,如果啥也不写,则看不见任何渲染的效果。 Babylon.js在这里做了很利于游戏开发的一个设计:Scene。

在 runRenderLoop 中需要调用 Scene.render 函数,才会看见东西。利用这个特性,我们可以控制渲染的帧率

你可能看糊涂了,上面不是说了,runRenderLoop 中的闭包函数不就是以60帧的频率在往前跑吗,这还能怎么控制。

你再看看我上面说的,要控制的是什么,是渲染的帧率!看代码,一目了然:

// 初始化一个 engine
const bbEngine = new Engine(canvas, true);
// 初始化一个 Scene
const bbScene = new Scene(bbEngine);
// 一个小计数器
let frameCounter = 0;
// 开始循环
bbEngine.runRenderLoop(()=>{
    frameCounter++;
    // 自己的业务逻辑
    customLogic();
    if (frameCounter%2 === 0) {
        // 渲染场景
        bbScene.render();
    }
});

上面代码就是说,customLogic 是60帧的频率在跑,但是bbScene.render()却是30帧的频率在跑。

这样一来,逻辑不动的情况下,渲染的帧率可以自由调节了,根据设备卡不卡。

玩游戏的时候,都会有这么个设置吧,就是30 60 120 啥的。这个控制的就是渲染帧率

这个不会影响逻辑!

那你要是问,我怎么能跑到120呢,这个就不可能了,这是设备决定的,你可以使用一个支持120的设备,跑上述代码,这样你自己来控制渲染帧率就好了。