WebGPU 的着色器语言是 WGSL,但与 GLSL 和 HLSL 不同,不支持 #ifdef
等宏。为了实现各种着色器变体,迄今为止,宏一直是着色器编程中非常重要的功能。那么应该如何处理没有宏的 WGSL?
WebGPU 和 WGSL 提供了一个名为“Pipeline Overridable Constants”的函数,用于从 JavaScript 端覆盖着色器常量。这种方式可以接近宏的实现了。
首先,在着色器中定义一个常量。稍后可以从 JavaScript 端覆盖该常量。 这次我们在片段着色器中定义它。
override is_red: bool;
override color_r: f32 = 1.0;
override color_g: f32 = 1.0;
override color_b: f32 = 1.0;
@fragment
fn main() -> @location(0) vec4<f32> {
if (is_red) {
return vec4<f32>(1.0, 0.0, 0.0, 1.0);
} else {
return vec4<f32>(color_r, color_g, color_b, 1.0);
}
}
通过在常量名称之前添加 override
,该常量就成为可以从 JavaScript 端覆盖的常量。 是否指定默认值并不重要,但如果不指定,则必须始终从 JavaScript 端覆盖它。 如果不覆盖,将使用着色器端定义的默认值。
在 JavaScript 方面,为 Pipeline 的 GPUProgrammableStage
的 constants
属性指定一个常量值。
const pipeline = g_device.createRenderPipeline({
layout: 'auto',
vertex: {
module: g_device.createShaderModule({
code: vertWGSL,
}),
entryPoint: 'main',
},
fragment: {
module: g_device.createShaderModule({
code: fragWGSL,
}),
entryPoint: 'main',
constants: {
'is_red': false,
'color_r': 0.5,
'color_g': 0.25,
'color_b': 1.0,
}
...
有关可以指定的常量的类型和功能的更多详细信息,请参阅WebGPU规范。
通过使用 Pipeline-Overridable-Constants,我们能够覆盖着色器端的常量值。查看示例。