Shader Basic Concepts
Makepad Shader is a custom MPSL shader language. MPSL can be compiled into shader languages like GLSL.
Recommended prerequisite learning: GLSL Shader Introduction Tutorial https://thebookofshaders.com/
What is a Shader
Let's begin understanding shaders with a simple analogy. Imagine you're a painter facing an enormous canvas divided into millions of tiny squares (pixels).
You have two tasks:
- Determine the position and size of each shape (Vertex Shader)
- Decide what color to fill in each square (Fragment/Pixel Shader)
1// A basic Makepad shader
2MyFirstShader = {{MyFirstShader}} {
3 // 1. Vertex shader - handles position
4 fn vertex(self) -> vec4 {
5 // Place the shape in the correct position
6 let position = self.geom_pos * self.rect_size + self.rect_pos;
7 return self.camera_projection * vec4(position, 0.0, 1.0);
8 }
9
10 // 2. Fragment shader - handles color
11 fn pixel(self) -> vec4 {
12 // Color each pixel
13 return vec4(1.0, 0.0, 0.0, 1.0); // Red
14 }
15}
Let's visualize this process:
1Vertex Shader Stage: Pixel Shader Stage:
2
3 P1●─────●P2 ░░░░░░░░
4 │ │ ░██████░
5 │ │ => ░██████░
6 │ │ ░██████░
7 P3●─────●P4 ░░░░░░░░
8
9(Determine shape position) (Fill each pixel)
GPU vs CPU Rendering Differences
Why use GPU rendering? Let's understand through an example:
Imagine rendering a 1000×1000 pixel area:
1CPU Rendering:
2- Process each pixel sequentially
3- 1 million pixels processed one at a time
4- Similar to filling with a single brush
5
6GPU Rendering:
7- Process many pixels in parallel
8- 1 million pixels processed simultaneously
9- Similar to covering with a spray gun
Visual representation::
1CPU Rendering Progress: GPU Rendering Progress:
2█░░░░░░░░░ 10% ▒▒▒▒▒▒▒▒▒▒ 100%
3██░░░░░░░░ 20% (Processed simultaneously)
4███░░░░░░░ 30%
5...
Coordinate Systems in Detail
In Makepad, we need to work with three main coordinate systems:
Normalized Device Coordinates (NDC)
Range [-1,1], provides device-independent standardized space, ensuring consistent rendering results across different resolutions.
- Use cases: When you need device-independent rendering or handling 3D transformations.
- Examples: 3D rendering, view clipping, perspective projection, cross-device consistent rendering.
Pixel Coordinates
Actual screen pixels, used for precise positioning on screen, directly corresponding to physical display devices.
- Use cases: When you need precise control over rendering target positions on screen.
- Examples: Precise UI element positioning, pixel border drawing, text rendering alignment.
UV Coordinates
:
Range [0,1] texture coordinates, used for texture mapping and parametric surfaces, providing resolution-independent relative positioning.
- Use cases: When you need to handle texture mapping or create parametric visual effects.
- Examples: Texture mapping, gradient effects, UV animation, procedural texture generation, parametric shapes.
Code and diagrams to understand coordinate conversions
1fn vertex(self) -> vec4 {
2 // 1. Mapping from geometric coordinates to pixel coordinates
3 let pixel_pos = self.geom_pos * self.rect_size + self.rect_pos;
4
5 // 2. Mapping from pixel coordinates to UV coordinates
6 self.uv = (pixel_pos - self.rect_pos) / self.rect_size;
7
8 // 3. Mapping from pixel coordinates to NDC
9 let ndc = self.camera_projection * vec4(pixel_pos, 0.0, 1.0);
10
11 return ndc;
12}
Coordinate system visualization:
1Normalized Device Pixel UV
2Coordinates (NDC) Coordinates Coordinates
3 (-1,1) (0,0) (0,0)
4 ┃ ┃ ┃
5 ┃ ┃ ┃
6 ━━━━━━●━━━━━━ ━━━━━●━━━━━ ━━━━━━━●━━━━━━━
7 ┃ ┃ ┃
8 ┃ ┃ ┃
9 (1,-1) (width, (1,1)
10 height)
11
12Coordinate mapping flowchart:
13
14Pixel Coords (100, 100) UV Coords (0.5, 0.5) NDC (0.0, 0.0)
15 ┌──────────┐ ┌──────────┐ ┌──────────┐
16 │(0,0) │ ÷size │(0,0) │ *2-1 │(-1,1) │
17 │ │ ────────────► │ │ ────────────► │ │
18 │ ● │ │ ● │ │ ● │
19 │ │ │ │ │ │
20 │ (w,h)│ │ (1,1)│ │ (1,-1)│
21 └──────────┘ └──────────┘ └──────────┘
22
23Requirements Decision:
24┌────────────────────┐
25│Need pixel precision?│
26└─────────┬──────────┘
27 │
28 ┌─────┴─────┐
29 │ Yes │ No
30 ▼ ▼
31Pixel ┌──────────────┐
32Coords │Need texture │
33 │or gradients? │
34 └──────┬───────┘
35 │
36 ┌────┴────┐
37 │ Yes │ No
38 ▼ ▼
39 UV Coords NDC Coords
Colors and Pixels
In Makepad, colors are represented using vec4
, containing four RGBA channels:
1fn pixel(self) -> vec4 {
2 //---------- Red Green Blue Alpha
3 return vec4(1.0, 0.0, 0.0, 1.0);
4}
Color blending illustration:
1Base Colors: Alpha Blending:
2Red (1,0,0) ██ Opaque (alpha = 1.0)
3Green (0,1,0) + ▒▒ Semi-transparent (alpha = 0.5)
4Blue (0,0,1) ░░ Transparent (alpha = 0.0)
The concept of Premultiplied Alpha:
1// Regular RGBA
2vec4(1.0, 0.0, 0.0, 0.5) // Semi-transparent red
3
4// Premultiplied Alpha (recommended)
5vec4(0.5, 0.0, 0.0, 0.5) // RGB channels already multiplied by alpha