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

所以 StageStageGL 到底有多大差别呢?
“抖” 个简单的试验!


形单影只的“抖”

随便从网上找了一张像素小人图(如存在版权问题,还请告知…)
像素小人图
做成了SpriteSheet图
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的样子,好温(膈)暖(应)🤣
一起high-stage
此时独显的风扇开始狂吹…
同时,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出场,平滑且安静的“抖”

stagegl
只需要做小小的调整,fps 就再次重回高地,且风扇也不转了😏

不过你发现没有
画布上的 fps 标签没有了

核心代码

// stage = new createjs.Stage("examCanvas")
stage = new createjs.StageGL("examCanvas")

对比调整

按官方的说法,StageGL 可以充分利用GPU在优化内容
但这其实这只是 StageStageGL 最基本的区别

官方给出的 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 的使用限制

  • ShapeShadowText 均不会显示
  • 想要显示上述无法渲染的内容,需要通过 cache 缓存
  • 图像会被包装成 WebGL 的纹理,每个图形卡的并发纹理有限制,过多的纹理会明显降低性能
  • 每个 cache 都算作一个单独的纹理。建议使用 SpriteSheetSpriteSheetBuilder 来减少纹理数量
  • 在多个 StageGL 实例间使用图像节点(DOM Image/Canvas Element),必须是一个 clone
  • 如果在创建StageGL实例后调整画布大小,必须调用 updateViewport
  • 最佳性能将来自手动管理纹理内存,但默认情况下会自动处理

因此,针对 StageGLShapeText 不显示的问题,只需要调整几句代码即可

核心代码

// function handleComplete()
// 在定义完shape和text后,进行cache
fpsLabel.cache(0, 0, 960, 400)
fpsBack.cache(0, 0, 960, 400)

// function tick()
// 随时间变化,同时还要updateCache
fpsLabel.updateCache()

完整代码

Github - Performance

<!-- 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>
<!-- Performance.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>

码字不易,如果喜欢,不用三连,点个赞👍便是最大的鼓励
欢迎关注微信公众号 "书咖里的曼基康"
书咖里的曼基康

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值