Cocos纹理格式与压缩纹理选型:显存优化与真机避坑指南

发布时间:2026/9/30 12:09:35
Cocos纹理格式与压缩纹理选型:显存优化与真机避坑指南
做 Cocos 项目做到中后期十有八九会被纹理格式和压缩纹理这两件事卡住一次。前期在编辑器里跑得好好的一打真机包就发现内存飙到崩溃、部分机型贴图发黑、透明区域变成黑块、渐变图出现一圈圈色带——这些问题追根溯源基本都落在同一个地方贴图用了什么格式、有没有走压缩纹理、压缩格式和机型是否匹配。这篇就把 Cocos 里纹理格式和压缩纹理这条链路从头捋一遍包括每种格式的内存账怎么算、Creator 3.x 和 2.x 的配置入口有什么区别、怎么给不同平台做选型以及那些文档里不写、但真机上一定会遇到的坑。不管你是刚接触 Cocos Creator 的新手还是已经带过完整项目的老手只要项目里贴图数量上了规模这篇里的内容大概率能帮你省下几次通宵排查。1. 纹理格式到底在解决什么问题1.1 先算一笔实在的内存账很多人第一次意识到纹理格式重要是在真机内存告警的那一刻。游戏里一张 2048×2048 的图看起来就是个普通背景但如果用默认的 RGBA8888 存进显存它占的空间是 2048×2048×4 字节也就是 16MB。这还只是单张一个中重度项目里几十上百张贴图叠起来几百 MB 显存就这么没了。关键点是显存占用跟文件大小完全不是一回事。你在电脑上看到的 PNG 可能只有 800KB但 GPU 不认识 PNG它拿到的是解码后的原始像素数据。PNG 的压缩只在磁盘和传输阶段起作用一旦进入显存它就是按每像素多少位来算的。所以「图片文件不大」这个认知在移动端游戏里经常是致命的误导。我给你一段小脚本可以直接拿来评估不同格式的差距尺寸和格式随便改// 计算不同格式下纹理占用的显存单位 MB function textureMemory(w, h, bitsPerPixel) { return (w * h * bitsPerPixel) / 8 / 1024 / 1024; } const w 2048, h 2048; console.log(RGBA8888 :, textureMemory(w, h, 32).toFixed(2), MB); console.log(RGB565 :, textureMemory(w, h, 16).toFixed(2), MB); console.log(RGBA4444 :, textureMemory(w, h, 16).toFixed(2), MB); console.log(ETC1/ETC2:, textureMemory(w, h, 4).toFixed(2), MB); console.log(PVRTC 2bpp:, textureMemory(w, h, 2).toFixed(2), MB); console.log(ASTC 6x6 :, textureMemory(w, h, 128 / 36).toFixed(2), MB);跑一遍你就明白差距有多夸张同一张 2048×2048 的图RGBA8888 是 16MBETC2 是 4MBPVRTC 2bpp 只要 2MB。也就是说选对格式这件事直接决定了你的项目能不能在中低端安卓机上活下来。这里面没有任何玄学全是小学算术。1.2 压缩纹理的本质是「用画质换内存和带宽」理解了内存账再理解压缩纹理就顺了。GPU 平时不干别的它做的是海量的并行取像素操作纹理带宽是它的命脉。压缩纹理的核心思路是让 GPU 直接在压缩状态下采样不用先解压成 RGBA8888 再算。这样做有三个直接好处显存占用成倍下降、采样带宽下降、CPU 侧的加载压力也变小。代价当然是画质。压缩纹理是有损的尤其是低比特率的格式会出现色块、边缘噪点、渐变色带。还有一个隐形成本平台兼容性。不同 GPU 支持的压缩格式不一样iOS 和安卓、安卓内部的高通和联发科、老机型和旗舰机能吃的格式都不同。这就逼着你在构建时给每个平台准备多套贴图运行时按机型能力挑一套加载。所以压缩纹理不是「开了就完事」的开关它是一个需要规划的资源策略。你要想清楚哪些图值得压、压到什么程度、面向哪些机型、首包和热更包怎么分。想不清楚就会出现「压完画质崩了」或者「压了但部分机型加载失败」这类两头不讨好的情况。1.3 什么样的项目该认真对待这件事不是所有项目都需要大动干戈。如果是一个界面简单、贴图总量不到 20MB 的小游戏用默认 RGBA8888 加合理裁剪尺寸就够了强行上压缩纹理反而增加构建复杂度和兼容风险。但只要满足下面任意一条就建议把压缩纹理正式排进构建流程贴图总量超过 60MB或者有大量 2048 级别的大图面向中低端安卓机内存敏感有大量场景、角色、特效贴图需要动态加载需要控制首包体积走分包或热更项目要长期迭代资源会持续增长我自己的经验是在项目立项阶段就把纹理规范定下来最省事美术出图尺寸上限、命名规则、哪些图走压缩、哪些图保持无损一次性约定好比后期返工抢救要轻松十倍。等美术已经产出了几百张图再来改格式那才叫真正的痛苦。2. 主流纹理格式逐个拆解与选型2.1 未压缩格式RGBA8888、RGB565、RGBA4444未压缩格式是引擎的保底选项任何设备都能用代价是显存。RGBA8888 是标准配置每个通道 8 位总共 32 位画质最好适合图标、UI、需要精确颜色的小图以及那些对压缩瑕疵极其敏感的图比如带细线条的 UI、文字图集。RGB565 砍掉了 alpha 通道红色和蓝色各 5 位、绿色 6 位绿色多一点是因为人眼对绿色更敏感。它适合确定不需要透明的图比如不透明背景、纯色遮罩显存直接省一半。但要注意565 在渐变和暗部会有明显的色阶断裂深色渐变图用它会很难看。RGBA4444 保留了 alpha但每个通道只有 4 位颜色精度损失明显容易出现脏色和色带。它适合那些本身颜色简单、又需要透明的图比如纯色带透明边的粒子但用来做精细 UI 基本是自找麻烦。这三种格式在 Cocos 里通常作为「不压缩平台」的兜底也就是当你选定的压缩格式在当前设备上不被支持时的降级方案。所以即使你主推压缩格式也必须给未压缩格式留一个位置否则在个别老设备上会直接加载失败。2.2 压缩格式ETC1、ETC2、PVRTC、ASTC、DXT这几种是真正的主角我按实际使用频率来拆。ETC1是移动端最普及的格式4 位每像素显存只有 RGBA8888 的八分之一。但它最大的问题是完全不支持 alpha 通道。这意味着任何带透明的图用 ETC1 压完透明区域会变成黑色或直接丢失。所以 ETC1 只能用在确定不透明的图上比如地面、不透明背景、纯色遮罩。安卓上它几乎是全设备通吃这也是它至今没被淘汰的原因。ETC2是 ETC1 的升级版支持 alpha同样是 4bpp。它在 OpenGL ES 3.0 及以上的设备上支持覆盖了现在绝大多数安卓机。对 Cocos 项目来说ETC2 基本是安卓平台的默认首选。唯一要留意的是极个别老设备只支持 ES 2.0那就得靠 ETC1 兜底。PVRTC是 iOS 平台特有的格式分 2bpp 和 4bpp 两档画质上 2bpp 相当激进4bpp 勉强能接受好处是显存占用极低。但它有个硬性约束非常容易踩坑要求贴图必须是 2 的幂尺寸而且最好接近正方形。你把一张 500×300 的图丢给 PVRTC结果要么报错、要么被强制拉伸画质直接崩。所以 iOS 项目里凡是走 PVRTC 的图美术规范里必须强制 2 的幂。ASTC是现在最推荐的格式最大的优势是块大小可调从 4×4 到 12×12 有十几档可选。块越小画质越好、显存越大块越大越省、画质越糊。4×4 大约是 8bpp6×6 约 3.56bpp8×8 约 2bpp。它画质好、灵活度高苹果从 A8 之后、安卓中高端机也基本都支持。现在很多项目的做法是iOS 首选 ASTC安卓上支持 ASTC 的用 ASTC不支持的降级到 ETC2 或 ETC1。DXTBC 系列主要在桌面平台移动端基本用不上Cocos 打包桌面或部分模拟器场景会接触到。了解即可不作为移动端重点。2.3 各平台选型对照表把上面的信息整理成一张表构建时对着填预设就行平台首选格式备选/兜底关键约束iOSASTC 6×6PVRTC 4bpp、RGBA8888PVRTC 必须 2 的幂安卓高端ASTC 6×6 / 8×8ETC2需检测设备支持安卓中低端ETC2ETC1、RGBA8888ETC1 无 alpha微信小游戏KTX2 / 不压缩RGBA8888平台能力受限Web/H5KTX2Basis/ 图片格式RGBA8888兼容性优先有一点要特别说明格式优先级列表是要按顺序填的运行时从前往后挑第一个当前设备支持的格式。表里第一位是首选后面是降级。很多人配置时把顺序填反导致明明支持 ASTC 的机型也走了最低画质画质白白损失。注意给带透明的图配 ETC1或者给非 2 的幂的图配 PVRTC是新手最常见的两个致命配置构建能过运行时出问题。配置完一定要真机验证。3. Cocos 里配置压缩纹理的完整流程3.1 Creator 3.x 的配置入口与预设Cocos Creator 3.x 把压缩纹理做成了「预设Preset」机制。整体流程是先建一个预设在预设里为每个平台指定一串格式优先级然后把预设挂到具体的贴图资源上。这样做的好处是同一套策略可以复用到大量资源改一次全生效。具体操作路径大体是打开构建发布面板找到「压缩纹理」相关的配置区域不同小版本入口位置略有差异有的在构建面板的独立标签页有的整合进项目设置里新建一个预设并命名比如叫common或者ui_hq。然后在预设里逐平台勾选格式并把顺序拖成你想要的优先级。一个我常用的预设划分思路是这样的common普通场景贴图安卓 ETC2 优先、ETC1 兜底iOS ASTC 6×6 优先ui_hqUI 和图标画质优先ASTC 4×4 或干脆不压缩opaque_bg大背景不透明走 ASTC 8×8 或 ETC1压缩率拉满no_compress需要像素级精确的图直接 RGBA8888预设建好后选中贴图资源在 Inspector 面板里会有一个压缩纹理预设的下拉选项选上对应的预设即可。如果某个资源没手动指定就会走默认策略。这就是为什么建议先把默认策略配好避免漏网之鱼。3.2 Creator 2.x 的差异与迁移注意如果你还在用 Creator 2.x配置方式和 3.x 有区别。2.x 的压缩纹理配置通常集中在构建发布面板里直接为安卓、iOS 等平台设置格式优先级列表粒度更粗没有 3.x 那种可复用的预设概念。也就是说2.x 里你只能设置平台的全局策略做不到「同一张图在 A 场景用高画质、在 B 场景用低画质」。从 2.x 迁移到 3.x 的时候最容易出问题的地方就在这里资源级覆盖。2.x 里可能一张图一直是全局策略迁到 3.x 后如果预设挂错格式会发生变化。我的做法是迁移后跑一次资源审计把所有贴图当前的压缩预设列出来过一遍重点检查带透明和渐变的图。另外 2.x 和 3.x 在资源导入的默认设置上也不完全一样比如默认的 Filter Mode、Mip Filter、Packable 勾选状态。迁移项目建议不要一股脑全接受默认值而是对照老项目的设置逐项核对。3.3 单个资源的覆盖设置除了全局预设单个贴图在 Inspector 里还有一堆影响最终效果的开关这些和压缩纹理是配套使用的Packable是否参与自动图集打包。大图一般不勾小图建议勾上减少 draw call。Filter Mode采样过滤方式Point 适合像素风Bilinear/Trilinear 适合写实。Wrap Mode超出 UV 范围时的平铺方式。Mip Filtermipmap 的生成策略这个后面单独说。压缩纹理预设就是前面说的绑定哪套策略。这里有个经验不要指望全局预设解决一切。UI 图、字体图集、法线贴图、特效序列帧这四类图的诉求完全不同。UI 要清晰、字体图集几乎是像素级精确、法线贴图是数据不是颜色、序列帧要省内存。把它们分到不同的预设里比一刀切效果好得多。3.4 一次真实的参数计算与配置示例举个具体例子。假设项目里有一张 2048×2048 的场景背景图不透明一张 1024×1024 的 UI 底图带半透明白色渐变还有一批 512×512 的角色贴图带 alpha。按预算来算如果背景图走 ASTC 8×8显存约 (2048×2048×2)/8/1024/1024 1MB走 RGBA8888 则是 16MB。一张图差 15MB十张就是 150MB这个差距在低端机上就是「能跑」和「闪退」的区别。配置上我会这么做背景图挂opaque_bg预设安卓优先 ETC1iOS 优先 ASTC 8×8UI 底图挂ui_hq预设因为带渐变绝不能压太狠安卓走 ETC2iOS 走 ASTC 4×4角色贴图挂common预设ETC2 优先配完不要直接打正式包先出一个测试包在真机上跑一遍重点看渐变有没有色带、透明边缘有没有黑边、内存曲线是否平稳。这一步省不得压缩纹理的画质问题在编辑器里往往看不出来必须真机。# 出包后建议用真机性能面板观察内存重点看 GPU 纹理内存曲线 # 如果某张图切换预设后内存变化异常优先怀疑它没走压缩格式4. 常见报错与排查技巧实录4.1 Blender 里正常、Cocos 里报错或变黑这是被问得最多的一类问题模型贴图在 Blender 里看着好好的一进 Cocos 就报错或者显示异常。我梳理下来原因基本集中在这几个点第一是尺寸问题。Blender 里的图可能不是 2 的幂甚至不是 4 的倍数。走 ASTC 时块对齐可能导致尺寸被裁走 PVRTC 时直接不满足要求。排查方法很简单翻一下图片的实际像素尺寸改成 2 的幂或至少 4 的倍数再看。第二是色彩空间和通道。Blender 导出的贴图如果是 HDR、16 位或 32 位浮点Cocos 的常规导入流程可能不支持表现就是加载失败或颜色完全错乱。另外单通道灰度图、去掉 alpha 但内容依赖 alpha 的图也会出问题。最稳妥的做法是导出前统一转成 8 位 RGB/RGBA。第三是文件本身有问题。贴图损坏、ICC 配置文件异常、元数据过大都会让引擎加载时抛错。这种情况用图像工具重新导出一遍通常就好了。第四是alpha 用错格式。贴图带透明但预设里给了 ETC1透明区域直接变黑。表现就是「Blender 里边缘透明Cocos 里边缘一圈黑」。改预设或补一层 alpha 通道即可。第五是模型材质配置问题。有时候不是贴图本身的问题而是模型的材质在 Blender 里引用了多个图片节点Cocos 导入后 UV 或材质槽对不上看起来像贴图错了。这种情况检查一下模型的材质球数量和贴图映射关系。排查这类问题我的顺序是先看尺寸再看通道和位深再看格式预设最后看模型材质。按这个顺序走九成问题能定位。4.2 色班、脏边、透明丢失压完之后画质出问题是压缩纹理的必然风险关键是怎么把损失压到可接受范围。渐变色带最容易出现在天空盒、光晕、纯色渐变底图上。低比特率格式把连续的颜色量化成了有限的色阶肉眼就看到一圈圈的分层。解决办法是把这类图单独拎出来用高画质格式比如 ASTC 4×4或者干脆不压缩。这个取舍值得做因为渐变一旦有色带整个画面的廉价感就上来了。透明边缘脏边是图集打包和采样共同造成的。图集中相邻图元的像素在采样时会互相污染尤其是走 mipmap 之后。常见做法是给图集的每张子图留 padding并在导出时做边缘扩散dilate。这是图集工具的配置项别忽略。透明丢失前面说过本质是格式不支持 alpha。带透明的图务必用 ETC2、ASTC、PVRTC 或 RGBA 系格式避开 ETC1。4.3 内存没降反升、首包变大压完之后发现内存没降甚至涨了这种情况也有。原因通常是生成了多套格式的贴图但都被打进了包。比如你给安卓配了 ETC2 和 ETC1 两套构建时如果选择了全部打包包体就会显著变大加载时还要挑出错概率也高。正确的做法是明确每个平台只打必要的那一两套格式多余的降级格式按需保留。首包和分包要分开规划常用资源进首包大图和大场景资源进分包按需下载。这样既控制了首包体积也没浪费内存。还有一个容易忽略的点mipmap 会额外增加约三分之一的显存。你算出来一张图占 4MB但如果开了 mipmap实际占用会上升到大约 5.33MB。所以算预算是不能只算基础尺寸要把 mipmap 算进去。4.4 问题速查表把高频问题整理成表出问题时直接对号入座现象最可能原因处理方式透明区域变黑用了 ETC1换 ETC2/ASTC加载报错、贴图不显示尺寸非 2 的幂、位深异常转 2 的幂、转 8 位渐变色带明显压缩率过高提高画质格式或不压缩边缘有脏边图集无 padding补 padding、做 dilate内存没降反升多套格式全打包精简格式、分包部分机型画质差降级格式画质低检查格式优先级顺序真机加载慢首次解码大图加 mipmap、改尺寸5. 进阶细节mipmap、sRGB、图集与 Shader 采样5.1 mipmap 不是可选项mipmap 是一组逐级缩小的同图副本作用是解决远处贴图的闪烁和摩尔纹同时提升采样效率。很多人为了省内存把 mipmap 关了结果远景贴图疯狂闪烁反而更难看。我的建议是3D 场景里的物体贴图开 mipmapUI 图可以关。UI 通常是 1:1 或固定缩放显示mipmap 没多大意义还平白多占三分之一显存。在 Cocos 里贴图的 Mip Filter 选项控制生成策略。开了之后要注意压缩格式的 mipmap 生成规则和未压缩不同某些压缩格式的自定义 mipmap 需要专门处理。如果用的是 ASTC 或 ETC2一般交给引擎自动生成就好不要手动去生成 mip 链容易出问题。5.2 色彩空间sRGB 与线性这是很多画质问题的隐藏根源。颜色贴图albedo、漫反射应该按 sRGB 处理而数据贴图法线、粗糙度、金属度、遮罩必须按线性空间处理。如果法线贴图被当成 sRGB 读取光照会明显不对看起来发灰或者方向感怪异反过来颜色贴图按线性读整体会偏亮泛白。在 Cocos 里贴图资源的导入设置一般会有色彩空间的选项。项目里养成习惯拿到一张贴图先判断它是「颜色」还是「数据」然后选对应的空间。这个判断只需要几秒钟但能避免大量后期返工。5.3 图集打包与压缩纹理的关系图集和压缩纹理是两件相关但不相同的事。图集是把多张小图拼成一张大图减少 draw call 和纹理切换压缩纹理是决定这张图在显存里怎么存。它们组合起来才完整。这里有个容易被忽略的冲突图集打包后整张图集按一种格式压缩。也就是说如果图集里既有带透明的图又有不透明的图你只能按带透明的格式来压不透明图就浪费了 alpha 的空间。所以在规划图集时最好把带透明和不透明的图分开打各自的格式策略独立压缩效率会更高。另外图集尺寸尽量控制在 2048 以内太大的图集在低端机上可能超出单张纹理上限。UI 图集和特效图集也建议分开因为它们的更新频率和图质要求往往不同。5.4 自定义 Shader 采样要注意什么一旦你开始写自定义效果比如做一个游戏迷雾、边缘发光、场景扭曲就会直接操作贴图采样。这时候要留意几点。第一采样时 alpha 的处理。用压缩格式后alpha 的精度可能较低如果你在 Shader 里用 alpha 做裁剪clip/alphaTest阈值附近的像素可能出现锯齿或闪烁。稳妥做法是给阈值留一点余量并考虑在贴图侧给边缘做柔化。第二避免在片元里做重复采样。压缩纹理的采样带宽已经比你想象的省但如果你在 Shader 里对同一张贴图采三四次带宽还是会被拉满。能合并的采样尽量合并能用顶点阶段算的别放到片元阶段。第三迷雾这类效果对贴图的依赖。做游戏迷雾时如果迷雾遮罩走的是低比特率压缩边缘会出现明显的块状。建议迷雾遮罩用高画质格式或不压缩或者改用程序化噪声生成减少贴图依赖。第四格式降级带来的分支。不同设备支持的格式不同如果你的 Shader 依赖某种格式特有的行为降级后可能表现不一致。Shader 本身不感知纹理格式但贴图内容差异会传导过来。真机上多测几档机型。提示写自定义 Shader 前先把这条效果依赖的贴图格式定下来别等 Shader 写完才发现贴图格式表现不对那时候改起来代价更大。6. 我在实际项目里踩过的坑说几个我印象最深的。第一个坑是图集里混了透明和不透明的图结果整张图集只能按带透明格式压一张本来可以走 ETC1 的大图硬是走了 ETC2白白多吃了一倍多显存。后来我把图集按是否带透明重新分组显存直接降下来一截。这件事教会我图集的划分逻辑不能只看功能还要看格式诉求。第二个坑是预设顺序填反。有一次为了省事把 ETC1 填在了优先级列表最前面结果所有支持 ASTC 的高端机也走了 ETC1画质肉眼可见地差。真机一看才发现改回 ASTC 优先立刻就好了。格式优先级的顺序比格式本身还容易出错配置完一定要核对。第三个坑是法线贴图被当颜色图处理。项目里角色光照一直怪怪的排查了半天才发现法线贴图的色彩空间设置错了。改过来之后光照瞬间正常。这个坑很隐蔽因为它不报错只是「看起来不太对」。第四个坑是忘记算 mipmap。做内存预算时按基础尺寸算的上线前真机压测才发现内存超了原因是开了 mipmap 忘了算那额外三分之一。后来我在预算表里固化了 mipmap 系数每次算预算都带上再没出过这个问题。最后一个也是我现在会强烈建议的在项目立项阶段就写好纹理规范文档。把尺寸上限、命名规则、格式策略、图集划分、色彩空间全部写清楚美术和程序各拿一份。这份文档前期花不了多少时间但能让整个项目在资源这块少走大量弯路。资源规范这种事永远是在源头治理最便宜。