-
Creator 版本:2.0.4
-
目标平台: h5
下图代码,基于官方代码小修改了下,普通手机和苹果手机都很流畅,反而比较高端点的安卓机,小米6一加5等会特别特别卡,甚至会卡停音乐。
capture-web.rar (1.8 KB)
Creator 版本:2.0.4
目标平台: h5
下图代码,基于官方代码小修改了下,普通手机和苹果手机都很流畅,反而比较高端点的安卓机,小米6一加5等会特别特别卡,甚至会卡停音乐。
对比过不同手机渲染方式,都是webgl的渲染方式(除了苹果咯),也改过opengl的渲染方式还是依旧卡顿。
真的卡顿巨型严重好几秒的那种,奇怪的是low点的手机反而不会卡,用同样的手机测白鹭的截图一点也不会卡顿。
刚刚试了升级cocoscreator到2.07还是一样的卡。
大家都没遇到过这种问题么,截图这种需求挺常见,不然好多项目都用不了cocos了
不好意思,没有很明白是什么意思,能详细说下么,我这里给renderTexture是设置的this.node的高宽呀。
我之前的表述不是问题所在,实际问题出现在this.node.width 和 this.node.height这两位数是浮点数值
texture.readPixels()获取到的像素数组元素是非常多的。
let start = srowwidth4;
for (let i = 0; i < rowBytes; i++) {
imageData.data[i] = data[start+i];
//这里由于浮点数的下标所以这个元素是undefined的,双重for循环下imageData.data的值一会变成undefined,一会变成0,已造成运算压力。
}
建议向下取整:let start = Math.floor(srowwidth4);
改过来了,但是并未改善,这个奇怪的地方是部分高端的安卓机会卡,其他的手机其实都很快。
感觉是这里绘图导致的,我尝试直接截取canvas不绘制就一点都不卡。
我一会再安卓上测试看下
多谢!截的图片越大卡顿越明显,我这边已知会卡的手机有 一加6,魅蓝Note6,小米5,还有一个华为的忘记什么型号了。
我在小米 MIX 2S上测试没有出现问题,在安卓高版本和低版本的机型截图耗时都差不多
不是安卓版本的问题,是手机类型,很明显的卡顿好几秒的那种仅仅只是手机不同,大佬可以试试我说的那几款手机。
我也遇到过同样问题,以下是直接的部分分析见解(主要针对FB Instant Game)
截图耗时主要有几个地方(微信好像不用第二、三步的样子)
其中,第2步,参考两种对比写法
// 接下来就可以对这些数据进行操作了
// 创建一个新的画布
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
canvas.width = width;
canvas.height = height;
// 将刚刚的渲染数据渲染到新的画布上
// 图片用32bit位表示一个像素,所以一行有width个像素,一共是width*32/8bit = width*4字节
let rowBytes = width * 4;
let s3 = new Date().getTime();
// 依次读取图片里的每行数据,放入到ctx中。
for (let row = 0; row < height; row++) {
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// DEMO 写法(高性能,兼容性好)
// 设置开始行为最下面那行
// 因为 RenderTexture 得到的纹理是上下翻转的,所以需要旋转回来
// 在这里几位从最下面的行开始读取图片数据
let srow = height - 1 - row;
// 从图片的所有数据中,获取一行的图片字节数据
let oneLineImageData = new Uint8ClampedArray(textureData.buffer, Math.floor(srow * width * 4), rowBytes);
// 设置图片数据对象
// 设置一个一行的图片,所以就是 width, 1
let imageData = new ImageData(oneLineImageData, width, 1);
ctx.putImageData(imageData, 0, row);
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// // 官网文档 写法(在iPhone5机器上 ctx.createImageData 得到的对象是不能直接通过读取 .data 属性赋值的, 因为该属性为只读,所以是不能写入到数据导致没有截图数据)
// // 设置开始行为最下面那行
// // 因为 RenderTexture 得到的纹理是上下翻转的,所以需要旋转回来
// // 在这里几位从最下面的行开始读取图片数据
// let srow = height - 1 - row;
// // 设置图片数据对象
// // 设置一个一行的图片,所以就是 width, 1
// let imageData = ctx.createImageData(width, 1);
// // 从最下面那行的第一个字节开始读
// // 下标是从0开始, srow* width * 4 则刚刚好为最下面那行的第一个字节
// let start = srow * width * 4;
// for (let i = 0; i < rowBytes; i++) {
// imageData.data[i] = data[start + i];
// }
// ctx.putImageData(imageData, 0, row);
// if (row == 0) {
// console.log(`imageData:`);
// console.log(imageData);
// }
}
if (CC_DEBUG) {
cc.log(`生成截图耗时: ${new Date().getTime() - s3} ms`);
}
同一个手机
没仔细测试,只是简单对比了手头上的几台手机,其他手机情况未知
这个是MDN统一方法,没解的样子,除非我们自己重写一遍,不然就是完全阻塞,想到一个绕一点的方法,截图数据分几次读取,比如截好图之后,分多次去读取数据,每次读取数据耗时控制在8ms左右,一帧还剩下8ms交给Loading菊花去转,或者音乐播放之类
感谢大佬,刚刚用大佬修改了下,速度的确快了不少,还没上真机测试等会看看能不能解决部分手机卡的问题。
刚刚上真机试了试,可惜还是卡顿,但是已经快了大约40%了。同时对比了调整了Canvas.toDataUrl的质量到0.3和默认对真机的影响,对卡的那几种手机影响几乎感觉不到。感觉不是这个方向的问题,怕是手机渲染硬件导致的问题
补充一点,一开始设置截图大小的时候就要向下取整截图尺寸,这是因为截图尺寸的宽高有可能是浮点数,那么读出来的内容就可能出现越界问题,即便后面 start 那里向下取整调整回来,也会有问题,我也是找了好久才知道,Anyway
using the following code, you may see the screenshot on iPhone 5 like this:
// Getting view rect size.
let visibleSize = cc.view.getVisibleSize();
let width =visibleSize.width;
let height = visibleSize.height;
// 新建一个 RenderTexture,并且设置 camera 的 targetTexture 为新建的 RenderTexture,这样 camera 的内容将会渲染到新建的 RenderTexture 中。
let renderTexture = new cc.RenderTexture();
// 初始化纹理大小,如果截图内容中不包含 Mask 组件,可以不用传递第三个参数
renderTexture.initWithSize(width, height, cc.game._renderContext.STENCIL_INDEX8);
this.camera.targetTexture = renderTexture;
after using Math.floor , everything is fine:
// Getting view rect size.
let visibleSize = cc.view.getVisibleSize();
let width = Math.floor(visibleSize.width);
let height = Math.floor(visibleSize.height);
// 新建一个 RenderTexture,并且设置 camera 的 targetTexture 为新建的 RenderTexture,这样 camera 的内容将会渲染到新建的 RenderTexture 中。
let renderTexture = new cc.RenderTexture();
// 初始化纹理大小,如果截图内容中不包含 Mask 组件,可以不用传递第三个参数
renderTexture.initWithSize(width, height, cc.game._renderContext.STENCIL_INDEX8);
this.camera.targetTexture = renderTexture;
剩下的应该是 Canvas.toDataUrl 那块的卡顿了,你可以测试一下那里的耗时,如果真的是这里耗时了,你可以参考下我上面说到的应对思路,就是比较绕。。。
好的多谢!