Clip space is a linearly dependent vector space between eye space and *normalized device coordinates* (NDC). See Spaces.

It is where the viewing volume is finally defined, by:

Geometry is typically clipped to be inside this volume. This is somewhat straight forward for lines and more complex for triangles, which may require multiple triangles to render after clipping.

By convention, vectors in clip space are normalized with a perspective divide to take them to NDC.

The purpose of this page is to cover some of the maths and geometric oddities when working in clip space.

A good presentation of clipping in clip space is at chaosinmotion.com.

# Interpolation

When working in clip space, vectors can mostly be dealt with the same as 3D but just with another component. For exmaple, the point $p$ at $t$ along a line between two vertices $\mathbf{a}$ and $\mathbf{b}$ in clip space is simply:

Computing perspective correct depth $d$ with a perspective divide is then:

If instead $\mathbf{a}$ and $\mathbf{b}$ were normalized before interpolation, the result would be incorrect. As a general rule, perform the perspective divide at the last moment, right when a 2D screen position or non-linear depth is needed.

# Line–Plane Intersections

Starting with just the left plane, $-w \geq x$. This inequality defines a deceptively simple plane equation in cartesian coordinates:

Think of this as a plane in 4D space intersecting the origin and with the normal $(1, 0, 0, 1)$. To find the intersection with a line $\mathbf{o} + \mathbf{d} t$ , plug the line equation into $x - w = 0$ and solve for t:

For the positive $x$ clipping plane:

This can almost be thought of as intersecting with an axis aligned box, plus a linearly dependent $w$. Unfortunately that tantalising simplicity is not so. One surprise is that even in the case $\mathbf{o}_x = 0$ and $\mathbf{d}_x > 0$, $t$ may be negative because $w$ in $x - w = 0$ “out-runs” in the $+t$ direction. For a regular axis aligned intersection this wouldn’t happen — if a line moves in positive $x$; it must hit axis-aligned planes in that direction.

It’s easy to see this geometrically when thinking about a perspective frustum. The gradient of the line’s direction is simply not low enough to intersect the right hand clipping plane in the positive direction. It still intersects the right hand plane, just at negative $t$. In fact this intersection occurrs outside the viewing volume, which is another surprise. Both left and right clipping planes place lower $t$ bounds on this line and the $x$ axis has no upper bound on $t$. This complicates a general intersection algorithm.

# Inside and Outside

An easy algorithm to clip a line to a box is to first compute the intersection times $t$ of the axis aligned planes. Then sort them into $t_0$ and $t_1$ for each axis — there’s only two, so it’s not much of a sort. Finally $t_0 = \max(t_{x0}, t_{y0}, t_{z0})$ and $t_1 = \min(t_{x1}, t_{y1}, t_{z1})$. This works for a bounding box because the first of two intersections on each axis is always the lower bound of the box and the second is always the upper bound. As described above, the same does not work for clipping against perspective projections.

As seen in the figure above, intersections on opposing planes may be both lower (in this case, shown in green) or both upper bounds on $t$. What is needed is a test for the side of the plane the line hits.

Continuing the example above for a line $\mathbf{o} + \mathbf{d} t$. In the general case, a line hits the front of a plane if its direction vector $\mathbf{d}$ is opposite the plane’s normal vector $\mathbf{n}$. The normal vectors for clipping planes are simply:

If $\mathbf{d} \cdot (1, 0, 0, 1) < 0$, i.e. $\mathbf{d}_x + \mathbf{d}_w < 0$, then the line will hit the left clipping plane coming from the right hand side, meaning the time of intersection $t$ (see the section above) becomes an upper limit to clip the line’s $t_1$ to. If the inequality is false then the line hits the left clipping plane coming from the left and $t$ should instead be a lower limit on the line’s $t_0$.

For an example of this in use, see this frustum clipping shadertoy.