Visual LabINTERACTIVE LEARNING
SHADER LANGUAGE FIELD GUIDE适合入门 · 迁移 · 速查

GLSL vs WGSL
语法详细对比

从着色器语言迁移的视角,一屏看懂 WebGL / OpenGL 常见 GLSL 写法与 WebGPU 的 WGSL 写法差异。

属性标注显式类型资源绑定入口函数
01

核心定位

先理解语言背后的 API 模型,再对照关键字。

GLSL传统图形 API 着色器语言

常见于 OpenGL / WebGL,状态与资源接口较隐式。

WGSLWebGPU 官方着色器语言

强调类型安全、显式声明和创建管线时的可验证性。

迁移心法

不要只替换关键字;要同时重画属性写法、资源绑定、类型与入口函数。

02

基本类型与变量声明

WGSL 把变量名放在前面,类型通过冒号显式写出。

GLSL:类型写在变量名前面 WGSL:变量名后写类型,形式为 name: type 向量 / 矩阵vec3vec3<f32>mat4mat4x4<f32>
GLSL
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);
}
WGSL
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>();
}
03

常量、可变变量、地址空间

WGSL 用 var / let / const 区分生命周期,并把 GPU 地址空间写入声明。

GLSL
const float PI = 3.14159;
uniform mat4 uMVP;

void example() {
  float x = 0.0;
}
WGSL
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 缓冲区
04

输入输出:attribute / varying / builtin

GLSL 依赖阶段关键字和内建变量;WGSL 用结构体字段属性描述接口。

A旧式 WebGL 心智模型attribute / in → @location(...)varying / out → @location(...)gl_Position → @builtin(position)
GLSL 阶段接口
attribute vec3 position;
attribute vec2 uv;
varying vec2 vUV;

void main() {
  vUV = uv;
  gl_Position = vec4(position, 1.0);
}
WGSL 阶段接口
struct VSIn {
  @location(0) position: vec3<f32>,
  @location(1) uv: vec2<f32>,
};

struct VSOut {
  @builtin(position) position: vec4<f32>,
  @location(0) uv: vec2<f32>,
};
05

顶点着色器与片元着色器入口

WGSL 用 @vertex / @fragment 标记普通函数,并显式返回输出位置。

顶点着色器 · GLSL
attribute vec3 position;
attribute vec3 color;
varying vec3 vColor;

void main() {
  gl_Position = vec4(position, 1.0);
  vColor = color;
}
片元着色器 · GLSL
precision mediump float;
varying vec3 vColor;

void main() {
  gl_FragColor = vec4(vColor, 1.0);
}
渲染着色器 · WGSL
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);
}
WGSL 不再使用 gl_FragColor,而是返回带 @location(0) 的颜色值。
06

Uniform / Buffer / 资源绑定

WebGPU 把应用侧的 BindGroup 映射到 WGSL 的 @group / @binding。

GLSL
uniform mat4 uMVP;
uniform sampler2D uTex;
WGSL
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组内槽位
07

函数、结构体、语法风格

WGSL 的字段写作 field: type,函数用 fn 并将返回类型写在箭头后。

GLSL
struct Light {
  vec3 dir;
  vec3 color;
};

float saturate(float x) {
  return clamp(x, 0.0, 1.0);
}
WGSL
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 结构体字段使用逗号结尾
08

计算着色器(Compute Shader)

两者都能描述并行计算;WGSL 把入口、工作组大小与内建值统一为属性标注。

GLSL Compute
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;
}
WGSL Compute
@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)
09

常见迁移坑点

迁移不是全文替换:先定接口,再定资源,最后补齐显式类型。

vec3 → vec3<f32>mat4 → mat4x4<f32>
不再使用 gl_FragColor颜色从 @location(0) 返回
纹理与 sampler 分开声明分别占用 binding 槽位
入口函数必须标注@vertex / @fragment / @compute
资源绑定必须重写@group / @binding
WGSL 类型规则更严格很多隐式转换会直接报错
ONE-LINE RECAPWGSL = 属性标注 + 显式资源绑定 + 严格类型系统
继续看最小示例