在游戏开发中,纹理是游戏中展示图像的重要元素,它是大部分游戏中占据包体最大的资源,并且占据了大量的内存,传统的图片压缩格式,如jpg, png等虽然可以减少图片资源的大小,但是不能被GPU识别,需要先加载到内存,通过CPU解码,最终转换成RGB/RGBA等能被GPU识别的格式,才能传送到GPU进行渲染。
压缩纹理的出现,解决上面的问题,它是一种专门针对GPU的纹理压缩方案。它可以直接被GPU识别和渲染。它具有以下有点:
- 无需CPU解码,节省了CPU运算,减少耗电量。
- 纹理直接被传送到GPU,避免了内存占用,提高渲染性能。
- 高效的压缩算法,减少了包体大小。
常用的压缩纹理格式
在Cocos Creator中,常用的压缩纹理格式有以下几种:
-
ETC1:ETC1把
4*4的像素块压缩成固定的64位编码(8个字节),4*4像素块是16个像素,每个像素4字节,一共占64个字节,所以压缩比是 64/8=8。但是ETC1只能存储RGB信息,不适用带透明度的纹理,为解决这个问题,Creator在ETC1文件中额外写入了透明度信息,即ETC1+A格式,它的压缩比是 64/16=4。
ETC1/ETC1+A需要OpenGL ES 2.0(对应WebGL 1.0)环境,目前几乎所有Android手机都支持ETC1,但是iOS不支持。
ETC1/ETC1+A纹理的长宽可以不相等,但要求是2的幂次方。 -
ETC2:ETC2是ETC1的扩展,压缩比率一样,但压缩质量更高,而且支持透明通道,能完整存储RGBA信息。ETC2需要OpenGL ES 3.0(对应WebGL 2.0)环境,目前还有不少低端Android手机不兼容,iOS方面从 iPhone5S 开始都支持OpenGL ES 3.0。
ETC2和ETC1一样,长宽可以不相等,但要求是2的幂次方。 -
PVRTC:适用于iOS平台,压缩比率和ETC相似,但在纹理长宽相等、为2的幂次方的要求和画面质量方面存在限制。在实测中还发现转换后的图片质量不如ETC1,存在模糊、毛边现象,对画面要求高的游戏不适合
因此通常安卓平台会选择ETC1方式,IOS平台会选择ETC2
自动化设置压缩纹理
在设置压缩纹理格式时,目前Creator 2.x版本还需手动一个一个设置,下面用node.js自动化设置压缩纹理格式,并随时可以取消,恢复原始设置。
代码如下:
const fs = require('fs');
const path = require('path');
const etcSettings = {
android: {
formats: [
{
name: 'etc1',
quality: 'slow',
},
],
},
ios: {
formats: [
{
name: 'etc2',
quality: 'slow',
},
],
},
};
function lookupDir(url, isCompress) {
if (!fs.existsSync(url)) {
return;
}
const files = fs.readdirSync(url);
files.forEach((file) => {
const curPath = path.join(url, file);
const stat = fs.statSync(curPath);
if (stat.isDirectory()) {
lookupDir(curPath, isCompress); // 遍历目录
} else if (file.endsWith('.meta')) {
try {
const data = fs.readFileSync(curPath, 'utf8');
const obj = JSON.parse(data);
if (obj && obj.platformSettings) {
obj.platformSettings = isCompress ? etcSettings : {};
const wrdata = JSON.stringify(obj, null, 2);
fs.writeFileSync(curPath, wrdata, 'utf8');
}
} catch (err) {
console.error(`Error reading or parsing file ${curPath}:`, err);
}
}
});
}
function main() {
const sourcePath = process.argv[2];
const isCompress = parseInt(process.argv[3]);
if (!sourcePath) {
console.error('Source path not provided.');
return;
}
const absolutePath = path.isAbsolute(sourcePath)
? sourcePath
: path.join(__dirname, sourcePath);
lookupDir(absolutePath, isCompress);
}
main();
将上面代码保存为auto_etc.js文件
使用 使用命令行:
node auto_etc.js /path/assets isCompress
第二个参数为资源的目录,第三个为是否压缩,1:压缩,0:取消压缩