Shader syntax cheat sheet
The same ideas in HLSL, GLSL, WGSL, Godot and Metal, side by side. Use it when you port a shader from one language to another.
| Idea | HLSLUnity, Unreal | GLSLShadertoy, three.js, OpenGL | WGSLWebGPU, Bevy | GodotGodot 4 shading language | MetaliOS, macOS |
|---|---|---|---|---|---|
| Vectors | float2 float3 float4 | vec2 vec3 vec4 | vec2f vec3f vec4f (or vec3<f32>) | vec2 vec3 vec4 | float2 float3 float4 |
| Declare a value | float d = length(p); | float d = length(p); | let d = length(p); (var if you change it later) | float d = length(p); | float d = length(p); |
| A function | float circle(float2 p, float r) { ... } | float circle(vec2 p, float r) { ... } | fn circle(p: vec2f, r: f32) -> f32 { ... } | float circle(vec2 p, float r) { ... } | float circle(float2 p, float r) { ... } |
| Matrices | float2x2, multiply with mul(M, v) | mat2 mat3, multiply with M * v (this site writes v * M for lesson rotations) | mat2x2f, multiply with M * v (this site writes v * M for lesson rotations) | mat2 mat3, multiply with M * v (this site writes v * M for lesson rotations) | float2x2, multiply with M * v (this site writes v * M for lesson rotations) |
| Blend | lerp(a, b, t) | mix(a, b, t) | mix(a, b, t) | mix(a, b, t) | mix(a, b, t) |
| Fractional part | frac(x) | fract(x) | fract(x) | fract(x) | fract(x) |
| Clamp to 0..1 | saturate(x) | clamp(x, 0.0, 1.0) | saturate(x) | clamp(x, 0.0, 1.0) | saturate(x) |
| Remainder | fmod(a, b) (keeps the sign of a) | mod(a, b) (always positive for positive b) | a % b (keeps the sign of a) | mod(a, b) (always positive for positive b) | fmod(a, b) (keeps the sign of a) |
| Choose | c ? a : b | c ? a : b | select(b, a, c) (false value first) | c ? a : b | c ? a : b |
| Angle of a vector | atan2(y, x) | atan(y, x) | atan2(y, x) | atan(y, x) | atan2(y, x) |
| Time in seconds | time, or Unity's _Time.y | time, or Shadertoy's iTime | time | TIME | time |
| Pixel position | uv (0..1, bottom-left) | uv, or fragCoord in mainImage | uv (0..1, bottom-left) | UV (0..1, top-left) | uv (0..1, bottom-left) |
| Width / height | aspect, or _ScreenParams.x / _ScreenParams.y | aspect, or iResolution.x / iResolution.y | aspect | aspect | aspect |
| Entry point | float4 frag(float2 uv) { return …; } | vec4 frag(vec2 uv) or void mainImage(out vec4 fragColor, in vec2 fragCoord) | fn frag(uv: vec2f) -> vec4f { return …; } | void fragment() { COLOR = …; } | float4 frag(float2 uv) { return …; } |
Functions that are the same everywhere
sin cos abs sign floor ceil frac step smoothstep clamp min max pow exp sqrt length distance dot cross normalize reflect
Gotchas by language
HLSL Unity, Unreal
- Every pixel runs on its own, with no memory of other pixels.
- Declare a function above the place you use it.
- Prefer 2.0 over 2 in maths. This site fixes most cases for you; real engines may not.
- Loops need a small fixed count: for (int i = 0; i < 5; i++).
GLSL Shadertoy, three.js, OpenGL
- Every pixel runs on its own, with no memory of other pixels.
- Declare a function above the place you use it.
- Prefer 2.0 over 2 in maths. This site fixes most cases for you; real engines may not.
- Loops need a small fixed count: for (int i = 0; i < 5; i++).
WGSL WebGPU, Bevy
- Every pixel runs on its own, with no memory of other pixels.
- Functions can be declared in any order.
- Parameters are read-only: copy one into a var to change it (var p = pIn;).
- You cannot assign to two components at once (p.xz = …). Write p.x and p.z separately.
- Floats and ints never mix silently: f32(i) turns a loop counter into a float.
Godot Godot 4 shading language
- Every pixel runs on its own, with no memory of other pixels.
- Declare a function above the place you use it.
- Prefer 2.0 over 2 in maths. This site fixes most cases for you; real engines may not.
- Loops need a small fixed count: for (int i = 0; i < 5; i++).
- Godot's UV starts at the top-left. The lessons' frag(uv) uses bottom-left, which is why the starter flips it. The wrapper doesn't count towards your score.
Metal iOS, macOS
- Every pixel runs on its own, with no memory of other pixels.
- Declare a function above the place you use it.
- Prefer 2.0 over 2 in maths. This site fixes most cases for you; real engines may not.
- Loops need a small fixed count: for (int i = 0; i < 5; i++).
- Metal is C++ based. The export puts your functions in a struct so they can read time and aspect.
Practise in the language you need
Every lesson and challenge on ShaderBattle shows in all of these languages, with hints, error messages and an export file for your engine. Pick your language, or read how the concepts work in Shader concepts explained.
shaderbattle.com/cheatsheet