creator贴图纹理压缩(creator2.4.x 实现ETC2和ASTC)

您所在的位置:网站首页 微信etc2代怎么样 creator贴图纹理压缩(creator2.4.x 实现ETC2和ASTC)

creator贴图纹理压缩(creator2.4.x 实现ETC2和ASTC)

2024-07-17 02:41| 来源: 网络整理| 查看: 265

目录

1. creator游戏开发之纹理压缩

2. 常用的压缩纹理格式

3. 测试

4. ETC2 格式测试

6. ASTC格式测试

送上下载链接 不修改引擎的实现ASTC格式加载.zip-cocos2D文档类资源-CSDN下载

7.  最后附上插件代码

1. creator游戏开发之纹理压缩

目的:减少运行内存,减少耗电量发热

2. 常用的压缩纹理格式 常用压缩格式有 ETC1、ETC2、PVRTC、ASTC 分析对比:

兼容 、内存、 效果 各方面分析对比

ETC1的问题是不支持透明通道;而PVRTC的问题是透明图片质量太差,且图片大小必须是2的幂和正方形。ETC2的出现正好弥补了这两个格式的不足。

ETC2 需要 OpenGL ES 3.0 支撑。

OpenGL ES 3.0的兼容情况,大概是这样的:

软件: android 4.3以上支持ES3.0 android  minSdkVersion版本18 IOS 7以上支持ES3.0 硬件: Adreno 300 and 400 series (Android, BlackBerry 10, Windows Phone 8, Windows RT) Mali T600 series onwards (Android, Linux, Windows 7) PowerVR Series6 (iOS, Linux) Vivante (Android, OS X 10.8.3, Windows 7) Nvidia (Android, Linux, Windows 7) Intel (Linux) 苹果设备从A7开始支持ES3.0,最低要求的设备是: iPhone 5S iPad Air iPad mini with Retina display

  

ASTC 6x6的内存容量小于ETC2 4 bits,压缩质量高于ETC2 4 bits。creator3.0以后支持ASTC ,受版本限制creator2.4需要修改c++底层逻辑来加载ASTC

3. 测试

测试的纹理图片:1.jpg (720*1600) 位深度24、2.png( 614*902) 位深度8、3.png( 462*689)位深度8

补充知识:

「RGBA4444」 :每个通道占4位(bit)4*4 = 16位

「RGBA8888」 :每个通道占8位(bit)32位

「RGB565」 :占用的存储大小 5+6+5 = 16 位 = 2Byte

「RGB888」 :每个通道占8位(bit)24位 = 3Byte

纹理内存计算:(12* 720*1600 + 4* 614*902 + 4* 462*689)/(1024*1024) = 16.5M

测试工程:不加载任何纹理 (空包内存):50.6M

显示那3张图片内存:67.3M

4. ETC2 格式测试 准备工作

需要android  minSdkVersion版本18

使用的 ext.COMPRESSED_RGBA8_ETC2_EAC

引擎目录jsb-adapter/bin/jsb-builtin.js可以看到支持的压缩格式

压缩工具在引擎目录:\2.4.3\resources\static\tools\texture-compress\mali\Windows_64\

etcpack.exe

相关工具ImageMagick 中文站

构建后需要关注的变化:

查阅 CCMacro.js的 SUPPORT_TEXTURE_FORMATS和 resources\engine\cocos2d\renderer\gfx\ enums.js 的enums

回到构建后的assets目录下资源,压缩需要处理的贴图得到pkm

 0 换成 6@29

IOS 需要改用ES3.0的EGLContext 参考 PR #1685

creator2.4支持

creator2.4.3 提示只支持导出,但实际测试是已经支持加载了。可能编辑器没同步更新。

结果

ETC2 fast 内存:减少%40以上

一共花了约2分钟

ETC2 slow 压缩一张图片要3-5分钟,实在太慢了。好在有缓存不用重复压缩,和fast模式差别不大,可能图片质量高一些,看不太出来。

问题 :

透明渐变区域有波纹(透明通道) mac平台纹理压缩 后透明度不对, etc2存在alpha精度丢失

解决方式(Mac 升级工具链)

6. ASTC格式测试

ASTC 6x6的内存容量小于ETC2 4 bits,压缩质量高于ETC2 4 bits。

需要参考creator3.x的实现方式自行修改 参考这里

送上下载链接 不修改引擎的实现ASTC格式加载.zip-cocos2D文档类资源-CSDN下载 7.  最后附上插件代码

插件说明:插件实现在构建的时候自动将项目贴图资源压缩,无感操做

完整构建插件:packages\pack-render

核心代码文件(main.js):

/*main.js*/ /* eslint-disable no-undef */ const Fs = require('fs'); const Path = require('path'); const FsExtra = require('fs-extra'); const { resolve } = require('path'); const settingPath = "packages://pack-render/config/setting.json" const astc = "packages://pack-render/astcenc/astcenc-avx2" var isCompress = true; var platform = "android" // 开始构建 function onBeforeBuildStart (options, callback) { isCompress = options.isCompress platform = options.platform Editor.log("pack-render:start::", isCompress); if (!isCompress) { callback(); return; } Editor.Ipc.sendToMain("pack-render:doWork", "start", function (event, args) { Editor.log("doWork start >>> Complete"); callback(); }); } // 构建完成 function onBeforeBuildFinish (options, callback) { callback(); } function onBuildFinish (options, callback) { isCompress = options.isCompress platform = options.platform Editor.log("pack-render:finish::", isCompress); if (!isCompress) { callback(); return; } Editor.Ipc.sendToMain("pack-render:setBuildResults", options.bundles); Editor.Ipc.sendToMain("pack-render:doWork", "finish", function (event, args) { Editor.log("doWork finish >>> Complete"); callback(); }); } const Types = { NONE: "none", ETC2_RGBA: "etc2", ASTC_6_6: "astc_6_6", ASTC_8_8: "astc_8_8" } function autoSetTypeSelectWithPlatform (setting, p) { if (p === 'ios') { setting.typeSelect = Types.ASTC_6_6 } else if (p === 'android') { setting.typeSelect = Types.ETC2_RGBA } } module.exports = { data: { setting: {}, platformSettings: {}, cmd: "start", buildBundles: null }, messages: { 'open' () { Editor.Panel.open('pack-render'); // 面板加载时,直接显示缓存数据. setTimeout(() => { Editor.Ipc.sendToPanel("pack-render", "loadConfigs", "arg1", "arg2"); }, 2000); }, 'onStart' (event, arg1, arg2) { Editor.log("onStart", arg1, arg2); }, 'setBuildResults' (event, bundles) { // Editor.log("setBuildResults:", bundles); this._setBuildResults(bundles); }, async 'doWork' (event, arg1) { // this.encNativeTexture("D:/build/jsb-default/assets/testui/native/2e/2ef15057-867c-45ec-a6b1-1dabeaeec6bc.c4c12.png"); // return; Editor.log("doWork:", arg1); await this.updateSetting() this.cmd = arg1 let isAstc = this.isASTC() if (this.cmd == "start") { if (this.setting.include && this.setting.include.length > 0) { // if (isAstc) { // setTimeout(() => { // if (event.reply) { // event.reply(null, 'Fine, thank you!'); // } // }, 1000); // } else { this.findPaths(this.setting.include, event) // } } } else if (this.cmd == "finish") { if (this.setting.include && this.setting.include.length > 0) { if (isAstc) { this.findImports(this.setting.include, event) } else { this.findPaths(this.setting.include, event) } } } } }, load () { this.updateSetting(); Editor.Builder.on('build-start', onBeforeBuildStart); // 构建开始时触发。 // 在构建结束 之前 触发,此时除了计算文件 MD5、生成 settings.js、原生平台的加密脚本以外,大部分构建操作都已执行完毕。我们通常会在这个事件中对已经构建好的文件做进一步处理。 Editor.Builder.on('before-change-files', onBeforeBuildFinish); Editor.Builder.on('build-finished', onBuildFinish); // 构建完全结束时触发。 }, unload () { Editor.Builder.removeListener('build-start', onBeforeBuildStart); Editor.Builder.removeListener('before-change-files', onBeforeBuildFinish); Editor.Builder.removeListener('build-finished', onBuildFinish); }, addLog (...str) { Editor.Ipc.sendToPanel("pack-render", "addLog", str.join(':')); Editor.log(str.join(':')) }, // 同步配置 updateSetting () { return new Promise(resolve => { // 检查配置文件 Fs.access(Editor.url(settingPath), Fs.constants.R_OK | Fs.constants.W_OK, (err) => { if (err) { autoSetTypeSelectWithPlatform(this.setting, platform) Fs.writeFile(Editor.url(settingPath), JSON.stringify({}), 'utf-8'); return resolve(this.setting) } else { // Editor.log(`${settingPath} exists, and it is read-writable`); Fs.readFile(Editor.url(settingPath), 'utf-8', (err, res) => { if (err) { return resolve(this.setting); } const settingObj = res ? JSON.parse(res) : {}; autoSetTypeSelectWithPlatform(settingObj, platform) Editor.log("update setting", JSON.stringify(settingObj)); this.setting = settingObj return resolve(this.setting) }); } }) }); }, isASTC () { return this.setting.typeSelect == Types.ASTC_6_6 || this.setting.typeSelect == Types.ASTC_8_8 }, _setBuildResults (bundles) { this.buildBundles = bundles }, // 查询资源 async findPaths (include, event) { // for (let index = 0; index < include.length; index++) { const config = include[index]; let path = "db://assets/" + config.path + "/**/*" // "db://assets/testui/**/*" let results = await this.queryAssets(path) if (!results) { continue; } for (let itemidx = 0; itemidx < results.length; itemidx++) { const item = results[itemidx]; if (this.isExcludePath(item.url)) { this.addLog("排除:", item.url); continue } // Editor.log("绝对路径:", item.path); let uuid = item.uuid; this.addLog("设置纹理格式:", item.url); await this.changeMeta(item.uuid, item.url) } if (index == include.length - 1) { this.addLog(">>> Complete"); if (event.reply) { event.reply(null, 'Fine, thank you!'); } } } }, isExcludePath (url) { // 排除 for (let index = 0; index < this.setting.exclude.length; index++) { const path = this.setting.exclude[index].path; if (url.indexOf(path) >= 0) { return true; } } return false; }, queryAssets (urlPath) { Editor.log("查询目录:", urlPath); return new Promise(resolve => { Editor.assetdb.queryAssets(urlPath, "texture", (err, results) => { if (err) { Editor.log("error:", err); return resolve(null) } Editor.log("找到文件个数:", results.length); return resolve(results) }); }); }, // 修改meta changeMeta (uuid, url) { return new Promise(resolve => { let type = this.setting.typeSelect this.platformSettings = { android: { formats: [] } } if (this.cmd == "finish") { this.platformSettings = {}; } else { if (type == Types.ETC2_RGBA) { this.platformSettings.android.formats.push({ name: "etc2", quality: "fast" }) } else if (type == Types.ETC2_RGB) { this.platformSettings.android.formats.push({ name: "etc2_rgb", quality: "fast" }) } else { this.platformSettings = {}; } } var platformSettingsTemp = this.platformSettings // Editor.log("修改meta:", JSON.stringify(this.platformSettings)); // Editor.log("修改meta:", uuid); Editor.Ipc.sendToMain("asset-db:query-meta-info-by-uuid", uuid, function (err, info) { let metaInfo = JSON.parse(info.json) // Editor.log("修改前meta:", platformSettingsTemp); metaInfo.platformSettings = platformSettingsTemp // Editor.log("修改后meta:", JSON.stringify(metaInfo)) Editor.assetdb.saveMeta(metaInfo.uuid, JSON.stringify(metaInfo, null, 2), function (err, info) { resolve() }); }) }); }, // 查询import async findImports (include, event) { if (!this.isASTC()) { return; } for (let index = 0; index < this.buildBundles.length; index++) { const bundle = this.buildBundles[index]; // Editor.log("bundle:", bundle) if (bundle.name == "internal" || !bundle.root) { continue } var buildResults = bundle.buildResults; // let querypath = bundle.root + "/**/*" let results = await this.queryImports(querypath) if (!results) { continue; } for (let j = 0; j < results.length; ++j) { let item = results[j]; if (this.isExcludePath(item.url)) { this.addLog("排除:", item.url); continue } Editor.log("ready astcEnc :", item.url) let uuid = item.uuid var nativePath = buildResults.getNativeAssetPath(uuid); let importUrl; if (buildResults._md5Map) { let import_md5 = buildResults._md5Map[uuid]; importUrl = bundle.dest + "/import/" + uuid.slice(0, 2) + "/" + uuid + "." + import_md5 + ".json" } else { importUrl = bundle.dest + "/import/" + uuid.slice(0, 2) + "/" + uuid + ".json" } await this.astcEnc(importUrl, nativePath); } } if (event.reply) { event.reply(null, 'Fine, thank you!'); } }, queryImports (urlPath) { Editor.log("查询目录:", urlPath); return new Promise(resolve => { Editor.assetdb.queryAssets(urlPath, "texture", (err, results) => { if (err) { Editor.log("error:", err); return resolve(null) } return resolve(results) }); }); }, async astcEnc (importUrl, nativeUrl) { Editor.log("importUrl:", importUrl); await this.changeImportJson(importUrl) Editor.log("nativeUrl:", nativeUrl); await this.encNativeTexture(nativeUrl) return new Promise(resolve => { resolve(); }); }, // 废弃 getAssetPath (uuid, bundelName) { for (let index = 0; index < this.buildBundles.length; index++) { const bundle = this.buildBundles[index]; // if (bundle.name != bundelName) { // continue // } var buildResults = bundle.buildResults; // Editor.log("bundle:", JSON.stringify(bundle)); // Editor.log("buildResults:", buildResults); // 获得指定资源依赖的所有资源 // var depends = buildResults.getDependencies(uuid); // Editor.log("depends:", depends); // 获得构建后的原生资源路径(原生资源有图片、音频等,如果不是原生资源将返回空) var nativePath = buildResults.getNativeAssetPath(uuid); let importUrl; if (buildResults._md5Map) { let import_md5 = buildResults._md5Map[uuid]; importUrl = bundle.dest + "/import/" + uuid.slice(0, 2) + "/" + uuid + "." + import_md5 + ".json" } else { importUrl = bundle.dest + "/import/" + uuid.slice(0, 2) + "/" + uuid + ".json" } // Editor.log("importPath:", importUrl); // 获取资源类型 // var type = buildResults.getAssetType(uuid); // Editor.log("type:", type); return { nativeUrl: nativePath, importUrl: importUrl } } }, changeImportJson (importUrl) { return new Promise(resolve => { Fs.readFile(importUrl, 'utf-8', (err, res) => { if (err) { return resolve(); } let obj = JSON.parse(res) if (this.setting.typeSelect == Types.ASTC_6_6) { obj[5][0] = "7@34,9729,9729,33071,33071,0,0,1" } else if (this.setting.typeSelect == Types.ASTC_8_8) { obj[5][0] = "7@37,9729,9729,33071,33071,0,0,1" } // Editor.log("changeImportJson:", JSON.stringify(obj)); Fs.writeFileSync(importUrl, JSON.stringify(obj), 'utf-8'); return resolve(obj) }); }); }, encNativeTexture (nativeUrl) { return new Promise(resolve => { // var cmd = Editor.url('packages://pack-render/astcenc/a.bat') + " " + nativeUrl; // var cmd = Editor.url('packages://pack-render/astcenc/do.bat') + " " + nativeUrl; let outfile = nativeUrl.replace(/\.\w+$/, ".astc"); let sel = "6x6" if (this.setting.typeSelect == Types.ASTC_6_6) { sel = "6x6" } else if (this.setting.typeSelect == Types.ASTC_8_8) { sel = "8x8" } var cmd = "python " + Editor.url('packages://pack-render/astcenc/runner.py') + ` -cl ${nativeUrl} ${outfile} ${sel} -medium`; this.exec(cmd, () => { Fs.unlink(nativeUrl, (err) => { if (err) { Editor.error(err) } Editor.log('>>> encNativeTexture complete'); return resolve(); }); }) // let pythonFile = Editor.url('packages://pack-render/') + "test.py" // this.python(pythonFile, [nativeUrl, Editor.url('packages://pack-render/')], () => { // Editor.log('>>> encNativeTexture complete'); // }) }); }, exec (cmd, callback) { var exec = require('child_process').exec; Editor.log('exec::' + cmd); exec(cmd, function (err, stdout, stderr) { if (err) { Editor.log('execall:: error:' + stderr); } else { // var data = JSON.parse(stdout); Editor.log(stdout) callback() } }); }, shell (cmd, callback) { var callfile = require('child_process'); var ip = '1.1.1.1'; var username = 'test'; var password = 'pwd'; var newpassword = 'newpwd'; callfile.execFile('xxx.sh', ['-H', ip, '-U', username, '-P', password, '-N', newpassword], null, function (err, stdout, stderr) { // callback(err, stdout, stderr); }); }, python (pythonUrl, pramas, callback) { var exec = require('child_process').exec; exec('python ' + pythonUrl + ' ' + pramas[0] + ' ' + pramas[1] + ' ', function (error, stdout, stderr) { if (stdout.length > 1) { Editor.log('you offer args:', stdout); } else { Editor.log('you don\'t offer args'); } if (error) { Editor.info('python call error::' + stderr); } }); } }

参考

1.

Cocos Creator 纹理压缩插件 - Creator - Cocos中文社区

2. etc2

【技术分享之三】cocos实现对ETC2的支持 - Creator - Cocos中文社区

astc

大佬们有没有计划或者方案在2.4.x上使用astc - Creator - Cocos中文社区



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3