使用 BASIS 纹理
关于
"Basis Universal Supercompressed GPU Texture Codec"——这是来着 basis_universal 的官方介绍,关键词是 Supercompressed。
相比于 .ktx 为容器的压缩纹理,可以理解为它是以 .basis 为容器的压缩纹理格式,不同的是,它是通过 WebAssembly 运行时解码为各端可支持的压缩纹理格式。
优点:
- 一套资源:.basis
- 文件体积更小,常规的比 png 还小
- 有损性较低:最终的显示效果与原图基本相差不大
缺点:
- 需要额外加载两个解码相关的文件:basis_transcoder.js 和 basis_transcoder.wasm
- 有运行时开销:实时解码(借助 WebWorker 可缓解)
数据对比
文件 | 尺寸(px) | 大小(kb) | |||
---|---|---|---|---|---|
.png | .basis | .astc.ktx | .pvr.ktx | ||
a.png | 256*256 | 13.44 | 10.217 | 29.684 | 32.868 |
b.png | 512*512 | 68.864 | 36.697 | 118.436 | 131.172 |
c.png | 1024*1024 | 353.482 | 134.412 | 467.956 | 524.388 |
d.png | 2048*2048 | 1391.118 | 417.787 | 1871.524 | 2097.252 |
【表1】各类型压缩纹理与 png 的大小对比
a.basis | b.basis | c.basis | d.basis | 6张basis | 6张basis且可用 | |
---|---|---|---|---|---|---|
尺寸(px) | 256*256 | 512*512 | 1024*1024 | 2048*2048 | 2048*2048 | 2048*2048 |
iPhone 7P 耗时(ms) | 59.4 | 98.09 | 126 | 195.84 | 784.62 | 1388.4 |
iPhone 7P Worker 耗时(ms) | - | - | - | 245.52 | 1103.04 | 1002.8 |
OPPO R11 耗时(ms) | 24.29 | 63 | 175.5 | 420.3 | 2485.44 | 3228.54 |
OPPO R11 Worker 耗时(ms) | - | - | - | 435.42 | 2804.55 | 1186.64 |
【表2】BASIS 纹理解码耗时(不含加载)对比
* 注:以上数据仅供参考,不代表真实场景。
Tips
- 从【表1】可以看出:.basis 格式甚至比 .png 还要小,尺寸越大越明显
- 从【表2】可以看出:
- 从 d.basis 的耗时分析可以估算 Worker 本身创建+通信是有一定损耗的(平均一次在 50ms 左右)
- “6张basis” 的纯解码耗时因设备而异,Worker 的优势是可以并行执行,不阻塞后面的逻辑,正如“6张basis+可用”栏目,平均 1s 就能达到可用
如何使用?
关于制作 POT 等宽 Atlas 图集可阅读 《使用压缩纹理 / 如何使用?》篇。
生成 BASIS 纹理
通过上面制作生成的 .png,你就可以通过 tinyjs-cli 来快速生成 BASIS 纹理。
# 全量生成 .astc.ktx、.pvr.ktx、.basis
$ tiny texture-compressed res/hao.png
# 只生成 .basis
$ tiny texture-compressed res/hao.png -f basis
通过以上命令,会在 res
目录下生成以下 BASIS 格式压缩纹理:
- basis 格式: https://gw.alipayobjects.com/os/tiny/resources/1.0.8/compressedtexture/hao.basis
Tips
- 生成 BASIS 纹理的功能,
tinyjs-cli
版本需要>=1.4.0
,详细命令请移步:生成压缩纹理
使用 BASIS 纹理
使用之前,你最好已经对 WebAssembly 有了大致的了解,起码知道它是个什么东西。
1、常规姿势
引用 BASIS 的解码器:
<script crossorigin="anonymous" src="https://gw.alipayobjects.com/os/tiny/owl/1.0.8/libs/basis_transcoder.js"></script>
Tips
- 此解码器会自动加载同目录下的
basis_transcoder.wasm
文件
初始化压缩纹理插件并执行:
const app = new Tiny.Application({...});
const loader = new Tiny.loaders.Loader();
// 初始化压缩纹理插件
Tiny.plugins.compressedTexture.init(app.renderer);
// 1. 检测当前环境是否支持 WebAssembly
// 2. 只有 WebGL 渲染模式下才走 BASIS 纹理,避免执行无用的 WebAssembly 计算
if (window.WebAssembly && app.renderer.gl) {
// 此 BASIS 方法是 basis_transcoder.js 提供的 wasm 模块
BASIS()
.then((Module) => {
const { BasisFile, initializeBasis } = Module;
// run module
initializeBasis();
// 执行绑定
Tiny.plugins.compressedTexture.BASISLoader.bindTranscoder(BasisFile);
start(true);
})
.catch(e => {
console.log(e);
});
} else {
start();
}
function start(useCT) {
let metadata;
if (useCT) {
// 设置 metadata.useFormat 为 basis,告诉加载器明确只使用 BASIS 纹理
metadata = { useCompressedTexture: true, useFormat: 'basis' };
}
loader
.add('logo', './res/logo.png', { metadata })
.load((loaderInstance, resources) => {
const sprite = new Tiny.Sprite(Tiny.TextureCache['logo']);
});
}
Tips
- TinyJS 1.6.0 及以上版本才支持 BASIS 纹理。
- 与 KTX 容器的压缩纹理一样,BASIS 纹理也只有 WebGL 模式下才有效,如果当前环境不支持 WebGL 会自动降级到同目录下的
.png
,支持的话则使用与.png
同目录下同文件名的.basis
文件
2、多 Worker 姿势
使用之前,你最好已经对 Web Workers 有了大致的了解,知道是怎么回事。
const app = new Tiny.Application({...});
const loader = new Tiny.loaders.Loader();
// 初始化压缩纹理插件
Tiny.plugins.compressedTexture.init(app.renderer);
// 1. 检测当前环境是否支持 Worker 和 WebAssembly
// 2. 只有 WebGL 渲染模式下才走 BASIS 纹理,避免执行无用的 WebAssembly 计算
if (window.Worker && window.WebAssembly && app.renderer.gl) {
// 加载转换器并执行转换
Tiny.plugins.compressedTexture.WorkedBASISLoader.loadAndRunTranscoder({
// basis_transcoder 的 js 及 wasm 文件路径,可使用相对路径。
// 加载后的完整链接为:
// https://gw.alipayobjects.com/os/tiny/owl/1.0.8/libs/basis_transcoder.js
// https://gw.alipayobjects.com/os/tiny/owl/1.0.8/libs/basis_transcoder.wasm
path: 'https://gw.alipayobjects.com/os/tiny/owl/1.0.8/libs',
// Worker 线程数,默认为 2,最高 8,可按资源数量设置
threads: 6,
})
.then(start.bind(this, true))
.catch(e => {
console.log(e);
});
} else {
start();
}
function start(useCT) {
// 使用方法同:1、常规姿势
}
Tips
- 多 Worker 模式比较适合资源量较大的场景,如果只有1、2个资源,其实常规模式就可以了,因为 Worker 创建和通信的耗时可能反而会让你得不偿失