WGSL 顶点和片元着色器
本页介绍 WGSL 顶点和片元着色器专用的结构:属性、varying 和片元输出。
各着色阶段共享的 uniform、纹理和存储缓冲区,采用简化语法声明并自动反射到绑定组,参见 WGSL 反射。
顶点属性
属性定义逐顶点输入,只能在顶点着色器中使用,必须按如下语法声明:
attribute aUv0: vec2f;
内部自动创建 VertexInput 结构并填入全部属性。可通过传入主函数的结构访问,也可在全局作用域访问。
attribute aUv0: vec2f;
@vertex fn vertexMain(input: VertexInput) -> VertexOutput {
// access it using input passed to the main function
var myUv1 = input.aUv0;
// but also as a global variable (particularly useful inside other functions)
var myUv2 = aUv0;
}
以下内置属性自动提供于 VertexInput 结构及全局作用域:
vertexIndex: @builtin(vertex_index)
instanceIndex: @builtin(instance_index)
属性名称必须与创建 ShaderMaterial 时 attributes 中指定的名称匹配。
Varying
Varying 从顶点着色器向片元着色器传递值。两种着色器中均使用以下简化语法声明:
varying texCoord: vec2f;
内部会解析它们,分别保存到顶点着色器的 VertexOutput 和片元着色器的 FragmentInput 结构。
顶点着色器
VertexOutput 自动提供以下内置变量:
position: @builtin(position)
示例:
varying texCoord: vec2f;
@vertex fn vertexMain(input: VertexInput) -> VertexOutput {
var output: VertexOutput;
output.position = uniform.matrix_viewProjection * pos;
output.texCoord = vec2f(0.0, 1.0);
return output;
}
片元着色器
FragmentInput 自动提供以下内置变量:
position: @builtin(position) // interpolated fragment position
frontFacing: @builtin(front_facing) // front-facing
sampleIndex: @builtin(sample_index) // sample index for MSAA
sampleMask: @builtin(sample_mask) // coverage mask for MSAA
primitiveIndex: @builtin(primitive_index) // primitive index (when supported)
这些内置值也可在全局作用域通过以下名称访问:
pcPosition
pcFrontFacing
pcSampleIndex
pcSampleMask
pcPrimitiveIndex // when supported
primitiveIndex / pcPrimitiveIndex 仅在 device.supportsPrimitiveIndex 为 true 时可用。此功能仅受 WebGPU 支持,WebGL2 不可用。关于 enable primitive_index; 和 CAPS_PRIMITIVE_INDEX,参见 WGSL 语言扩展。
示例:
varying texCoord: vec2f;
@fragment
fn fragmentMain(input: FragmentInput) -> FragmentOutput {
var output: FragmentOutput;
output.color = vec4f(1.0);
return output;
}
片元着色器输出
片元着色器负责生成一个或多个颜色输出,写入帧缓冲区的渲染目标(颜色附件)。
引擎自动提供 FragmentOutput,包含预定义的 vec4f 字段 color、color1、color2 等,覆盖全部可能的颜色附件,上限由 GraphicsDevice.maxColorAttachments 决定。
FragmentOutput 自动提供以下内置变量:
fragDepth: @builtin(frag_depth)
sampleMask: @builtin(sample_mask)
示例:
@fragment fn fragmentMain(input: FragmentInput) -> FragmentOutput {
var output: FragmentOutput;
output.color = vec4f(1.0);
output.color1 = vec4f(0.5);
output.fragDepth = 0.2;
return output;
}
渲染到多重采样目标时,写入 output.sampleMask 可控制片元写入哪些样本。GPU 将写入遮罩与覆盖遮罩按位与,因此着色器可以丢弃独立样本。这是自定义 alpha-to-coverage 抖动图案等技术的基础:
@fragment fn fragmentMain(input: FragmentInput) -> FragmentOutput {
var output: FragmentOutput;
output.color = vec4f(1.0);
output.sampleMask = pcSampleMask & 0x5u; // keep samples 0 and 2 only
return output;
}
双源输出
材质混合状态使用第二源因子时,主颜色写入 output.color,第二混合值写入 output.colorSecondary。引擎在位置 0 以适当的 @blend_src 属性生成两个输出,并启用所需 WGSL 扩展。
双源混合要求恰好一个颜色附件。能力检测和 BlendState 配置参见双源混合。
目前尚不支持向整数纹理渲染,即使用非 vec4f 的输出格式,将在未来加入。