关于自动合图导致的uv变化问题,还有 drawcall 如何减少求助。

项目中要加载很多用户网络图片。每一个图片的结构是这样的。
bigContainer
- avatarImage-1
- avatarImage-2

然后 avatarImage 要实现圆角效果,borderImage 是边框。

最初想的很简单,就使用自带的 mask 组件。 但是自测的时候发现自带的mask 会导致 drawcall 变得很大。于是放弃使用mask组件。
后来想着要不学学shader做一个简单的mask组件。做完了之后发现,在编辑器下是能够成功实现圆角效果的。那么项目跑起来。
1.问题来了,项目跑起来之后发现渲染的奇奇怪怪的,后来去社区看了看发现是自动和合图导致的uv变化,没办法最简单的办法就是当网络图片加载成功之后,给 spriteFrame 的 packable 设置为false。这样做完项目运行起来是正常的,但是drawcall也会增加, 每张图片增加一个dc。 这样做虽然比mask组件要好不少,但是我还是想要进一步减少dc。
2.无奈, 这样的话就只能还是打开动态合图功能, 不然就不可能减少dc。那该怎么办呢, 继续逛社区。发现有一个大佬@渡鸦说可以传入 uv ,然后经过转换能够得到原始的uv。我很兴奋,于是 cv 了一下大佬的代码。本质是定义一个 uniform 然后每张图片传入自己在大图中的顶点 uv 位置给 shader。ok, 项目运行起来,效果正常。 但是 drawcall 还是没有减少。 我对 drawcall 不是很熟悉, 猜测是每一个图片传入自己的顶点 uv 给shader 导致打断了合批功能。

以上的是最近几天的经历, 如果有什么位置说的不对的欢迎大佬指正。
然后我想问问,就是有没有什么办法,能够做到将方形图片变成圆形的,同时不会让dc增加的方案。

dc不能合批是因为用了不同的材质球,用同一个定制材质球,通过参数控制,就可以合批了

是的, 现在问题就是使用相同的材质球就无法使用动态合图功能, 因为每张图片的 uv 不一样。这样会导致dc增加。 然后如果使用动态合图功能, 那就无法使用同一个材质球了, 必须要动态传入 uv。

手动合图吧。动态合图没办法做到这一点。

大佬, 手动合图和动态合图有什么区别吗,手动合图如何做到统一材质问题呢。因为感觉他们的 uv 还是需要动态传入呀。 能方便解答一下吗

目前加载的是网络图片

const frame = this.sprite.spriteFrame;
// xMin
const l = frame.uv[0];
// xMax
const r = frame.uv[6];
// yMax
const b = frame.uv[3];
// yMin
const t = frame.uv[5];
// 纹理在合图中的四个边界 uv 坐标
const u_uvOffset = new Vec4(l, t, r, b);
// 纹理是否旋转
const u_uvRotated = frame.rotated ? 1.0 : 0.0;
const material = this.sprite.getMaterialInstance(0);
// 设置材质的属性
material.setProperty(‘u_uvOffset’, u_uvOffset);
material.setProperty(‘u_uvRotated’, u_uvRotated);
实时去新的uv,传进去shader自己转换一下

谢谢, 这个我是用过, 可以实现。但是这样的话, shader 就不是一个实例了, 每一个 shader 的 uv 都是动态传入转换的, 还是会导致drawcall增加。

动态合图只能用默认材质才能合批。手动/自动合图的话合批只取决于材质是否相同。

好的 我去试试看

这个是可以的,我实现过。
我分享过一个下载远程图片做了类shader操作后的分享。
参考这个:【分享】远程图片加载,加类shader操作后动态合批 (这个适用用web,如果你要原生运行需要自己实现)

比如用户头像在这里都做了圆角操作后,就可以用默认的shader正常合批了,接着打开动态合图就合批了。

1赞

谢谢您的分享, 看了你的代码我非常有收获

本来材质是一样的,然后我获取材质(这时候默认会复制一份)改变某些参数这时候还能合批吗?

那就不能了