Vectors and Matrices
How vectors and matrices work in shaders — the math that powers every transformation, lighting calculation, and effect.
Turn the guide into code
Take the key idea from this page into the playground and validate it in a real shader instead of leaving it as theory.
Open PlaygroundVectors and matrices are the core data types in shader programming. Every position, direction, color, and transformation is expressed through them.
Vectors
A vector is a fixed-size bundle of numbers. BWSL provides float2, float3, and float4:
float2 uv = float2(0.5, 0.75);
float3 position = float3(1.0, 2.0, 3.0);
float4 color = float4(1.0, 0.0, 0.0, 1.0); // red, fully opaque
What Vectors Represent
The same float3 can mean completely different things depending on context:
| Usage | Example | Components mean |
|---|---|---|
| Position | float3(10, 5, 3) | x, y, z coordinates |
| Direction | float3(0, 1, 0) | pointing up |
| Color | float3(1, 0.5, 0) | red, green, blue |
| Scale | float3(2, 2, 2) | uniform 2x scale |
The GPU doesn't care — it's all just numbers. You give them meaning by how you use them.
Component Access
Access individual components with .x, .y, .z, .w:
float3 v = float3(1.0, 2.0, 3.0);
float a = v.x; // 1.0
float b = v.y; // 2.0
float c = v.z; // 3.0
For colors, you can use .r, .g, .b, .a — they're aliases for the same components:
float4 color = float4(1.0, 0.5, 0.0, 1.0);
float red = color.r; // same as color.x → 1.0
float alpha = color.a; // same as color.w → 1.0
Swizzling
You can read multiple components in any order, even with repeats:
float3 v = float3(1.0, 2.0, 3.0);
float2 a = v.xy; // float2(1.0, 2.0)
float2 b = v.yx; // float2(2.0, 1.0) — swapped
float3 c = v.zzy; // float3(3.0, 3.0, 2.0) — repeated
float4 d = v.xyzz; // float4(1.0, 2.0, 3.0, 3.0) — expanded
This is extremely useful for packing, unpacking, and rearranging data without temporary variables.
Arithmetic
Vectors support component-wise arithmetic. Operations apply to each component independently:
float3 a = float3(1.0, 2.0, 3.0);
float3 b = float3(4.0, 5.0, 6.0);
float3 sum = a + b; // float3(5.0, 7.0, 9.0)
float3 product = a * b; // float3(4.0, 10.0, 18.0)
float3 scaled = a * 2.0; // float3(2.0, 4.0, 6.0)
a * b is component-wise multiplication, NOT the dot product or cross product. For those, use dot(a, b) and cross(a, b).
Essential Vector Operations
Length and Distance
length(v) gives the magnitude of a vector. distance(a, b) gives the distance between two points.
float3 v = float3(3.0, 4.0, 0.0);
float len = length(v); // 5.0
float dist = distance(a, b); // same as length(a - b)
Normalize
normalize(v) returns a vector pointing the same direction but with length 1. Essential for directions — lighting math assumes unit-length normals and light directions.
float3 dir = float3(3.0, 4.0, 0.0);
float3 unit = normalize(dir); // float3(0.6, 0.8, 0.0), length = 1.0
Dot Product
dot(a, b) measures how aligned two vectors are. Returns a single float:
float3 normal = normalize(input.normal);
float3 lightDir = normalize(float3(1.0, 1.0, 0.0));
float alignment = dot(normal, lightDir);
// 1.0 = facing light, 0.0 = perpendicular, -1.0 = facing away
Cross Product
cross(a, b) returns a vector perpendicular to both inputs. Only works on float3. Used for computing normals from two edges of a triangle:
float3 edge1 = v1 - v0;
float3 edge2 = v2 - v0;
float3 faceNormal = normalize(cross(edge1, edge2));
Reflect
reflect(incident, normal) reflects a vector off a surface. Used for specular lighting and mirror effects:
float3 reflected = reflect(-lightDir, normal);
float specular = pow(max(dot(reflected, viewDir), 0.0), 32.0);
Matrices
A matrix transforms vectors — rotating, scaling, translating, or projecting them. BWSL provides mat3 (3x3) and mat4 (4x4).
Transform Chain
3D rendering typically chains three matrices:
vertex {
float4 worldPos = resources.modelMatrix * float4(attributes.position, 1.0);
float4 viewPos = resources.viewMatrix * worldPos;
output.position = resources.projectionMatrix * viewPos;
}
| Matrix | What it does |
|---|---|
| Model | Object space → World space (position, rotation, scale of the object) |
| View | World space → Camera space (where things are relative to the camera) |
| Projection | Camera space → Clip space (perspective or orthographic projection) |
Matrix-Vector Multiplication
mat4 * float4 transforms the vector. Order matters — matrix on the left, vector on the right:
float4 result = myMatrix * float4(position, 1.0);
Use 1.0 as the W component for positions (affected by translation) and 0.0 for directions (not affected by translation): float4(direction, 0.0).
Normal Transformation
Normals need special treatment — they should be transformed by the inverse transpose of the model matrix to stay perpendicular to the surface after non-uniform scaling:
float3 worldNormal = normalize((resources.normalMatrix * float4(attributes.normal, 0.0)).xyz);
See Also
- Types Overview — Full type reference including vectors and matrices
- Vector Intrinsics — dot, cross, normalize, reflect, and more
- Matrix Intrinsics — determinant, inverse, transpose