自定义资源解析器
PlayCanvas 每种资源类型都通过一个资源处理器加载,例如 'texture'、'model'、'audio'。处理器内部由解析器处理具体文件格式,例如纹理处理器包含浏览器图像、DDS、KTX2 和 Basis 解析器。处理器公开解析器注册机制,因此无需修改引擎,即可支持新格式或覆盖内置格式。
自定义解析器自引擎 v2.21.0 起可用,属于引擎运行时 API:解析器在应用加载资源时执行,不影响编辑器的资源导入流程。
资源加载流程
加载资源时,ResourceLoader 查找为该资源类型注册的 ResourceHandler。处理器按最新注册优先的顺序,询问解析器是否识别该资源:
- 处理器构造描述资源的上下文,包含 URL、扩展名等。
- 选择最近注册且
canParse(context)返回true的解析器。 - 解析器的
load()获取文件并提供数据。 - 解析器的
open()将数据转换为Texture、Model等运行时资源。
由于后注册者优先,自定义解析器对其声明支持的资源会优先于内置解析器。
解析器接口约定
解析器可以是普通对象或类实例,需要提供以下方法:
class MyParser {
// return true if this parser handles the described resource
canParse(context) {
return context.ext === 'myformat';
}
// fetch the resource and deliver its raw data via callback(err, data)
load(url, callback, asset) {
this.handler.fetch(url, pc.Http.ResponseType.ARRAY_BUFFER, callback, asset);
}
// optional: convert the loaded data into the runtime resource
open(url, data, asset) {
return data;
}
}
传给 canParse 的 context 描述待加载资源:
| 属性 | 说明 |
|---|---|
url | 去掉查询字符串的原始资源 URL,或 null |
ext | 不含开头句点的小写扩展名,例如 'tga' |
basename | 小写文件名,例如 'lod-meta.json' |
asset | 正在加载的 Asset,如果存在 |
app | 运行中的 AppBase |
注册解析器时,处理器会将自身赋给解析器的 handler 属性。这样,load() 可以调用 this.handler.fetch(url, responseType, callback, asset),沿用处理器重试设置下载资源,并在可用时复用预先获取的数据;也可以访问 this.handler.app 等处理器状态。
注册解析器
在资源类型对应的处理器上注册解析器:
app.loader.getHandler('texture').addParser(new TgaParser());
应在该资源类型开始任何加载之前注册。已注册的解析器可通过 removeParser(parser) 移除,通过只读的 parsers 属性查看当前注册项。
由于后注册者优先,如果新解析器声明支持内置解析器已经支持的格式,就会覆盖内置行为;无论针对特定扩展名还是通用兜底解析器,规则都相同。
示例:TGA 纹理解析器
引擎运行时默认不加载 .tga 文件,自定义解析器可以补充此功能:
class TgaParser {
canParse(context) {
return context.ext === 'tga';
}
load(url, callback, asset) {
this.handler.fetch(url, pc.Http.ResponseType.ARRAY_BUFFER, callback, asset);
}
// texture parsers use an extended open signature: the handler passes the graphics
// device and the texture options derived from the asset's data
open(url, data, device, textureOptions) {
// decode the TGA file into RGBA8 pixels (using your decoder of choice)
const { width, height, pixels } = decodeTga(data);
const texture = new pc.Texture(device, {
name: url,
width: width,
height: height,
format: pc.PIXELFORMAT_RGBA8,
levels: [pixels],
// spread the asset-derived options last, so that asset settings
// (srgb, filtering, mipmaps, ...) override the defaults above
...textureOptions
});
texture.upload();
return texture;
}
}
app.loader.getHandler('texture').addParser(new TgaParser());
注册后,.tga 文件就能像其他纹理一样加载:
const asset = new pc.Asset('picture', 'texture', { url: 'images/picture.tga' }, { srgb: true });
app.assets.add(asset);
app.assets.load(asset);
完整可运行的自定义模型解析器示例,可查看引擎的 OBJ 解析器,以及使用它的 OBJ 加载示例。
各处理器的注意事项
大多数直接处理文件格式的资源处理器都支持解析器注册,包括 model、texture、material、gsplat、container、animation、animclip、animstategraph、template、audio、json、css、html、text、shader 和 binary。不同类型的细节如下:
- texture:解析器实现上文所示扩展版
open(url, data, device, textureOptions)。内置浏览器图像解析器充当通用兜底,因此未知扩展名默认由它处理,除非自定义解析器声明支持。 - material:处理器的资源绑定,即绑定材质数据引用的纹理资源,只适用于内置 JSON 解析器生成的
StandardMaterial;自定义解析器生成的材质自行管理资源引用。 - audio:通过
this.handler.manager访问声音管理器。自定义解析器可解码得到AudioBuffer,包装为pc.Sound后返回。 - 组合其他资源而非解析文件格式的处理器(
cubemap、font、sprite、textureatlas),以及专用处理器(bundle、script、folder),不会查询已注册解析器。