压缩纹理格式
WebGL API 提供了使用压缩纹理格式的方法。这些格式在增加纹理细节的同时,可以限制所需的额外显存。默认情况下,没有可用的压缩格式:必须先启用相应的压缩纹理格式扩展。
用法
除非另有说明,本文适用于 WebGL 1 和 2 上下文。
如果支持,纹理可以以压缩格式存储在显存中。这允许增加细节,同时限制所需的额外显存。在着色器访问纹理时,纹理会被即时解压缩。请注意,这种优势并不能转化为网络带宽:虽然这些格式比未压缩数据更好,但它们通常比 PNG 和 JPG 等标准图像格式差得多。
由于压缩纹理需要硬件支持,因此 WebGL 没有强制要求特定的格式;相反,根据硬件支持,上下文可以提供不同的格式。WebGL Texture Tester 网站显示了所用浏览器支持的格式。
使用压缩格式首先需要通过 WebGLRenderingContext.getExtension() 激活相应的扩展。如果支持,它将返回一个包含新增格式常量的扩展对象,并且可以通过调用 gl.getParameter(gl.COMPRESSED_TEXTURE_FORMATS) 来获取这些格式。(例如,对于 WEBGL_compressed_texture_s3tc 扩展,可以使用 ext.COMPRESSED_RGBA_S3TC_DXT1_EXT。)然后,可以使用 compressedTexImage[23]D 或 compressedTexSubImage[23]D 代替 texImage2D 调用。
请注意,WebGL 不提供压缩或解压缩纹理的功能:纹理必须已经是压缩格式,然后才能直接上传到显存。
所有格式都支持 2D 纹理。下表列出了支持 TEXTURE_2D_ARRAY 和 TEXTURE_3D 目标(与 compressedTexImage3D 结合使用)的格式。
| 扩展名 | 注意 | TEXTURE_2D_ARRAY | TEXTURE_3D |
|---|---|---|---|
| WEBGL_compressed_texture_astc | 是 | 是 | |
| WEBGL_compressed_texture_etc | 是 | 否 | |
| WEBGL_compressed_texture_etc1* | 不能与 compressedTexSubImage2D/copyTexSubImage2D 一起使用。 | 否 | 否 |
| WEBGL_compressed_texture_pvrtc | 宽度和高度必须是 2 的幂。 | 否 | 否 |
| WEBGL_compressed_texture_s3tc | 宽度和高度必须是 4 的倍数。 | 是 | 否 |
| WEBGL_compressed_texture_s3tc_srgb | 宽度和高度必须是 4 的倍数。 | ? | 否 |
示例
async function getCompressedTextureIfAvailable(gl) {
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture); // create texture object on GPU
const ext = gl.getExtension("WEBGL_compressed_texture_s3tc"); // will be null if not supported
if (ext) {
// the file is already in the correct compressed format
const dataArrayBuffer = await fetch(
"/textures/foobar512x512.RGBA_S3TC_DXT1",
).then((response) => response.arrayBuffer());
gl.compressedTexImage2D(
gl.TEXTURE_2D,
0, // set the base image level
ext.COMPRESSED_RGBA_S3TC_DXT1_EXT, // the compressed format we are using
512,
512, // width, height of the image
0, // border, always 0
new DataView(dataArrayBuffer),
);
gl.generateMipMap(gl.TEXTURE_2D); // create mipmap levels, like we would for a standard image
return texture;
}
}