Learn Unity shaders in HLSL
HLSL is the language of Unity's Built-in render pipeline and of DirectX. Every ShaderBattle lesson is written in HLSL first, so this is the most direct way to learn it: you write the fragment function in the browser, watch it run, and export it as a ready-to-use Unity shader.
Things to know about HLSL
- Vectors are
float2,float3andfloat4; blend withlerp;fracis the fractional part. - Matrices multiply with
mul(M, v), with the matrix first. fmod(a, b)keeps the sign ofa, so useabs()or add an offset when you work with negative numbers.- Unity gives you
_Time.yfor seconds and_ScreenParamsfor the screen size. The editor accepts them too.
Cheat sheet
| Idea | Write |
|---|---|
| Vectors | float2 float3 float4 |
| Declare a value | float d = length(p); |
| A function | float circle(float2 p, float r) { ... } |
| Matrices | float2x2, multiply with mul(M, v) |
| Blend | lerp(a, b, t) |
| Fractional part | frac(x) |
| Clamp to 0..1 | saturate(x) |
| Remainder | fmod(a, b) (keeps the sign of a) |
| Choose | c ? a : b |
| Angle of a vector | atan2(y, x) |
| Time in seconds | time, or Unity's _Time.y |
| Pixel position | uv (0..1, bottom-left) |
| Width / height | aspect, or _ScreenParams.x / _ScreenParams.y |
| Entry point | float4 frag(float2 uv) { return …; } |
Handy built-ins: sin cos abs sign floor ceil frac step smoothstep clamp min max pow exp sqrt length distance dot cross normalize reflect
Gotchas
- 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++).
Example: a glowing ring
The same shader as it is written for Unity (Built-in):
float4 frag(float2 uv)
{
float2 p = (uv - 0.5) * float2(aspect, 1.0);
float d = length(p);
float m = 1.0 - smoothstep(0.0, 0.02, abs(d - 0.3));
float3 bg = float3(0.08, 0.08, 0.12);
float3 fg = float3(0.4, 0.9, 1.0);
return float4(lerp(bg, fg, m), 1.0);
} Exporting to Unity
In Unity: Create → Shader → Unlit Shader, replace everything with this, then put a material using it on a Quad.
Shader "ShaderBattle/Glowing ring"
{
SubShader
{
Tags { "RenderType"="Opaque" }
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment fragMain
#include "UnityCG.cginc"
struct v2f
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0; // the mesh's UV: (0,0) bottom-left, (1,1) top-right
};
v2f vert (appdata_base v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.texcoord.xy;
return o;
}
// Globals the website gives you for free:
#define time _Time.y // seconds since start
static const float aspect = 1.0; // a Quad is square. (The website renders 4:3.)
// ---- your code from ShaderBattle -------------------------------
float4 frag(float2 uv)
{
float2 p = (uv - 0.5) * float2(aspect, 1.0);
float d = length(p);
float m = 1.0 - smoothstep(0.0, 0.02, abs(d - 0.3));
float3 bg = float3(0.08, 0.08, 0.12);
float3 fg = float3(0.4, 0.9, 1.0);
return float4(lerp(bg, fg, m), 1.0);
}
// ----------------------------------------------------------------
fixed4 fragMain (v2f i) : SV_Target
{
return frag(i.uv);
}
ENDCG
}
}
} Questions
Is HLSL the same in Unity and Unreal?
The language is the same. What differs is how you get your code into the engine: a ShaderLab file in Unity, a Custom node in Unreal. Switch between the two in the language picker to see each export.
Do I need Unity installed to learn?
No. Everything runs in your browser. Install Unity only when you want to use what you built.
Other languages
Unity (URP) · Unreal · Shadertoy / WebGL · OpenGL (LWJGL, raylib) · three.js · GameMaker · LÖVE (Lua) · Godot · Apple (iOS, macOS) · WebGPU / Bevy