白鹭引擎(Egret)扩展KTX处理器以支持ASTC纹理格式解析

新增 ASTC 扩展获取、写入 Capabilities.supportedCompressedTexture.astc,并把 ASTC 扩展加入 _supportedCompressedTextureInfo,这样引擎的压缩纹理上传链路就能识别 ASTC internalFormat。

egret.web.js
WebGLRenderContext.prototype.getSupportedCompressedTexture = function () {
	var gl = this.context ? this.context : egret.sys.getContextWebGL(this.surface);
	this.pvrtc = gl.getExtension('WEBGL_compressed_texture_pvrtc') || gl.getExtension('WEBKIT_WEBGL_compressed_texture_pvrtc');
	if (this.pvrtc) {
		this.pvrtc.name = 'WEBGL_compressed_texture_pvrtc';
	}
	//
	this.etc1 = gl.getExtension('WEBGL_compressed_texture_etc1') || gl.getExtension('WEBKIT_WEBGL_compressed_texture_etc1');
	if (this.etc1) {
		this.etc1.name = 'WEBGL_compressed_texture_etc1';
	}
	//
	// ASTC (if supported by the current hardware/browser)
	this.astc = gl.getExtension('WEBGL_compressed_texture_astc') || gl.getExtension('WEBKIT_WEBGL_compressed_texture_astc');
	if (this.astc) {
		this.astc.name = 'WEBGL_compressed_texture_astc';
	}
	//
	if (egret.Capabilities._supportedCompressedTexture) {
		egret.Capabilities._supportedCompressedTexture = egret.Capabilities._supportedCompressedTexture || {};
		egret.Capabilities._supportedCompressedTexture.pvrtc = !!this.pvrtc;
		egret.Capabilities._supportedCompressedTexture.etc1 = !!this.etc1;
		egret.Capabilities._supportedCompressedTexture.astc = !!this.astc;
	}
	else {
		egret.Capabilities['supportedCompressedTexture'] = egret.Capabilities._supportedCompressedTexture || {};
		egret.Capabilities['supportedCompressedTexture'].pvrtc = !!this.pvrtc;
		egret.Capabilities['supportedCompressedTexture'].etc1 = !!this.etc1;
		egret.Capabilities['supportedCompressedTexture'].astc = !!this.astc;
	}
	//
	this._supportedCompressedTextureInfo = this._buildSupportedCompressedTextureInfo(/*this.context, compressedTextureExNames,*/ [this.etc1, this.pvrtc, this.astc]);
};
  1. 工具函数( xxx.png ↔ xxx@1.ktx 约定一致)
    sheetAtlasPathToKtxAt1Path(url):仅当 r.url 以 .png 结尾时,得到同路径 xxx@1.ktx。
    isAstcSupportedForSheet():先调用 WebGLRenderContext.getInstance().getSupportedCompressedTexture()(保证已探测扩展),再读 Capabilities 里的 astc。
  2. SheetProcessor.onLoadStart
    仍先加载图集 JSON,解析出大图资源 r(与原来一致,data.file 仍可指向 xxx.png)。
    若推得出 ktxUrl 且 ASTC 可用:用 host.load(rKtx, ‘ktx’) 加载 rKtx(url 为 xxx@1.ktx,type: ‘ktx’,name 为临时名避免和配置冲突)。
    成功后 host.remove(rKtx)(去掉 KTX 专用缓存项,避免双份),再 buildSheet(tex),内部仍 host.save(r, baseTexture),$resourceInfo 仍是原来的 r,unload 行为与以前一致。
    KTX 失败或不可用:退回原来的 host.load®(按 image 加载 PNG)。

处理非图集:增强 sheetAtlasPathToKtxAt1Path(支持 URL 带 ?/#),并在 ImageProcessor 中加入与 SheetProcessor 相同的 KTX 优先加载逻辑。

assetsmanager.js

processor_1.getRelativePath = getRelativePath;
/**
 * 命名约定:xxx.png → xxx@1.ktx(图集大图 SheetProcessor、散图 ImageProcessor 共用)
 * 支持 url 带 ?query / #hash(只替换路径段的 .png)
 */
processor_1.sheetAtlasPathToKtxAt1Path = function (url) {
	if (!url || url.length < 5) {
		return null;
	}
	var qi = url.indexOf('?');
	var hi = url.indexOf('#');
	var end = url.length;
	if (qi >= 0) {
		end = Math.min(end, qi);
	}
	if (hi >= 0) {
		end = Math.min(end, hi);
	}
	var pathOnly = url.substring(0, end);
	var suffix = url.substring(end);
	if (pathOnly.length < 5) {
		return null;
	}
	var lower = pathOnly.toLowerCase();
	if (lower.slice(-4) !== '.png') {
		return null;
	}
	return pathOnly.slice(0, -4) + '@1.ktx' + suffix;
};
/**
 * 是否可用 ASTC(需先触发 WebGL 扩展探测)
 */
processor_1.isAstcSupportedForSheet = function () {
	try {
		if (egret['web'] && egret['web'].WebGLRenderContext && egret['web'].WebGLRenderContext.getInstance) {
			egret['web'].WebGLRenderContext.getInstance().getSupportedCompressedTexture();
		}
		var caps = egret.Capabilities;
		var s = caps && (caps._supportedCompressedTexture || caps['supportedCompressedTexture']);
		return !!(s && s.astc);
	}
	catch (e) {
		return false;
	}
};
processor_1.ImageProcessor = {
	onLoadStart: function (host, resource) {
		function loadImageViaImageLoader() {
			var loader = new egret.ImageLoader();
			loader.load(RES.getVirtualUrl(resource.root + resource.url));
			return promisify(loader, resource)
				.then(function (bitmapData) {
				var texture = new egret.Texture();
				texture._setBitmapData(bitmapData);
				var r = host.resourceConfig.getResource(resource.name);
				if (r && r.scale9grid) {
					var list = r.scale9grid.split(",");
					texture["scale9Grid"] = new egret.Rectangle(parseInt(list[0]), parseInt(list[1]), parseInt(list[2]), parseInt(list[3]));
				}
				return texture;
			});
		}
		var ktxUrl = processor_1.sheetAtlasPathToKtxAt1Path(resource.url);
		if (ktxUrl && processor_1.isAstcSupportedForSheet()) {
			var rKtx = { name: resource.name + "__egret_image_ktx", url: ktxUrl, type: 'ktx', root: resource.root };
			return host.load(rKtx, 'ktx').then(function (tex) {
				host.remove(rKtx);
				var r = host.resourceConfig.getResource(resource.name);
				if (r && r.scale9grid && tex) {
					var list = r.scale9grid.split(",");
					tex["scale9Grid"] = new egret.Rectangle(parseInt(list[0]), parseInt(list[1]), parseInt(list[2]), parseInt(list[3]));
				}
				return tex;
			}).catch(function () {
				return loadImageViaImageLoader();
			});
		}
		return loadImageViaImageLoader();
	},
	onRemoveStart: function (host, resource) {
		var texture = host.get(resource);
		texture.dispose();
	}
};

processor_1.SheetProcessor = {
	onLoadStart: function (host, resource) {
		return host.load(resource, "json").then(function (data) {
			var r = host.resourceConfig.getResource(RES.nameSelector(data.file));
			if (!r) {
				var imageName = getRelativePath(resource.url, data.file);
				r = { name: imageName, url: imageName, type: 'image', root: resource.root };
			}
			function buildSheet(baseTexture) {
				if (!baseTexture) {
					return null;
				}
				var frames = data.frames;
				var spriteSheet = new egret.SpriteSheet(baseTexture);
				spriteSheet["$resourceInfo"] = r;
				for (var subkey in frames) {
					var config = frames[subkey];
					var texture = spriteSheet.createTexture(subkey, config.x, config.y, config.w, config.h, config.offX, config.offY, config.sourceW, config.sourceH);
					if (config["scale9grid"]) {
						var str = config["scale9grid"];
						var list = str.split(",");
						texture["scale9Grid"] = new egret.Rectangle(parseInt(list[0]), parseInt(list[1]), parseInt(list[2]), parseInt(list[3]));
					}
				}
				host.save(r, baseTexture);
				return spriteSheet;
			}
			var ktxUrl = processor_1.sheetAtlasPathToKtxAt1Path(r.url);
			if (ktxUrl && processor_1.isAstcSupportedForSheet()) {
				var rKtx = { name: r.name + "__egret_sheet_ktx", url: ktxUrl, type: 'ktx', root: r.root };
				return host.load(rKtx, 'ktx').then(function (tex) {
					host.remove(rKtx);
					return buildSheet(tex);
				}).catch(function () {
					return host.load(r).then(function (bitmapData) {
						return buildSheet(bitmapData);
					}, function (e) {
						host.remove(r);
						throw e;
					});
				});
			}
			return host.load(r).then(function (bitmapData) {
				return buildSheet(bitmapData);
			}, function (e) {
				host.remove(r);
				throw e;
			});
		});
	},
	getData: function (host, resource, key, subkey) {
		var data = host.get(resource);
		if (data) {
			return data.getTexture(subkey);
		}
		else {
			return null;
		}
	},
	onRemoveStart: function (host, resource) {
		var sheet = host.get(resource);
		var r = sheet["$resourceInfo"];
		sheet.dispose();
		host.unload(r);
	}
};

解决Laya引擎导出的纹理压缩文件是 sRGB 的 ASTC KTX 格式颜色显示不对

Egret渲染管线仍是传统2D(非线性/非 Gamma-correct):屏幕期望直接显示 sRGB 值;一旦把 ASTC/KTX 按 sRGB 内部格式上传,GPU 会先做 sRGB→linear 解码,但最后不会再 linear→sRGB 编码输出,结果就会出现整体发暗/颜色怪异/对比不对。(因为使用的是Laya引擎打包出压缩纹理,使用的是sRGB 的 KTX,需要加载时把 sRGB internalFormat 映射成 linear)

libs\modules\egret\egret.js

compressedData.glInternalFormat = this.glInternalFormat;
替换成
var internalFormat = this.glInternalFormat;
// Map ASTC sRGB internalFormat to linear to avoid color shift
// in engines/environments that don't use a full linear+sRGB output pipeline (e.g. mini-games).
// ASTC LDR linear: 0x93B0..0x93BD, ASTC LDR sRGB: 0x93D0..0x93DD
if (internalFormat >= 0x93D0 && internalFormat <= 0x93DD) {
   	internalFormat = internalFormat - 0x20;
}
compressedData.glInternalFormat = internalFormat;
内容概要:本文档系统性地介绍了2024年最新提出的两种智能优化算法——青蒿素优化算法与霜冰优化算法(RIME)的原理、实现方法及其性能对比分析,并提供了完整的Matlab代码实现。文档不仅聚焦于核心算法的仿真与验证,还整合了大量前沿科研资源,涵盖微电网优化、风电功率预测、无人机三维路径规划、电动汽车调度、图像融合、负荷预测、通信信号处理、电力系统故障恢复等多个高价值应用场景。所有案例均基于Matlab/Simulink平台进行建模与仿真,强调算法在复杂工程系统中的实际应用能力,旨在为科研人员提供一套从理论到代码再到应用的完整复现体系。; 适合人群:具备一定编程基础和科研背景的研究生、高校教师及工程技术人员,尤其适合从事智能优化算法研究、新能源系统优化、自动化控制、电力系统调度、无人机导航与路径规划等相关领域的研究人员。; 使用场景及目标:①用于高水平学术论文的复现与创新性研究,提升科研效率与成果产出;②应用于复杂工程系统的建模仿真与智能优化设计,如多能互补系统调度、无人机避障路径规划、微电网能量管理等;③作为智能优化算法的教学与学习资料,深入理解现代元启发式算法的设计思想与实现机制。; 阅读建议:建议读者结合文档中提供的Matlab代码与Simulink仿真模型,按照目录结构循序渐进地学习与实践,优先选择与自身研究方向契合的案例进行代码复现,重点关注算法参数设置、收敛曲线分析与多算法对比实验部分,以全面提升算法应用与科研创新能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JIQIU.YANG

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值