window.requestAnimationFrame Web3D渲染帧率控制


注意: window.requestAnimationFrame控制Web3D渲染帧率一般不会超过运行环境所能提供的最高帧率的,假设电脑屏幕是165Hz的,能达到的最高帧就是165帧。

window.requestAnimationFrame简介

定义

window.requestAnimationFrame() 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行。

语法

window.requestAnimationFrame(callback);

参数

callback:下一次重绘之前更新动画帧所调用的函数 (即上面所说的回调函数)。该回调函数会被传入DOMHighResTimeStamp参数,该参数与performance.now()的返回值相同,它表示requestAnimationFrame() 开始去执行回调函数的时刻。

返回值

一个 long 整数,请求 ID ,是回调列表中唯一的标识。是个非零值,没别的意义。你可以传这个值给 window.cancelAnimationFrame() 以取消回调函数。

使用注意

准备更新动画时调用此方法,这将使浏览器在下一次重绘之前调用你传入给该方法的动画函数 (即你的回调函数);
回调函数执行次数通常是每秒 60 次,但在大多数遵循 W3C 建议的浏览器中,回调函数执行次数通常与 浏览器屏幕刷新次数 相匹配;
为了提高性能和电池寿命,因此在大多数浏览器里,当requestAnimationFrame() 运行在 后台标签页 或者隐藏的 iframe标签 里时,requestAnimationFrame() 会被暂停调用以提升性能和电池寿命;
回调函数会被传入DOMHighResTimeStamp参数,DOMHighResTimeStamp指示当前被 requestAnimationFrame() 排序的回调函数被触发的时间,在帧率控制中用这里传入的时间来计算时间差个人认为比较准备。在同一个帧中的多个回调函数,它们每一个都会接受到一个相同的时间戳,即使在计算上一个回调函数的工作负载期间已经消耗了一些时间。该时间戳是一个十进制数,单位毫秒,最小精度为 1ms(1000μs)。

两种方式控制帧率

定义两个描述:“标准帧”:不干涉默认requestAnimationFrame回调次数时的帧集合;“预计帧”:期望控制的帧集合;
在这里插入图片描述
方法一:默认帧数中取适当次数更新
不修改标准帧,只判断最近一次标准帧和上一次预期帧记录时间对比,看是否大于等于预计帧的间隔,大于则让希望被控制渲染的内容更新。如图中使用方法一预计在节点①更新的内容,实际是在标准帧中到第②节点才会去更新的。
方法二:用延时控制帧率更新的频率
修改标准帧,用setTimeout延时调用requestAnimationFrame,在方法二中让标准帧本该在①渲染的直接延时到方法二的①节点更新,达到帧数控制的效果。

以下代码是基于《Three.js学习七——播放模型动画时模型沿着轨迹移动》中代码修改的,引入了stats性能插件监控一下帧率和一些辅助变量,修改了部分animate方法内容。

import Stats from "./three.js-master/examples/jsm/libs/stats.module.js";

let stats = null;
function initStats() {
    
    
    stats = new Stats(); // 引入stats性能插件监控一下帧率
    stats.domElement.style.position = "absolute";
    stats.domElement.style.left = "0px";
    stats.domElement.style.up = "0px";
    document.body.appendChild(stats.domElement);
};

let timeS = 0;
let t = 0;
const FPS = 60;
const renderT = (1 / FPS) * 1000; //单位秒  间隔多长时间渲染渲染一次

默认帧数中取适当次数更新

/* 方法一animate */
function animate(time) {
    
    
	if (time !== undefined) {
    
    
		t = time - timeS; // 计算时间间隔
	}
	if (t >= renderT) {
    
    
		stats.update(); // 更新stats
		// 更新动画帧
		if (mixer) {
    
    
			mixer.update(clock.getDelta());
		}
		moveOnCurve();
        timeS = time; // 更新时间
	}
	renderer.render(scene, camera);
	requestAnimationFrame(animate);
};

效果:
请添加图片描述

用延时控制帧率更新的频率

/* 方法二animate */
function animate(time) {
    
    
    if (time !== undefined) {
    
    
        t = renderT - (time - timeS) % renderT;
    }
    stats.update();
    // 更新动画帧
    if (mixer) {
    
    
        mixer.update(clock.getDelta());
    }
    moveOnCurve();
    timeS = time; // 更新时间
    renderer.render(scene, camera);
    // 延时回调
    setTimeout(() => {
    
    
        requestAnimationFrame(animate);
    }, t)
};

效果:
请添加图片描述

总结

方法 要点 优缺点
方法一 判断帧间的时间间隔,默认帧数中取适当次数更新 在某些帧数区间会出现比较明显的帧数偏移,如我设置60帧可是实际跑一直是70帧;正常运行时帧数非常稳定,一般键鼠操作不会有明显影响。
方法二 计算预计帧间时间延时,用延时控制帧率更新的频率 由于控制了整个标准帧刷新,正常运行时帧数可能因为键鼠操作导致帧率上下浮动较方法一明显;比方法一更加贴近于设置帧数。

猜你喜欢

转载自blog.csdn.net/Mr_Bobcp/article/details/126179800