Dot Product

The dot product takes two vectors and returns a single number measuring how aligned they are — the projection of one onto the other. It is the cheapest non-trivial operation on a GPU, and it is how surfaces get lit.

Core Idea

The dot product takes two vectors and returns a single number — how much one vector projects onto the other. Drag the arrowheads; the gold segment is that projection, and crossing 90° flips its sign:

dot(a, b) = a.x·b.x + a.y·b.y + a.z·b.z  =  |a| · |b| · cos(θ)

For normalized vectors the result is exactly cos θ:

Result Meaning
1.0 same direction
0.0 perpendicular
-1.0 opposite directions
> 0 / < 0 same / opposite half-space

Order doesn’t matter (dot(a,b) = dot(b,a)), and the vectors don’t need to touch — only their directions are compared, as if both tails sat at the origin.

Lighting Is a Dot Product

The surface at the top of this page is lit by nothing else: max(dot(N, L), 0.0) per pixel — surface normal against light direction, negative values clamped to darkness. No light objects, no lighting system; one instruction. This Lambertian trick gives realistic diffuse shading at almost zero GPU cost.

It runs in the fragment shader — once per pixel. A 1920×1080 viewport at 60 fps is over 124 million dot products per second for a single lighting pass; the GPU shrugs, because dot() is a single hardware instruction executed by thousands of cores in parallel. The rasterizer interpolates normals across each triangle, so the value varies smoothly per pixel — soft gradients instead of flat facets.

What It’s For

Use case Expression
Facing check — is A looking toward B? dot(aForward, toB) > 0
Field-of-view / cone trigger dot(forward, toTarget) > 0.95
Impact strength along a surface abs(dot(velocity, surfaceNormal))
Diffuse lighting max(dot(N, L), 0.0)
Fresnel rim glow 1.0 - max(dot(N, viewDir), 0.0)
Terrain: floor vs. wall dot(N, (0,1,0)) > 0.9
Project a point onto an axis dot(point, axisDir)

The Fastest Angle Is One You Never Calculate

acos and atan2 cost many GPU cycles; dot() costs one. Almost every “what’s the angle?” question is really a threshold question — so compare dot(a, b) > 0.95 instead of computing degrees. See trigonometry for the sin/cos machinery underneath.

One Rule: Same Space

Both vectors must live in the same coordinate space. A light direction in world space against a normal in object space produces a number that is valid math and geometric nonsense — the most common source of “why does my lighting look wrong?”. In shaders, transform normals (normal matrix / model matrix) before the dot. See coordinate spaces.

Connections

dot(â, b̂) = cos θ ties it to trigonometry — an angle detector that never computes an angle. A matrix × vector multiply is a stack of dot products — it is the operation inside every transform. The cross product is the companion: perpendicular vector out, where dot gives an aligned scalar out. And because the result is a clean −1…1 number, it slots directly into interpolation — geometry turned into a blend parameter, a slider computed from the scene itself.