抖抖fps抖up,Stage和StageGL性能测试
StageGL更新公告 STAGEGL – A FASTER, BETTER, STRONGER WEBGL UPDATE TO EASELJS
参考 CreateJs - EaselJs 文档
概述
2017年4月,EaselJs发布更新,正式推出了StageGL
。
和Stage
一样,StageGL
也是加载显示列表的根级别容器,直接继承于Container
。同时是 WebGL-optimized 的
所以 Stage
和 StageGL
到底有多大差别呢?
来 “抖” 个简单的试验!
形单影只的“抖”
随便从网上找了一张像素小人图(如存在版权问题,还请告知…)
做成了SpriteSheet图
然后让他在canvas中“抖”起来
此处用的 Stage
,帧频基本保持在 60 fps
无压力
只不过诺大的画布上,“他”好寂寞…
核心代码
// function init()
// 构建舞台 & 加载图片
stage = new createjs.Stage("examCanvas")
loader = new createjs.LoadQueue(false)
loader.addEventListener('complete', handleComplete)
loader.loadManifest(
[{
src: 'mansheet.png', id: 'man'
}],
true, '../_assets/img/')
// function handleComplete()
// 创建sprite动画
let spriteSheet = new createjs.SpriteSheet({
'images': [loader.getResult('man')],
'frames': { 'width': 160, 'height': 280, 'count': 2, 'regX': 80, 'regY': 140 },
'animations': {
'play': [0, 1, 'play', 0.5]
}
})
let man = new createjs.Sprite(spriteSheet, 'play')
man.setTransform(Math.random() * 960, Math.random() * 400, 0.1, 0.1)
stage.addChild(man)
createjs.Ticker.timingMode = createjs.Ticker.RAF
createjs.Ticker.addEventListener("tick", tick)
// function tick()
// 随时间变化获取fps & 刷新stage
let fps = Math.round(createjs.Ticker.getMeasuredFPS())
stage.update()
来5000个一块“抖”
将代码中构建 Sprite
实例 man
的区域循环 5000
次
就变成了大家一起来high的样子,好温(膈)暖(应)????
此时独显的风扇开始狂吹…
同时,fps
徘徊在 30
左右,小人们的动作变慢了????
核心代码
for (let i = 0; i < 5000; i++) {
let man = new createjs.Sprite(spriteSheet, 'play')
man.setTransform(Math.random() * 960, Math.random() * 400, 0.1, 0.1)
stage.addChild(man)
}
StageGL出场,平滑且安静的“抖”
只需要做小小的调整,fps
就再次重回高地,且风扇也不转了????
不过你发现没有
画布上的 fps
标签没有了
核心代码
// stage = new createjs.Stage("examCanvas")
stage = new createjs.StageGL("examCanvas")
对比调整
按官方的说法,StageGL
可以充分利用GPU在优化内容
但这其实这只是 Stage
和 StageGL
最基本的区别
官方给出的 StageGL
显著特点
- Intelligent batching, with multiple textures in a batch, using the full number available on your hardware
- 智能批处理,每批次处理多种纹理,利用全部可用硬件
- No restrictions on display list order
- 显示列表顺序无限制
- Automatic GPU memory management
- 自动GPU内存管理
- Full cache support
- 全缓存支持
- Full filter support
- 全过滤器支持
- Canvas 2D Stage fallback
- 在不支持WebGL的设备上,自动呈现Canvas 2D Stage
StageGL
的使用限制
-
Shape
、Shadow
和Text
均不会显示 - 想要显示上述无法渲染的内容,需要通过
cache
缓存 - 图像会被包装成
WebGL
的纹理,每个图形卡的并发纹理有限制,过多的纹理会明显降低性能 - 每个
cache
都算作一个单独的纹理。建议使用SpriteSheet
和SpriteSheetBuilder
来减少纹理数量 - 在多个
StageGL
实例间使用图像节点(DOM Image
/Canvas Element
),必须是一个clone
- 如果在创建StageGL实例后调整画布大小,必须调用
updateViewport
- 最佳性能将来自手动管理纹理内存,但默认情况下会自动处理
因此,针对 StageGL
中 Shape
和 Text
不显示的问题,只需要调整几句代码即可
核心代码
// function handleComplete()
// 在定义完shape和text后,进行cache
fpsLabel.cache(0, 0, 960, 400)
fpsBack.cache(0, 0, 960, 400)
// function tick()
// 随时间变化,同时还要updateCache
fpsLabel.updateCache()
完整代码
<!-- PerformanceGL.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>EaselJS: Performance</title>
<link href="../_assets/css/shared.css" rel="stylesheet" type="text/css" />
<script src="../lib/easeljs-NEXT.js"></script>
<script src="../lib/preloadjs-NEXT.min.js"></script>
<script>
let stage, loader, fpsLabel
function init() {
// 利用StageGL实现
stage = new createjs.StageGL("examCanvas")
loader = new createjs.LoadQueue(false)
loader.addEventListener('complete', handleComplete)
loader.loadManifest(
[{
src: 'mansheet.png', id: 'man'
}],
true, '../_assets/img/')
}
function handleComplete() {
let spriteSheet = new createjs.SpriteSheet({
'images': [loader.getResult('man')],
'frames': { 'width': 160, 'height': 280, 'count': 2, 'regX': 80, 'regY': 140 },
'animations': {
'play': [0, 1, 'play', 0.5]
}
})
for (let i = 0; i < 5000; i++) {
let man = new createjs.Sprite(spriteSheet, 'play')
man.setTransform(Math.random() * 960, Math.random() * 400, 0.1, 0.1)
stage.addChild(man)
}
fpsLabel = new createjs.Text("@ -- fps", "bold 20px Arial", "#000");
fpsBack = new createjs.Shape(
new createjs.Graphics().beginFill('#fff').drawRect(0, 0, 100, 20)
)
fpsLabel.cache(0, 0, 960, 400)
fpsBack.cache(0, 0, 960, 400)
fpsLabel.x = fpsBack.x = 10;
fpsLabel.y = fpsBack.y = 20;
stage.addChild(fpsBack, fpsLabel)
createjs.Ticker.timingMode = createjs.Ticker.RAF
createjs.Ticker.addEventListener("tick", tick)
}
function tick() {
let fps = Math.round(createjs.Ticker.getMeasuredFPS())
fpsLabel.text = ` @ ${fps} fps`
fpsLabel.updateCache()
stage.update()
}
</script>
</head>
<body onload="init()">
<header class="Nora7aki">
<h1>性能测试 performace</h1>
<p>
通过<code>StageGL</code>渲染的5000个动画
</p>
</header>
<div class="content" style="overflow: hidden;width: 960px;height: 400px">
<canvas id="examCanvas" width="960" height="400"></canvas>
</div>
</body>
</html>
<!-- PerformanceGL.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>EaselJS: Performance</title>
<link href="../_assets/css/shared.css" rel="stylesheet" type="text/css" />
<script src="../lib/easeljs-NEXT.js"></script>
<script src="../lib/preloadjs-NEXT.min.js"></script>
<script>
let stage, loader, fpsLabel
function init() {
// 利用Stage实现
stage = new createjs.Stage("examCanvas")
loader = new createjs.LoadQueue(false)
loader.addEventListener('complete', handleComplete)
loader.loadManifest(
[{
src: 'mansheet.png', id: 'man'
}],
true, '../_assets/img/')
}
function handleComplete() {
let spriteSheet = new createjs.SpriteSheet({
'images': [loader.getResult('man')],
'frames': { 'width': 160, 'height': 280, 'count': 2, 'regX': 80, 'regY': 140 },
'animations': {
'play': [0, 1, 'play', 0.5]
}
})
for (let i = 0; i < 5000; i++) {
let man = new createjs.Sprite(spriteSheet, 'play')
man.setTransform(Math.random() * 960, Math.random() * 400, 0.1, 0.1)
stage.addChild(man)
}
fpsLabel = new createjs.Text("@ -- fps", "bold 20px Arial", "#000");
fpsBack = new createjs.Shape(
new createjs.Graphics().beginFill('#fff').drawRect(0, 0, 100, 20)
)
stage.addChild(fpsBack, fpsLabel);
fpsLabel.x = fpsBack.x = 10;
fpsLabel.y = fpsBack.y = 20;
createjs.Ticker.timingMode = createjs.Ticker.RAF
createjs.Ticker.addEventListener("tick", tick)
}
function tick() {
let fps = Math.round(createjs.Ticker.getMeasuredFPS())
fpsLabel.text = ` @ ${fps} fps`
stage.update()
}
</script>
</head>
<body onload="init()">
<header class="Nora7aki">
<h1>性能测试 performace</h1>
<p>
通过<code>Stage</code>渲染的5000个动画
</p>
</header>
<div class="content" style="overflow: hidden;width: 960px;height: 400px">
<canvas id="examCanvas" width="960" height="400"></canvas>
</div>
</body>
</html>
码字不易,如果喜欢,不用三连,点个赞????便是最大的鼓励
欢迎关注微信公众号 "书咖里的曼基康"
上一篇: JavaScript中的面向对象
下一篇: Pygame基础之 精灵(一):基本概念