SHADER LANGUAGE FIELD GUIDE适合入门 · 迁移 · 速查
GLSL vs WGSL
语法详细对比
从着色器语言迁移的视角,一屏看懂 WebGL / OpenGL 常见 GLSL 写法与 WebGPU 的 WGSL 写法差异。
核心定位
先理解语言背后的 API 模型,再对照关键字。
GLSL传统图形 API 着色器语言
常见于 OpenGL / WebGL,状态与资源接口较隐式。
WGSLWebGPU 官方着色器语言
强调类型安全、显式声明和创建管线时的可验证性。
迁移心法
不要只替换关键字;要同时重画属性写法、资源绑定、类型与入口函数。
基本类型与变量声明
WGSL 把变量名放在前面,类型通过冒号显式写出。
GLSL:类型写在变量名前面
WGSL:变量名后写类型,形式为
name: type
向量 / 矩阵:vec3 → vec3<f32>,mat4 → mat4x4<f32>
void example() {
float a = 1.0;
int b = 2;
vec2 uv = vec2(0.5, 1.0);
vec3 color = vec3(1.0, 0.0, 0.0);
mat4 m = mat4(1.0);
}
fn example() {
var a: f32 = 1.0;
var b: i32 = 2;
var uv: vec2<f32> = vec2<f32>(0.5, 1.0);
var color: vec3<f32> = vec3<f32>(1.0, 0.0, 0.0);
var m: mat4x4<f32> = mat4x4<f32>();
}
常量、可变变量、地址空间
WGSL 用 var / let / const 区分生命周期,并把 GPU 地址空间写入声明。
const float PI = 3.14159;
uniform mat4 uMVP;
void example() {
float x = 0.0;
}
const PI: f32 = 3.14159;
var<private> temp: f32;
var<workgroup> cache: array<f32, 64>;
fn example() {
var x: f32 = 0.0;
}
var<private>单个 shader invocation 私有
var<workgroup>同一工作组共享
var<uniform>只读、由应用提供
var<storage>大容量 GPU 缓冲区
输入输出:attribute / varying / builtin
GLSL 依赖阶段关键字和内建变量;WGSL 用结构体字段属性描述接口。
attribute vec3 position;
attribute vec2 uv;
varying vec2 vUV;
void main() {
vUV = uv;
gl_Position = vec4(position, 1.0);
}
struct VSIn {
@location(0) position: vec3<f32>,
@location(1) uv: vec2<f32>,
};
struct VSOut {
@builtin(position) position: vec4<f32>,
@location(0) uv: vec2<f32>,
};
顶点着色器与片元着色器入口
WGSL 用 @vertex / @fragment 标记普通函数,并显式返回输出位置。
attribute vec3 position;
attribute vec3 color;
varying vec3 vColor;
void main() {
gl_Position = vec4(position, 1.0);
vColor = color;
}
precision mediump float;
varying vec3 vColor;
void main() {
gl_FragColor = vec4(vColor, 1.0);
}
struct VSIn {
@location(0) position: vec3<f32>,
@location(1) color: vec3<f32>,
};
struct VSOut {
@builtin(position) position: vec4<f32>,
@location(0) color: vec3<f32>,
};
@vertex
fn vsMain(input: VSIn) -> VSOut {
var out: VSOut;
out.position = vec4<f32>(input.position, 1.0);
out.color = input.color;
return out;
}
@fragment
fn fsMain(input: VSOut) -> @location(0) vec4<f32> {
return vec4<f32>(input.color, 1.0);
}
Uniform / Buffer / 资源绑定
WebGPU 把应用侧的 BindGroup 映射到 WGSL 的 @group / @binding。
uniform mat4 uMVP;
uniform sampler2D uTex;
struct Uniforms {
mvp: mat4x4<f32>,
};
@group(0) @binding(0)
var<uniform> uniforms: Uniforms;
@group(0) @binding(1)
var texture: texture_2d<f32>;
@group(0) @binding(2)
var textureSampler: sampler;
APP / JS创建资源
BindGroup组织资源
@group资源组
@binding组内槽位
函数、结构体、语法风格
WGSL 的字段写作 field: type,函数用 fn 并将返回类型写在箭头后。
struct Light {
vec3 dir;
vec3 color;
};
float saturate(float x) {
return clamp(x, 0.0, 1.0);
}
struct Light {
dir: vec3<f32>,
color: vec3<f32>,
};
fn saturate(x: f32) -> f32 {
return clamp(x, 0.0, 1.0);
}
GLSL 返回类型写在函数名前WGSL 使用
fn name(...) -> typeWGSL 结构体字段使用逗号结尾计算着色器(Compute Shader)
两者都能描述并行计算;WGSL 把入口、工作组大小与内建值统一为属性标注。
layout(local_size_x = 64) in;
layout(std430, binding = 0) buffer Data {
float data[];
};
void main() {
uint i = gl_GlobalInvocationID.x;
data[i] = data[i] * 2.0;
}
@group(0) @binding(0)
var<storage, read_write> data: array<f32>;
@compute @workgroup_size(64)
fn csMain(@builtin(global_invocation_id) id: vec3<u32>) {
let i = id.x;
data[i] = data[i] * 2.0;
}
layout(local_size_x = 64)→@workgroup_size(64)
gl_GlobalInvocationID→@builtin(global_invocation_id)
常见迁移坑点
迁移不是全文替换:先定接口,再定资源,最后补齐显式类型。
vec3 → vec3<f32>mat4 → mat4x4<f32>
不再使用 gl_FragColor颜色从 @location(0) 返回
纹理与 sampler 分开声明分别占用 binding 槽位
入口函数必须标注@vertex / @fragment / @compute
资源绑定必须重写@group / @binding
WGSL 类型规则更严格很多隐式转换会直接报错
ONE-LINE RECAPWGSL = 属性标注 + 显式资源绑定 + 严格类型系统
继续看最小示例