WebGPU 纹理格式与采样器配置细节

从 WebGL 迈入 WebGPU,最显著的思维转变在于:隐式的全局状态机被彻底废除,取而代之的是显式的资源创建与不可变的管线对象(Pipeline Objects)。
在 WebGL 中,纹理绑定往往依赖 gl.bindTexture 与 gl.texParameteri 的运行时状态切换,极易出现状态遗漏或驱动层性能抖动。而在 WebGPU 中,纹理(GPUTexture)、纹理视图(GPUTextureView)与采样器(GPUSampler)被解耦为三个完全独立的显存与计算实体。
搞清楚纹理格式与采样器的底层配置细节,是写出高性能 WebGPU 渲染与通用计算(GPGPU)着色器的基石。
纹理格式(GPUTextureFormat)选型图谱
WebGPU 提供了极其严谨的纹理格式定义,常见的格式主要分为以下几类:
- rgba8unorm / bgra8unorm:最常用的 8 位无符号归一化整数格式,每个通道映射到 $[0.0, 1.0]$,显存占用 4 字节/像素。bgra8unorm 通常作为 Canvas 上下文(navigator.gpu.getPreferredCanvasFormat())的推荐格式以匹配操作系统原生显示。
- rgba8unorm-srgb:带 sRGB 非线性伽马校正的色彩格式,适合色彩准确度要求极高的 UI 与材质贴图。
- rgba16float / rgba32float:用于 HDR 渲染、后期辉光(Bloom)或 GPGPU 粒子物理位置计算。注意:并非所有移动端 GPU 都支持对 32 位浮点纹理进行线性滤波采样(Filtering)。
- depth24plus / depth24plus-stencil8 / depth32float:用于 Z-Buffer 遮挡剔除与阴影映射。
显式使用意图:GPUTextureUsage 的严格约束
在 WebGPU 中,必须在创建纹理时通过位掩码(Bitmask)提前声明该纹理的所有使用场景,以便底层图形驱动进行显存分配与管线优化:
export async function createStandardTexture(
device: GPUDevice,
imageBitmap: ImageBitmap
): Promise<{ texture: GPUTexture; view: GPUTextureView }> {
const texture = device.createTexture({
size: [imageBitmap.width, imageBitmap.height, 1],
format: 'rgba8unorm',
// 显式声明:该纹理将被作为着色器采样资源,且允许从 CPU 写入数据
usage:
GPUTextureUsage.TEXTURE_BINDING |
GPUTextureUsage.COPY_DST |
GPUTextureUsage.RENDER_ATTACHMENT,
});
// 使用 writeTexture 将位图数据上传至 GPU 显存
device.queue.copyExternalImageToTexture(
{ source: imageBitmap },
{ texture: texture },
[imageBitmap.width, imageBitmap.height]
);
const view = texture.createView();
return { texture, view };
}
采样器(GPUSampler)的核心配置与抗锯齿
采样器负责在着色器执行 textureSample() 时,定义如何根据 UV 坐标在离散的纹理像素点之间进行插值。
1. 过滤模式(Filtering)与 Mipmap
- magFilter(放大过滤):当一个纹理像素覆盖多个屏幕像素时生效(近景)。
- minFilter(缩小过滤):当多个纹理像素缩在一个屏幕像素内时生效(远景)。
- mipmapFilter:在不同层级的 Mipmap 贴图之间进行插值。设置为 linear 即开启三线性过滤(Trilinear Filtering),能极大消除摩尔纹与走样。
2. 各向异性过滤(Anisotropic Filtering)
当以大斜角观察地表或墙面时,普通的各向同性过滤会导致远景严重模糊。通过配置 maxAnisotropy: 16,采样器会在沿视线倾斜方向进行椭圆多重采样,恢复清晰的细节:
export function createHighQualitySampler(device: GPUDevice): GPUSampler {
return device.createSampler({
addressModeU: 'repeat', // U 轴平铺
addressModeV: 'repeat', // V 轴平铺
addressModeW: 'clamp-to-edge',
magFilter: 'linear', // 双线性放大
minFilter: 'linear', // 双线性缩小
mipmapFilter: 'linear', // 开启三线性 Mipmap 混合
maxAnisotropy: 16, // 开启最高 16x 各向异性过滤
});
}
export function createShadowComparisonSampler(device: GPUDevice): GPUSampler {
return device.createSampler({
compare: 'less', // 开启硬件深度比较采样
magFilter: 'linear',
minFilter: 'linear',
});
}
WGSL 着色器中的纹理与采样器绑定
在 WGSL 着色器代码中,采样器与纹理作为独立的 Bind Group 条目注入:
// WGSL 片元着色器示例
@group(0) @binding(0) var mySampler: sampler;
@group(0) @binding(1) var myTexture: texture_2d<f32>;
struct VertexOutput {
@builtin(position) position: vec4<f32>,
@location(0) uv: vec2<f32>,
};
@fragment
fn fs_main(input: VertexOutput) -> @location(0) vec4<f32> {
// 使用采样器对纹理进行双线性/各向异性采样
let color: vec4<f32> = textureSample(myTexture, mySampler, input.uv);
return color;
}
在阴影计算中,如果使用了比较采样器(sampler_comparison),WGSL 提供了 textureSampleCompare 函数:
@group(0) @binding(2) var shadowSampler: sampler_comparison;
@group(0) @binding(3) var shadowMap: texture_depth_2d;
fn calculateShadow(shadowCoords: vec3<f32>) -> f32 {
// 硬件直接完成深度对比并返回 [0.0, 1.0] 的阴影遮挡因子
return textureSampleCompare(shadowMap, shadowSampler, shadowCoords.xy, shadowCoords.z);
}
从粗糙的全局状态控制转向精密的管线与采样器配置,WebGPU 赋予了前端开发者直面现代 GPU 硬件微架构的能力。



